"""Parser."""

import logging
import os.path
import pickle

import pandas as pd
import pandas_datareader.data as web
from pandas_datareader._utils import RemoteDataError
from pandas_datareader.data import (
    get_data_google,
    get_data_quandl,
    get_data_yahoo,
    get_data_alphavantage,
)
from pandas_datareader.nasdaq_trader import get_nasdaq_symbols
from pandas_datareader.exceptions import ImmediateDeprecationError

from .base import Quotes
from .utils import get_data_path, timeit

__all__ = (
    'YahooQuotesLoader',
    'GoogleQuotesLoader',
    'QuandleQuotesLoader',
    'get_symbols',
    'get_quotes',
)


logger = logging.getLogger(__name__)


class QuotesLoader:

    source = None
    timeframe = '1D'
    sort_index = False
    default_tf = None
    name_format = '%(symbol)s_%(tf)s_%(date_from)s_%(date_to)s.%(ext)s'

    @classmethod
    def _get(cls, symbol, date_from, date_to):
        quotes = web.DataReader(
            symbol, cls.source, start=date_from, end=date_to
        )
        if cls.sort_index:
            quotes.sort_index(inplace=True)
        return quotes

    @classmethod
    def _get_file_path(cls, symbol, tf, date_from, date_to):
        fname = cls.name_format % {
            'symbol': symbol,
            'tf': tf,
            'date_from': date_from.isoformat(),
            'date_to': date_to.isoformat(),
            'ext': 'qdom',
        }
        return os.path.join(get_data_path('stock_data'), fname)

    @classmethod
    def _save_to_disk(cls, fpath, data):
        logger.debug('Saving quotes to a file: %s', fpath)
        with open(fpath, 'wb') as f:
            pickle.dump(data, f, pickle.HIGHEST_PROTOCOL)

    @classmethod
    def _load_from_disk(cls, fpath):
        logger.debug('Loading quotes from a file: %s', fpath)
        with open(fpath, 'rb') as f:
            return pickle.load(f)

    @classmethod
    @timeit
    def get_quotes(cls, symbol, date_from, date_to):
        quotes = None
        fpath = cls._get_file_path(symbol, cls.timeframe, date_from, date_to)
        if os.path.exists(fpath):
            quotes = Quotes.new(cls._load_from_disk(fpath))
        else:
            quotes_raw = cls._get(symbol, date_from, date_to)
            quotes = Quotes.new(
                quotes_raw, source=cls.source, default_tf=cls.default_tf
            )
            cls._save_to_disk(fpath, quotes)
        return quotes


class YahooQuotesLoader(QuotesLoader):

    source = 'yahoo'

    @classmethod
    def _get(cls, symbol, date_from, date_to):
        return get_data_yahoo(symbol, date_from, date_to)


class GoogleQuotesLoader(QuotesLoader):

    source = 'google'

    @classmethod
    def _get(cls, symbol, date_from, date_to):
        # FIXME: temporary fix
        from pandas_datareader.google.daily import GoogleDailyReader

        GoogleDailyReader.url = 'http://finance.google.com/finance/historical'
        return get_data_google(symbol, date_from, date_to)


class QuandleQuotesLoader(QuotesLoader):

    source = 'quandle'

    @classmethod
    def _get(cls, symbol, date_from, date_to):
        quotes = get_data_quandl(symbol, date_from, date_to)
        quotes.sort_index(inplace=True)
        return quotes


class AlphaVantageQuotesLoader(QuotesLoader):

    source = 'alphavantage'
    api_key = 'demo'

    @classmethod
    def _get(cls, symbol, date_from, date_to):
        quotes = get_data_alphavantage(
            symbol, date_from, date_to, api_key=cls.api_key
        )
        return quotes


class StooqQuotesLoader(QuotesLoader):

    source = 'stooq'
    sort_index = True
    default_tf = 1440


class IEXQuotesLoader(QuotesLoader):

    source = 'iex'

    @classmethod
    def _get(cls, symbol, date_from, date_to):
        quotes = web.DataReader(
            symbol, cls.source, start=date_from, end=date_to
        )
        quotes['Date'] = pd.to_datetime(quotes.index)
        return quotes


class RobinhoodQuotesLoader(QuotesLoader):

    source = 'robinhood'


def get_symbols():
    fpath = os.path.join(get_data_path('stock_data'), 'symbols.qdom')
    if os.path.exists(fpath):
        with open(fpath, 'rb') as f:
            symbols = pickle.load(f)
    else:
        symbols = get_nasdaq_symbols()
        symbols.reset_index(inplace=True)
        with open(fpath, 'wb') as f:
            pickle.dump(symbols, f, pickle.HIGHEST_PROTOCOL)
    return symbols


def get_quotes(*args, **kwargs):
    quotes = []
    # don't work:
    # GoogleQuotesLoader, QuandleQuotesLoader,
    # AlphaVantageQuotesLoader, RobinhoodQuotesLoader
    loaders = [YahooQuotesLoader, IEXQuotesLoader, StooqQuotesLoader]
    while loaders:
        loader = loaders.pop(0)
        try:
            quotes = loader.get_quotes(*args, **kwargs)
            break
        except (RemoteDataError, ImmediateDeprecationError) as e:
            logger.error('get_quotes => error: %r', e)
    return quotes