from modules import api, stream
from modules import terminal

from datetime import datetime, timedelta
import pprint
from pathFiles import PATH_UBUNTU

from datetime import datetime, timedelta
from archivosVPS_6 import archivosCSVClase
import smtplib
import traceback
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

import os
import sys
import json
import requests
import datetime
import time

# variables globlaes!!!
buclePrincipal = True
segundero = 0

# timeOpen = "00:05:00"
# timeClose = "23:00:00"

# timeIB1 = "00:05:00"
# timeIB1Close = "23:00:00"

# timeIB2 = "00:05:00"
# timeIB2Close = "23:00:00"

# timeIB3 = "00:05:00"
# timeIB3Close = "23:00:00"

# timeIB4 = "00:10:00"
# timeIB4Close = "23:00:00"

# timeIB5 = "00:15:00"
# timeIB5Close = "23:00:00"

# timeIB6 = "00:20:00"
# timeIB6Close = "23:00:00"

timeOpen = "09:29:00"
timeClose = "16:00:00"

timeIB1 = "09:40:00"
timeIB1Close = "16:00:00"

timeIB2 = "10:30:00"
timeIB2Close = "16:00:00"

timeIB3 = "11:00:00"
timeIB3Close = "16:00:00"

timeIB4 = "11:30:00"
timeIB4Close = "16:00:00"

timeIB5 = "09:31:00"
timeIB5Close = "16:00:00"

timeIB6 = "09:31:00"
timeIB6Close = "16:00:00"

fechaActual = datetime.datetime.now().strftime("%Y-%m-%d")

MAX_RETRIES = 3
RETRY_DELAY_SECONDS = 30

# Cambiar al directorio
os.chdir('/home/seba/projects/VPS_Streaming_CS')


def obtener_quotes_con_reintento(instruments):
    for intento in range(MAX_RETRIES):
        try:
            quotes_response = api.quotes.getList(instruments).json()
            return quotes_response
        except json.decoder.JSONDecodeError as json_error:
            print(
                f"Error al decodificar JSON en el intento {intento + 1}: {json_error}")
        except requests.RequestException as request_error:
            print(
                f"Error en la solicitud HTTP en el intento {intento + 1}: {request_error}")
        except Exception as e:
            print(f"Otro error inesperado en el intento {intento + 1}: {type(e).__name__}: {e}")
        time.sleep(RETRY_DELAY_SECONDS)

    else:
        print(
            f"Se ha producido un error en {MAX_RETRIES} intentos. Deteniendo el programa.")
        sys.exit(1)


def iniciarIronButterfly(archivo, anchoAlas):
    symbol = "SPXW"
    holidays = ["01/01/2024", "01/15/2024", "02/19/2024", "05/27/2024",
                "06/19/2024", "07/04/2024", "09/02/2024", "11/28/2024", "12/25/2024"]

    # Creando instancia para procesar datos
    archivosCSV = archivosCSVClase()

    # Obtener el SPX al momento de la ejecucion. Primero chequar si el archivo existe. Si el archivo existe quiere decir que ya se inicio con un determinado SPX Strike.
    spxStrike = archivosCSV.obtenerSPX(archivo)
    if spxStrike == -1:  # El archivo no existe, por ende obtener el SPX Actual
        print("\nThe CSV file does not exist. Getting SPX Strike based on the current SPX price.")
        elSPX = api.quotes.getList(["$SPX"]).json()
        SPXLastPrice = elSPX["$SPX"]["quote"]["lastPrice"]
    else:
        SPXLastPrice = spxStrike

    mod = SPXLastPrice % 5
    if mod > 2.5:
        spxStrike = int(SPXLastPrice - mod) + 5
    else:
        spxStrike = int(SPXLastPrice - mod)

    # Iron butterfly formato CALL BTO - CALL STO - PUT STO - PUT BTO
    if "Next" not in archivo:
        fechaActual = datetime.datetime.now().date()
    else:
        if datetime.datetime.now().time() < datetime.datetime.strptime('12:00', '%H:%M').time():
            fechaActual = datetime.datetime.now().date()
        else:
            fechaActual = datetime.datetime.now().date() + timedelta(days=1)
            # Verificar si la nueva fecha es sábado o domingo y ajustar si es necesario
            # 5 representa sábado, 6 representa domingo
            while fechaActual.weekday() in [5, 6] or fechaActual.strftime("%m/%d/%Y") in holidays:
                fechaActual += timedelta(days=1)

    ironbutterfly = []
    ironbutterfly = archivosCSV.creacionListasIB(symbol, fechaActual, spxStrike, anchoAlas)
    return ironbutterfly


