import pandas as pd
from loguru import logger
import pytz
from datetime import datetime, timedelta
from scripts.constants.app_configuration import ReqTimeZone
from sklearn.preprocessing import MinMaxScaler


class DataPreprocessing:
    @staticmethod
    def remove_outliers(df, param_list):
        try:
            for col in param_list:
                lb = df[col].mean() - 3 * df[col].std()
                ub = df[col].mean() + 3 * df[col].std()
                logger.debug(f"Min values of {col} = {df[col].min()} \nLower Bracket of {col} = {lb}")
                logger.debug(f"Max values of {col} = {df[col].max()} \nUpper Bracket of {col} = {ub}")
                logger.debug(f'Shape of df before outlier removal = {df.shape}')
                df = (df[(df[col] > lb) & (df[col] < ub)])
                logger.debug(f'Shape of df after outlier removal = {df.shape}')
            logger.debug(f'Shape final df before outlier removal = {df.shape}')
            return df
        except Exception as e:
            logger.exception(f'Exception - {e}')

    @staticmethod
    def train_test_split(df):
        try:
            today_date = datetime.now(pytz.utc).astimezone(pytz.timezone(ReqTimeZone.required_tz)).date()
            df = df[df['date'] != today_date]
            yesterday_date = today_date - timedelta(days=1)
            df_train = df[df['date'] < yesterday_date]
            df_test = df[df['date'] == yesterday_date]
            df_train.reset_index(drop=True, inplace=True)
            df_test.reset_index(drop=True, inplace=True)
            df_train.drop(['date'], axis=1, inplace=True)
            df_test.drop(['date'], axis=1, inplace=True)
            return df, df_train, df_test
        except Exception as e:
            logger.exception(f'Exception - {e}')

    @staticmethod
    def get_standardized_data(df, param_list=None):
        try:
            if param_list is None:
                scaler = MinMaxScaler()
                df_std = pd.DataFrame(scaler.fit_transform(df), columns=list(df.columns))
                return df_std, scaler
            else:
                scaler = MinMaxScaler()
                df_std = pd.DataFrame(scaler.fit_transform(df.drop(param_list, axis=1)),
                                      columns=list(df.drop(param_list, axis=1).columns))
                return df_std, scaler
        except Exception as e:
            logger.exception(f'Exception - {e}')

    @staticmethod
    def get_transform_std_data(df, scaler, param_list=None):
        try:
            if param_list is None:
                df_std = pd.DataFrame(scaler.transform(df), columns=list(df.columns))
                return df_std
            else:
                df_std = pd.DataFrame(scaler.transform(df.drop(param_list, axis=1)),
                                      columns=list(df.drop(param_list, axis=1).columns))
                return df_std
        except Exception as e:
            logger.exception(f'Exception - {e}')