from typing import Dict

from io import StringIO
import json

import pandas as pd
import numpy as np

from .api_methods import API
from .namespaces import no_dividends_namespaces


class QueryData:
    """
    Set of methods to get symbols data from API.
    """

    @staticmethod
    def get_symbol_info(symbol: str) -> Dict[str, str]:
        json_input = API.get_symbol_info(symbol)
        return json.loads(json_input)

    @staticmethod
    def csv_to_series(csv_input: str, period: str) -> pd.Series:
        ts = pd.read_csv(StringIO(csv_input),
                         delimiter=',',
                         index_col=0,
                         parse_dates=[0],
                         dtype={1: np.float64},
                         engine='python')
        if not ts.empty:
            ts.index = ts.index.to_period(period.upper())
            ts = ts.squeeze('columns')
        return ts

    @staticmethod
    def get_macro_ts(symbol: str, first_date: str = '1913-01-01', last_date: str = '2100-01-01') -> pd.Series:
        """
        Requests API for Macroeconomic indicators time series (monthly data).
        - Inflation time series
        - Bank rates time series
        """
        csv_input = API.get_macro(symbol=symbol, first_date=first_date, last_date=last_date)
        return QueryData.csv_to_series(csv_input, period='M')

    @staticmethod
    def get_ror(symbol: str, first_date: str = '1913-01-01', last_date: str = '2100-01-01', period='M') -> pd.Series:
        """
        Requests API for rate of return time series.
        """
        csv_input = API.get_ror(symbol=symbol, first_date=first_date, last_date=last_date, period=period)
        return QueryData.csv_to_series(csv_input, period)

    @staticmethod
    def get_nav(symbol: str, first_date: str = '1913-01-01', last_date: str = '2100-01-01', period='M') -> pd.Series:
        """
        NAV time series for funds (works for PIF namespace only).
        """
        csv_input = API.get_nav(symbol=symbol, first_date=first_date, last_date=last_date, period=period)
        return QueryData.csv_to_series(csv_input, period=period)

    @staticmethod
    def get_close(symbol: str, first_date: str = '1913-01-01', last_date: str = '2100-01-01', period='M') -> pd.Series:
        """
        Gets 'close' time series for a ticker.
        """
        csv_input = API.get_close(symbol=symbol, first_date=first_date, last_date=last_date, period=period)
        return QueryData.csv_to_series(csv_input, period)

    @staticmethod
    def get_adj_close(symbol: str, first_date: str = '1913-01-01', last_date: str = '2100-01-01', period='M') -> pd.Series:
        """
        Gets 'adjusted close' time series for a ticker.
        """
        csv_input = API.get_adjusted_close(symbol=symbol, first_date=first_date, last_date=last_date, period=period)
        return QueryData.csv_to_series(csv_input, period)

    @staticmethod
    def get_dividends(symbol: str, first_date: str = '1913-01-01', last_date: str = '2100-01-01',) -> pd.Series:
        """
        Dividends time series daily data (dividend payment day should be considered).
        """
        if symbol.split('.', 1)[-1] not in no_dividends_namespaces():
            csv_input = API.get_dividends(symbol, first_date=first_date, last_date=last_date)
            ts = QueryData.csv_to_series(csv_input, period='D')
        else:
            # make empty time series when no dividends
            ts = pd.Series(dtype=float)
            ts.rename(symbol, inplace=True)
        return ts

    @staticmethod
    def get_live_price(symbol: str) -> float:
        price = API.get_live_price(symbol)
        return float(price)