def principal():
    fechaActual = datetime.datetime.now().strftime("%Y-%m-%d")
    archivo_csv1 = PATH_UBUNTU + "Intraday_IB0940_" + str(fechaActual) + ".csv"
    archivo_csv2 = PATH_UBUNTU + "Intraday_IB1030_" + str(fechaActual) + ".csv"
    archivo_csv3 = PATH_UBUNTU + "Intraday_IB1100_" + str(fechaActual) + ".csv"
    archivo_csv4 = PATH_UBUNTU + "Intraday_IB1130_" + str(fechaActual) + ".csv"
    archivo_csv5 = PATH_UBUNTU + "Intraday_IB0932_" + str(fechaActual) + ".csv"  # IB 9:31 30 PUNTOS
    archivo_csv6 = PATH_UBUNTU + "Intraday_IB0933_" + str(fechaActual) + ".csv"  # IB 9:31 50 PUNTOS

    # archivo_csv15 = PATH_UBUNTU + "NextDay_IB1DTE.csv"
    SECONDS_BY_REQUEST = 6

    IB1_activado = False
    IB2_activado = False
    IB3_activado = False
    IB4_activado = False
    IB5_activado = False
    IB6_activado = False

    archivosCSV = archivosCSVClase()
    terminal.colorPrint.info("***** Market opened!!! *****")

    # Bucle principal obteniendo datos y guardando en archivos csv!!!
    while True:
        hora_actual = time.strftime("%H:%M:%S")
        # obtiene el precio del SPX
        elSPX = obtener_quotes_con_reintento(instruments=["$SPX"])
        elVIX = obtener_quotes_con_reintento(instruments=["$VIX"])

        # chequea si la respuesta viene con los datos del lastPrice y si hay un diccioanario $SPX
        # if elSPX is not None and "$SPX" in elSPX and "lastPrice" in elSPX["$SPX"]:
        if (elSPX is not None and "$SPX" in elSPX and "quote" in elSPX["$SPX"] and "lastPrice" in elSPX["$SPX"]["quote"]) and (elVIX is not None and "$VIX" in elVIX and "quote" in elVIX["$VIX"] and "lastPrice" in elVIX["$VIX"]["quote"]):
            SPXLastPrice = elSPX["$SPX"]["quote"]["lastPrice"]
            VIXLastPrice = elVIX["$VIX"]["quote"]["lastPrice"]

            print("")
            terminal.colorPrint.spx(str(SPXLastPrice))
            terminal.colorPrint.vix(str(VIXLastPrice))

            # Comenzar el streaming para el 1er IB 09:40
            if hora_actual >= timeIB1 and hora_actual <= timeIB1Close:
                if IB1_activado == False:
                    print("\nStarting IB 09:40... Wings 40")
                    IB1_activado = True
                    ironbutterfly1 = iniciarIronButterfly(archivo_csv1, 40)

                    print(ironbutterfly1)
                    SECONDS_BY_REQUEST = 6
                # obtiene cotizaciones
                quotes_response1 = obtener_quotes_con_reintento(instruments=ironbutterfly1)
                time.sleep(0.5)

                archivosCSV.guardarEnLista1(
                    archivo_csv1, quotes_response1, SPXLastPrice, VIXLastPrice)

            # Comenzar el streaming para el 2do IB 10:30
            if hora_actual >= timeIB2 and hora_actual <= timeIB2Close:
                if IB2_activado == False:
                    print("\nStarting IB 10:30... Wings 40")
                    IB2_activado = True
                    ironbutterfly2 = iniciarIronButterfly(archivo_csv2, 40)
                    print(ironbutterfly2)
                    SECONDS_BY_REQUEST = 5.5

                # obtiene cotizaciones
                quotes_response2 = obtener_quotes_con_reintento(
                    instruments=ironbutterfly2)
                time.sleep(0.5)
                # guarda resultados en lista/archivo
                archivosCSV.guardarEnLista2(
                    archivo_csv2, quotes_response2, SPXLastPrice, VIXLastPrice)

            # Comenzar el streaming para el 3er IB 11:00
            if hora_actual >= timeIB3 and hora_actual <= timeIB3Close:
                if IB3_activado == False:
                    print("\nStarting IB 11:00... Wings 40")
                    IB3_activado = True
                    ironbutterfly3 = iniciarIronButterfly(archivo_csv3, 40)
                    print(ironbutterfly3)
                    SECONDS_BY_REQUEST = 5

                # obtiene cotizaciones
                quotes_response3 = obtener_quotes_con_reintento(
                    instruments=ironbutterfly3)
                time.sleep(0.5)
                # guarda resultados en lista/archivo
                archivosCSV.guardarEnLista3(
                    archivo_csv3, quotes_response3, SPXLastPrice, VIXLastPrice)

            # Comenzar el streaming para el 4to IB 11:30
            if hora_actual >= timeIB4 and hora_actual <= timeIB4Close:
                if IB4_activado == False:
                    print("\nStarting IB 11:30... Wings 40")
                    IB4_activado = True
                    ironbutterfly4 = iniciarIronButterfly(archivo_csv4, 40)
                    print(ironbutterfly4)
                    SECONDS_BY_REQUEST = 4.5

                # Obtiene cotizaciones!!!
                quotes_response4 = obtener_quotes_con_reintento(
                    instruments=ironbutterfly4)
                time.sleep(0.5)
                # Guarda resultados en lista/archivo!!!
                archivosCSV.guardarEnLista4(
                    archivo_csv4, quotes_response4, SPXLastPrice, VIXLastPrice)

            # Comenzar el streaming para el IB 9:31 con alas de 30
            if hora_actual >= timeIB5 and hora_actual <= timeIB5Close:
                if IB5_activado == False:
                    print("\nStarting IB 9:31... Wings 30")
                    IB5_activado = True
                    ironbutterfly5 = iniciarIronButterfly(archivo_csv5, 30)
                    print(ironbutterfly5)
                    SECONDS_BY_REQUEST = 4.5

                # Obtiene cotizaciones!!!
                quotes_response5 = obtener_quotes_con_reintento(
                    instruments=ironbutterfly5)
                time.sleep(0.5)
                # Guarda resultados en lista/archivo!!!
                archivosCSV.guardarEnLista5(
                    archivo_csv5, quotes_response5, SPXLastPrice, VIXLastPrice)

            # Comenzar el streaming para el IB 9:31 con alas de 50
            if hora_actual >= timeIB6 and hora_actual <= timeIB6Close:
                if IB6_activado == False:
                    print("\nStarting IB 9:31... Wings 50")
                    IB6_activado = True
                    ironbutterfly6 = iniciarIronButterfly(archivo_csv6, 50)
                    print(ironbutterfly6)
                    SECONDS_BY_REQUEST = 4.5

                # Obtiene cotizaciones!!!
                quotes_response6 = obtener_quotes_con_reintento(
                    instruments=ironbutterfly6)
                time.sleep(0.5)
                # Guarda resultados en lista/archivo!!!
                archivosCSV.guardarEnLista6(
                    archivo_csv6, quotes_response6, SPXLastPrice, VIXLastPrice)

        else:
            print("\nNo $SPX or $VIXor lastPrice found in response!!!")

        time.sleep(SECONDS_BY_REQUEST)

        if hora_actual >= timeClose:
            return


