"""Utils to get stock data from Quandl"""

import quandl
import numpy as np
import pandas as pd


ticks_dicts = {
    "btc": {
        "tick": "BCHARTS/BITSTAMPUSD",
        "data_cols": ["Close", "Volume (BTC)"],
    },
    "eth": {"tick": "BITFINEX/ETHUSD", "data_cols": ["Last"]},
    "idx500": {
        "tick": "MULTPL/SP500_REAL_PRICE_MONTH",
        "data_cols": ["Value"],
    },
    "gold": {"tick": "WGC/GOLD_DAILY_USD", "data_cols": ["Value"]},
    "gas": {"tick": "FRED/GASREGCOVW", "data_cols": ["Value"]},
    "cons_idx": {"tick": "UMICH/SOC1", "data_cols": ["Index"]},
    "month_sav": {"tick": "FRED/PSAVERT", "data_cols": ["Value"]},
    "yale_cons_idx": {
        "tick": "YALE/US_CONF_INDEX_VAL_INST",
        "data_cols": ["Index Value"],
    },
    "cons_idx_infl": {"tick": "RATEINF/CPI_USA", "data_cols": ["Value"]},
    "cons_conf_idx": {
        "tick": "OECD/KEI_CSCICP02_USA_ST_M",
        "data_cols": ["Value"],
    },
    "yearly_us_rate": {
        "tick": "NAHB/INTRATES",
        "data_cols": [
            "Federal Funds Rate",
            "Freddie Mac Commitment Fixed Rate Mortgages",
            "Prime Rate",
        ],
    },
    "fed_for": {"tick": "FRED/BASE", "data_cols": ["Value"]},
}


def get_col_names_for_tick(tick="BCHARTS/BITSTAMPUSD"):
    """
    Return the columns available for the tick. Startdate is late by default to avoid getting much data
    """
    return quandl.get(tick, start_date=None).columns


def make_df_from_ticks(
    api_key,
    ticks_dicts=ticks_dicts,
    start_date="2017-01-01",
    end_date="2030-12-31",
    verbose=False,
):
    """
    Make a df from the ticks in the ticks_list
    """

    quandl.ApiConfig.api_key = api_key
    df = pd.DataFrame()
    first = True

    for name, tick_dict in ticks_dicts.items():
        if verbose:
            print(f"\nGetting data for {name}")
        for data_col in tick_dict["data_cols"]:
            try:
                if verbose:
                    print(f"{data_col}")
                tick_data = quandl.get(
                    tick_dict["tick"], start_date=start_date, end_date=end_date
                )
                if first:
                    df[name + "_" + data_col] = tick_data[data_col]
                    first = False
                else:
                    new_df = pd.DataFrame()
                    new_df[name + "_" + data_col] = tick_data[data_col]
                    df = pd.concat([df, new_df], axis=1, sort=False)

            except Exception as E:
                print(E, f"Available columns for {name}", tick_data.columns)

    # fill forward and backward the missing data
    df.fillna(method="ffill", axis=0, inplace=True)
    df.fillna(method="bfill", axis=0, inplace=True)

    return df


class divide_by_first:
    """
    Get the period growths for an investment whose values over time are given in a series
    """

    def __init__(self, date=None):
        self.date = date

    def fit_transform(self, series):
        """Get first term and divide all by first"""
        if self.date:
            divisor = series.loc[self.date]
        else:
            divisor = series.iloc[0]
        series.apply(lambda x: x / divisor)
        return series.apply(lambda x: x / divisor)


def normalize_df(df, columns=None, method=divide_by_first):
    """
    Normalize the columns of a dataframe
    """
    if columns is None:
        columns = df.columns
    scaler = method()
    df_norm = df.copy()
    for col in columns:
        # if the fit_transform works on a series
        try:
            df_norm[col] = scaler.fit_transform(df_norm[col])
        # otherwise, like standard scaler, turn everything into an array of array of single value
        except Exception as E:
            df_norm[col] = scaler.fit_transform(np.array(df_norm[col]).reshape(-1, 1))
    return df_norm
