'''This submodule contains functions to preprocess and update data.'''

import datetime
import json
import re
from pathlib import Path

import numpy as np
import pandas as pd
import requests as rq

from .scaler import Scaler

PACKAGEDIR = Path(__file__).parent.absolute()


def get_data(ticker = 'AAPL', column = 'close', length = 15, step = 1, start_date = '01-01-2013', split_date = '01-01-2022', end_date = '01-01-2023', flatten = False, validate = False):
    '''
    Prepares data for training and evaluating.

    Args:

        ticker: Ticker to get data for.

        column: Column from HLOCV to work with.

        length: Length of arrays, length-1 values are for fitting, 1 value is for evaluating.

        step: Step to cut data using sliding window.

        start_date: Date to start cutting data from.

        split_date: Date to split into train/test.

        end_date: Date to end cutting data.

        flatten: Shape format:  (cuts, length-1) or (cuts, length-1, 1).

        validate: To make validation split or not.

    Returns:
        x_train, x_test, y_train, y_test, scaler: train and test data with scaler to work with.

    Example:
    >>> get_data('AAPL', 'close', 10)
    [[0.122, 0.12, 0.125, ..], ..]
    [0.12, ..]
    [[0.132, 0.13, 0.135, ..], ..]
    [0.13, ..]
    Scaler()
    '''
    data = pd.read_parquet(f'{PACKAGEDIR}/data.parquet.gz')
    data = data[(data.dateTime >= start_date) & (data.ticker == ticker)]

    train_data = data[(data.dateTime < split_date)][column].values.reshape(-1, 1)
    test_data =  data[(data.dateTime >= split_date) & (data.dateTime < end_date)][column].values.reshape(-1, 1)

    train_set = [train_data[j:j+length,0] for j in range(0, len(train_data)-length, step)]
    test_set =  [test_data[j:j+length,0] for j in range(0, len(test_data)-length, step)]

    scaler = Scaler().fit(train_set)
    scaled_train_set = scaler.scale(train_set)
    scaled_test_set = scaler.scale(test_set)

    scaled_x_train, scaled_x_test = scaled_train_set[:,:length-1], scaled_test_set[:,:length-1]
    scaled_y_train, scaled_y_test = scaled_train_set[:,length-1],  scaled_test_set[:,length-1]

    if not flatten:
        scaled_x_train = np.reshape(scaled_x_train, (scaled_x_train.shape[0], length - 1,1))
        scaled_x_test = np.reshape(scaled_x_test, (scaled_x_test.shape[0], length - 1,1))

    if validate:
        val_data = data[(data.dateTime >= end_date) & (data.ticker == ticker)][column].values.reshape(-1, 1)
        val_set = [val_data[j:j+length,0] for j in range(0, len(val_data)-length, step)]
        scaled_val_set = scaler.scale(val_set)
        scaled_x_val, scaled_y_val = scaled_val_set[:,:length-1], scaled_val_set[:,length-1]
        return scaled_x_train, scaled_x_test, scaled_x_val, scaled_y_train, scaled_y_test, scaled_y_val, scaler
    else:
        return scaled_x_train, scaled_x_test, scaled_y_train, scaled_y_test, scaler

def update_data(tickers = []):
    '''
    Updates stored data for defined tickers.

    Args:

        tickers (list): Tickers list to update data for.

    Example:
    >>> get_data(['AMZN', 'TSLA', 'NVDA']])
    Info about 3 tickers successfully uploaded.
    '''
    all_tickers_df = pd.read_parquet(f'{PACKAGEDIR}/data.parquet.gz')
    for i in tickers:
        headers = {"Accept":"text/html", "Accept-Language":"en-US", "Referer":"https://www.nasdaq.com/", "User-Agent":"Chrome/64.0.3282.119"}
        resp = rq.get(f'https://api.nasdaq.com/api/quote/{i}/chart?assetclass=stocks&fromdate=2023-04-29&todate={datetime.datetime.now().strftime("%Y-%m-%d")}', headers=headers, verify=True)
        if resp.status_code == 200:
            try:
                smth = json.loads(re.search('\[.*\]', resp.text).group())
                cur_tick_data = pd.DataFrame([smth[k]['z'] for k in range(len(smth))])
                cur_tick_data['ticker'] = i
                for col_name in ['high','low','open','close','volume','value']:
                    cur_tick_data[col_name] = pd.to_numeric(cur_tick_data[col_name].str.replace(',',''))
                cur_tick_data['dateTime'] = pd.to_datetime(cur_tick_data['dateTime'])
                all_tickers_df = pd.concat([all_tickers_df, cur_tick_data])
            except KeyError:
                pass
        else:
            print(f'ERROR: smth is wrong with {i}')
    all_tickers_df.to_parquet(f'{PACKAGEDIR}/data.parquet.gz', compression='gzip')
    print(f'Info about {len(tickers)} tickers successfully uploaded.')
