import os
import time
import pandas as pd
import pandas_ta as ta
import logging
from datetime import datetime, timedelta
import pytz
from thefirstock import thefirstock
from typing import List
import numpy as np
import requests
import sys


class StockDataFetcher:
    def __init__(self, client_details: List[str]):
        self.client_details = client_details
        self.user_id = client_details[0]
        self.ist = pytz.timezone('Asia/Kolkata')
        self.logger = self.setup_logger()
        print("\n\n\n\n")
        self.logger.info("**************************")

    def setup_logger(self) -> logging.Logger:
        logger = logging.getLogger(__name__)
        logger.setLevel(logging.INFO)
        if not logger.handlers:
            formatter = self.ISTFormatter('%(asctime)s - %(levelname)s - %(message)s')
            console_handler = logging.StreamHandler()
            console_handler.setFormatter(formatter)
            logger.addHandler(console_handler)
        logging.getLogger().handlers.clear()
        return logger

    class ISTFormatter(logging.Formatter):
        def formatTime(self, record, datefmt=None):
            ist = pytz.timezone('Asia/Kolkata')
            record_time = datetime.fromtimestamp(record.created, tz=ist)
            return record_time.strftime(datefmt or '%Y-%m-%d %H:%M:%S')

    def login(self):
        try:
            response = thefirstock.firstock_login(*self.client_details)
            if response.get("status") == "success":
                self.logger.info("Login successful")
            else:
                self.logger.error(f"Login failed: {response}")
        except Exception as e:
            self.logger.error(f"Login error: {e}")

    def fetch_time_price_series(
        self, exchange: str, trading_symbol: str, start_time: str, end_time: str, interval: str
    ) -> pd.DataFrame:
        print("\n\n")
        self.logger.info(f"Fetching data for {trading_symbol}")
        try:
            response = thefirstock.firstock_TimePriceSeries(
                userId=self.user_id,
                exchange=exchange,
                tradingSymbol=trading_symbol,
                startTime=start_time,
                endTime=end_time,
                interval=interval,
            )
            if response.get("status") == "success":
                return pd.DataFrame(response.get("data", []))
            else:
                self.logger.error(f"Fetch failed: {response}")
                return pd.DataFrame()
        except Exception as e:
            self.logger.error(f"Error fetching series: {e}")
            return pd.DataFrame()
        
    def getStepValueAndShortSymbol(self, symbol):
        tmp_symbol=symbol
        if symbol == 'NSE:Nifty 50':
            step_value = 50
            tmp_symbol='NIFTY'
        elif symbol == 'NSE:Nifty Bank':
            step_value = 100
            tmp_symbol='BANKNIFTY'
        elif symbol == 'NSE:NIFTY MID SELECT':
            step_value = 25
            tmp_symbol='MIDCPNIFTY'
        elif symbol == 'NSE:Nifty Fin Service':
            step_value = 50
            tmp_symbol='FINNIFTY'
        elif symbol == 'BSE:SENSEX':
            step_value = 100
            tmp_symbol='SENSEX'
        else:
            step_value = 50

        return step_value, tmp_symbol

    def process_symbol_data(self, symbol: str, interval: int, start_time: datetime, end_time: datetime):
        step_value, tmp_symbol = self.getStepValueAndShortSymbol(symbol)
        exchange, trading_symbol = symbol.split(":")

        # Fetch Data
        df = self.fetch_time_price_series(
            exchange, trading_symbol,
            start_time.strftime("%d/%m/%Y %H:%M:%S"),
            end_time.strftime("%d/%m/%Y %H:%M:%S"),
            str(interval),
        )
        
        if df.empty:
            self.logger.warning(f"No data for {trading_symbol}")
            return

        # Preprocess timestamps and ensure data integrity
        #df['time'] = pd.to_datetime(df['time']).dt.tz_localize(self.ist)
        df['time'] = pd.to_datetime(df['time'], errors='coerce', dayfirst=True)
        if not df['time'].dt.tz:
            df['time'] = df['time'].dt.tz_localize(self.ist)

        df = df[~((df['time'].dt.hour == 9) & (df['time'].dt.minute < 15))]
        df = df[~(((df['time'].dt.hour == 15) & (df['time'].dt.minute >= 31)) | ((df['time'].dt.hour > 15) & (df['time'].dt.hour < 23)))]
        current_time = datetime.now(self.ist)
        df['elapsedTime'] = (current_time - df['time']).dt.total_seconds() // 60
        df = df.sort_values(by='time', ascending=True)
        #print(df)

        df['intc'] = pd.to_numeric(df['intc'], errors='coerce')
        

        # Compute moving averages for support/resistance entry
        df['Short_MA'] = df['intc'].rolling(window=10).mean()  # Short-term average
        df['Long_MA'] = df['intc'].rolling(window=50).mean()  # Long-term average

        df['mean'] = df['intc'].mean()
        df['std'] = df['intc'].std()
        df['mean_dev'] = (df['intc'] - df['intc'].mean()) / df['intc'].std()

        df = df.dropna(subset=['Short_MA']).reset_index(drop=True)
        df = df.dropna(subset=['Long_MA']).reset_index(drop=True)
        df = df.dropna(subset=['mean_dev']).reset_index(drop=True)


        #print (df)
        threshold = 1.0
        df = df[~df['mean_dev'].between(-threshold, threshold)]


        df = df[((df['intc'] < df['Short_MA']) & (df['Short_MA'] < df['Long_MA'])) |
                 ((df['intc'] > df['Short_MA']) & (df['Short_MA'] > df['Long_MA']))]
        
       
        # Entry based on statistical threshold
        df.loc[
            (df['intc'] < df['Short_MA']) &
            (df['intc'] < df['Long_MA']) &
            (df['mean_dev'] < -1),
            'Signal'
        ] = 'BUY'
        
        df.loc[
            (df['intc'] > df['Short_MA']) &
            (df['intc'] > df['Long_MA']) &
            (df['mean_dev'] > 1),
            'Signal'
        ] = 'SELL'


        df['momentum'] = df['intc'].diff(5)

        df = df.dropna(subset=['momentum']).reset_index(drop=True)

        save_output = False
        if save_output:
            columns_to_remove = ['ssboe', 'into', 'inth', 'intl', 'intvwap', 'intv', 'intoi', 'v', 'oi', 'elapsedTime']
            df_1 = df.drop(columns=columns_to_remove, errors='ignore')
            output_path = os.path.join("/var/www/html/ACTIONS/", f"{tmp_symbol}.csv")
            df_1.to_csv(output_path, index=False)

        # Execute only when new signal is observed
        #df['Signal_Change'] = df['Signal'] != df['Signal'].shift(1)
        #df = df[df['Signal_Change']].copy()

        df.loc[
            (df['Signal'] == 'BUY') & ((df['momentum'] > 0) & (df['momentum'].shift(1) < 0)),
            'Final_Trade'
        ] = 'CONFIRMED_BUY'

        df.loc[
            (df['Signal'] == 'SELL') & ((df['momentum'] < 0) & (df['momentum'].shift(1) > 0)),
            'Final_Trade'
        ] = 'CONFIRMED_SELL'


        # Log Signals & Output Results
        df.dropna(subset=['Final_Trade'], inplace=True)


        df = df.copy()  # Add this line before modifying the DataFrame
        df.loc[:, 'instrument'] = df['intc'].apply(lambda x: str(round(x / step_value) * step_value))
        # Append tmp_symbol at the beginning of the instrument
        df['instrument'] = tmp_symbol + df['instrument']

        # Add 'CE' at the end if Final_Trade is CONFIRMED_BUY, or 'PE' if CONFIRMED_SELL
        df.loc[df['Final_Trade'] == 'CONFIRMED_BUY', 'instrument'] += 'CE'
        df.loc[df['Final_Trade'] == 'CONFIRMED_SELL', 'instrument'] += 'PE'


        
        
        #print(df[['time', 'intc', 'Signal', 'instrument', 'elapsedTime' ]])
        print(df[['time', 'intc', 'mean', 'std', 'mean_dev', 'momentum', 'Final_Trade','instrument', 'elapsedTime' ]][-5:])
        last_entry = df[['time', 'intc', 'Signal', 'momentum', 'Final_Trade','instrument', 'elapsedTime' ]][-1:]
        elapsedTime = int(last_entry['elapsedTime'].iloc[0])
        
        if elapsedTime < 360:
            self.createEntry(last_entry)

        '''
        else:
            self.createEntry(last_entry)
        '''




    def createEntry(self, last_entry):

        url = "http://143.244.141.41/php/createEntry.php"  # Replace with your actual URL

        tickTime=last_entry['time'].iloc[-1]
        tickTime_str = tickTime.strftime("%Y-%m-%d_%H:%M:%S")

        # Define the parameters
        params = {
            'tickTime': str(tickTime_str),
            'instrument': str(last_entry['instrument'].iloc[-1]),
            'closePrice': str(last_entry['intc'].iloc[-1]),
            'signal': str(last_entry['Signal'].iloc[-1])
        }

        # Perform the GET request
        self.logger.info(f"\n\nGet Request with params: {params}\n")
        response = requests.get(url, params=params)
        if response.status_code != 200:
            self.logger.error(f"Request failed with status code: {response.status_code}")
            self.logger.error(response.text)  # Print error message if available
        else:
            self.logger.info(f"Request success: {response.text}")


    def fetch_all_data(self):
        
        
        symbols = {
            "NSE:Nifty 50": 28,
            "NSE:Nifty Bank": 28,
            "NSE:NIFTY MID SELECT": 14,
            "NSE:Nifty Fin Service": 28,
            "BSE:SENSEX": 28
        }


        for interval in [3]:
            for symbol, days in symbols.items():
                time.sleep(1)
                start_time = datetime.now(self.ist) - timedelta(days=days)
                end_time = datetime.now(self.ist).replace(hour=15, minute=30)
                self.process_symbol_data(symbol, interval, start_time, end_time)


if __name__ == "__main__":
    client_details = ['TT1582', 'O9i8u7y6##', '15111982', 'TT1582_API', 'ed87fa73888bc882c5d79bf832c0f9eb']
    client_details = ['GA0810', 'O9i8u7y6$$', '08101994', 'GA0810_API', '83a3652534fd8232e5e6d0173a069d79']
    stock_fetcher = StockDataFetcher(client_details)
    stock_fetcher.login()
    stock_fetcher.fetch_all_data()