def send_email(subject, body):
    # Configura tu servidor de correo electrónico y credenciales
    email_server = 'smtp.titan.email'
    email_port = 587
    email_username = 'info@spxbutterflies.com'
    email_password = 'Daleriver11$s'

    # Configura el correo electrónico
    sender_name = 'SPX Butterflies'
    sender_email = 'info@spxbutterflies.com'
    receiver_email = 'seba34e@gmail.com'

    message = MIMEMultipart()
    message['From'] = f'{sender_name} <{sender_email}>'
    message['To'] = receiver_email
    message['Subject'] = subject
    message.attach(MIMEText(body, 'plain'))

    # Conéctate al servidor de correo electrónico y envía el mensaje
    with smtplib.SMTP(email_server, email_port) as server:
        server.starttls()
        server.login(email_username, email_password)
        server.sendmail(sender_email, receiver_email, message.as_string())


def timeToMarketOpen(hora_actual, hora_apertura):
    diferencia_tiempo = hora_apertura - hora_actual
    # Imprimir la diferencia de tiempo en formato hh:mm:ss
    print(f"V6 - Time for the market open: {diferencia_tiempo // timedelta(hours=1):02}:{(diferencia_tiempo % timedelta(hours=1)) // timedelta(minutes=1):02}:{(diferencia_tiempo % timedelta(minutes=1)) // timedelta(seconds=1):02}", end="\r", flush=True)
    time.sleep(1)


def is_holiday(fecha, holidays):
    # Verificar si la fecha está en la lista de días feriados
    return fecha.strftime("%m/%d/%Y") in holidays


def calcular_hora_apertura(hora_actual, hora_primera_estrategia, holidays):
    dias_a_sumar = 1

    while True:
        # Calcular la nueva fecha sumando los días correspondientes
        nueva_fecha = hora_actual.date() + timedelta(days=dias_a_sumar)

        # Verificar si la nueva fecha es un día feriado o fin de semana (sábado o domingo)

        if not (is_holiday(nueva_fecha, holidays) or nueva_fecha.weekday() in [5, 6]):
            break  # Salir del bucle si no es un día feriado ni fin de semana

        # Si es un día feriado o fin de semana, sumar un día adicional y verificar nuevamente
        dias_a_sumar += 1

    # Calcular la nueva hora_apertura
    nueva_hora_apertura = datetime.datetime.combine(
        nueva_fecha, hora_primera_estrategia)
    print(nueva_hora_apertura)

    return nueva_hora_apertura


# Comienzo del progragma!!!
os.system("clear")  # Borra la pantalla!!!

marketIsOpen = False
hora_actual_string = time.strftime("%H:%M:%S")
hora_actual = datetime.datetime.now()
hora_cierre = datetime.datetime.strptime(timeClose, "%H:%M:%S").time()
hora_primera_estrategia = datetime.datetime.strptime(timeOpen, "%H:%M:%S").time()
holidays = ["01/01/2024", "01/15/2024", "02/19/2024", "05/27/2024", "06/19/2024", "07/04/2024", "09/02/2024", "11/28/2024", "12/25/2024"]

# Lógica para determinar hora_apertura
if hora_actual.time() > hora_cierre and hora_actual.time() < datetime.time(23, 59, 59):
    # Si es de tarde, obtener la fecha del día siguiente
    hora_apertura = datetime.datetime.combine(hora_actual.date() + timedelta(days=1), hora_primera_estrategia)
else:
    # Si es mañana, obtener la fecha actual
    hora_apertura = datetime.datetime.combine(hora_actual.date(), hora_primera_estrategia)

try:
    while True:
        hora_actual = datetime.datetime.now()
        timeToMarketOpen(hora_actual, hora_apertura)

        if hora_actual >= hora_apertura:
            os.system("clear")  # Borra la pantalla!!!
            marketIsOpen = True  # Comenzar el streaming para el 1er estragegia!!!

        if marketIsOpen:
            send_email("SPX Butterflies - mainStreamingVPS", "mainStreamingVPS: The data collection process began. Good trading!!!")
            api.initialize()  # checks tokens & loads variables
            api.updateTokensAutomatic()  # starts thread to update tokens automatically
            principal()
            # Si salio de principal, es porque el mercado cerró y volvera a iniciarse el proceso de espera!!!!
            send_email("SPX Butterflies - mainStreamingVPS", "mainStreamingVPS: market closed satisfactorily. Closed data collection process.")

            print("\n***** The market is closed *****\n")
            marketIsOpen = False
            hora_apertura = calcular_hora_apertura(hora_actual, hora_primera_estrategia, holidays)


except Exception as e:
    error_message = f"Error occurred: {str(e)}\n\n{traceback.format_exc()}"
    # Envía un correo electrónico o notificación
    send_email("mainStreamingVPS is stopped!!! Verify!!!", error_message)
