import wx
import urllib.request
import json
import threading
import time
from datetime import datetime

# URLs de los servicios oficiales
URL_OPENAI = "https://status.openai.com/api/v2/summary.json"
URL_ANTHROPIC = "https://status.anthropic.com/api/v2/summary.json"
URL_GOOGLE = "https://status.cloud.google.com/incidents.json"

# Diccionarios de traducción accesibles para lectura de pantalla
TEXTO_ESTADOS = {
    "operational": "[VERDE - OPERATIVO]",
    "AVAILABLE": "[VERDE - OPERATIVO]",
    "degraded_performance": "[AMARILLO - RENDIMIENTO DEGRADADO / LENTO]",
    "SERVICE_DISRUPTION": "[AMARILLO - DEGRADACIÓN DE SERVICIO]",
    "partial_outage": "[NARANJA - INTERRUPCIÓN PARCIAL]",
    "major_outage": "[ROJO - CAÍDA TOTAL / SIN SERVICIO]",
    "SERVICE_OUTAGE": "[ROJO - CAÍDA TOTAL / SIN SERVICIO]",
    "under_maintenance": "[AZUL - EN MANTENIMIENTO]",
}

TEXTO_INCIDENTES = {
    "investigating": "Investigando el problema",
    "identified": "Problema identificado",
    "monitoring": "Monitoreando la solución",
    "resolved": "Resuelto",
    "postmortem": "Análisis posterior"
}

def fetch_json(url):
    try:
        req = urllib.request.Request(
            url, 
            headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'}
        )
        with urllib.request.urlopen(req, timeout=8) as resp:
            if resp.status == 200:
                return json.loads(resp.read().decode('utf-8'))
    except Exception as e:
        print(f"Error cargando {url}: {e}")
    return None


class HelpDialog(wx.Dialog):
    """Diálogo de ayuda con TextCtrl de solo lectura y botón Aceptar en español."""
    def __init__(self, parent):
        super().__init__(parent, title="Ayuda y Leyenda de Estados", size=(650, 480))
        
        sizer = wx.BoxSizer(wx.VERTICAL)

        texto_ayuda = (
            "LEYENDA DE ESTADOS Y SIGNIFICADO DE DISTINTIVOS\n"
            "=====================================================\n\n"
            "1. DISTINTIVOS DE ESTADO:\n\n"
            "   • [VERDE - OPERATIVO]:\n"
            "     Todos los sistemas y funciones están operando normalmente.\n\n"
            "   • [AMARILLO - RENDIMIENTO DEGRADADO / LENTO]:\n"
            "     El servicio está funcionando pero presenta lentitud, respuestas demoradas o fallos intermitentes.\n\n"
            "   • [NARANJA - INTERRUPCIÓN PARCIAL]:\n"
            "     Una parte del servicio o una función específica no está disponible.\n\n"
            "   • [ROJO - CAÍDA TOTAL / SIN SERVICIO]:\n"
            "     Interrupción grave o caída completa del servicio.\n\n"
            "   • [AZUL - EN MANTENIMIENTO]:\n"
            "     El sistema se encuentra en trabajos de mantenimiento programado.\n\n"
            "-----------------------------------------------------\n"
            "2. FASES DE INCIDENTES:\n\n"
            "   • Investigando: El equipo técnico está buscando la causa raíz del fallo.\n"
            "   • Problema identificado: Se ha detectado la causa y se está preparando la solución.\n"
            "   • Monitoreando: La solución ha sido aplicada y se está supervisando la estabilidad.\n"
            "   • Resuelto: El problema se ha corregido por completo y el servicio vuelve a la normalidad.\n"
        )

        txt_ctrl = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.TE_READONLY)
        txt_ctrl.SetValue(texto_ayuda)
        txt_ctrl.SetInsertionPoint(0)

        sizer.Add(txt_ctrl, 1, wx.EXPAND | wx.ALL, 10)

        # Botón único Aceptar (en español)
        btn_aceptar = wx.Button(self, label="Aceptar")
        btn_aceptar.Bind(wx.EVT_BUTTON, lambda evt: self.EndModal(wx.ID_OK))
        
        sizer.Add(btn_aceptar, 0, wx.ALIGN_CENTER | wx.BOTTOM, 10)
        self.SetSizer(sizer)


class MainFrame(wx.Frame):
    def __init__(self):
        super().__init__(None, title="Monitor de Estado de IA - Accesible", size=(850, 650))
        self.SetMinSize((700, 500))

        panel_main = wx.Panel(self)
        main_sizer = wx.BoxSizer(wx.VERTICAL)

        # -------------------------------------------------------------
        # Panel superior de controles (Casilla, Intervalo, Botones)
        # -------------------------------------------------------------
        ctrl_panel = wx.Panel(panel_main)
        ctrl_sizer = wx.BoxSizer(wx.VERTICAL)

        # Fila 1: Casilla e intervalo
        row1_sizer = wx.BoxSizer(wx.HORIZONTAL)

        self.chk_auto = wx.CheckBox(ctrl_panel, label="Activar actualización automática en tiempo real")
        self.chk_auto.SetValue(True)
        self.chk_auto.Bind(wx.EVT_CHECKBOX, self.on_toggle_auto)

        lbl_freq = wx.StaticText(ctrl_panel, label="Actualizar cada:")
        self.spin_val = wx.SpinCtrl(ctrl_panel, value="15", min=1, max=999, size=(70, -1))
        self.spin_val.Bind(wx.EVT_SPINCTRL, self.on_interval_changed)
        self.spin_val.Bind(wx.EVT_TEXT, self.on_interval_changed)

        self.choice_unit = wx.Choice(ctrl_panel, choices=["Segundos", "Minutos"])
        self.choice_unit.SetSelection(0)
        self.choice_unit.Bind(wx.EVT_CHOICE, self.on_interval_changed)

        row1_sizer.Add(self.chk_auto, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 15)
        row1_sizer.Add(lbl_freq, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
        row1_sizer.Add(self.spin_val, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
        row1_sizer.Add(self.choice_unit, 0, wx.ALIGN_CENTER_VERTICAL, 0)

        # Fila 2: Botones de Acción
        row2_sizer = wx.BoxSizer(wx.HORIZONTAL)

        btn_refresh = wx.Button(ctrl_panel, label="Actualizar ahora")
        btn_refresh.Bind(wx.EVT_BUTTON, self.on_manual_refresh)

        btn_help = wx.Button(ctrl_panel, label="Ayuda de estados")
        btn_help.Bind(wx.EVT_BUTTON, self.on_show_help)

        self.lbl_status_bar = wx.StaticText(ctrl_panel, label="Estado: Cargando datos iniciales...")

        row2_sizer.Add(btn_refresh, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 10)
        row2_sizer.Add(btn_help, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 15)
        row2_sizer.Add(self.lbl_status_bar, 0, wx.ALIGN_CENTER_VERTICAL, 0)

        ctrl_sizer.Add(row1_sizer, 0, wx.EXPAND | wx.ALL, 8)
        ctrl_sizer.Add(row2_sizer, 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 8)
        ctrl_panel.SetSizer(ctrl_sizer)

        main_sizer.Add(ctrl_panel, 0, wx.EXPAND | wx.ALL, 5)

        # -------------------------------------------------------------
        # Pestañas (Notebook) con TextCtrl multilínea y solo lectura
        # -------------------------------------------------------------
        self.notebook = wx.Notebook(panel_main)

        # TextCtrl para cada pestaña
        self.txt_openai = wx.TextCtrl(self.notebook, style=wx.TE_MULTILINE | wx.TE_READONLY)
        self.txt_google = wx.TextCtrl(self.notebook, style=wx.TE_MULTILINE | wx.TE_READONLY)
        self.txt_anthropic = wx.TextCtrl(self.notebook, style=wx.TE_MULTILINE | wx.TE_READONLY)

        self.notebook.AddPage(self.txt_openai, "OpenAI (ChatGPT / API)")
        self.notebook.AddPage(self.txt_google, "Google (Gemini / Vertex AI)")
        self.notebook.AddPage(self.txt_anthropic, "Anthropic (Claude / API)")

        main_sizer.Add(self.notebook, 1, wx.EXPAND | wx.ALL, 5)
        panel_main.SetSizer(main_sizer)

        # Timer para auto-actualización
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.on_timer, self.timer)
        
        self.reiniciar_timer()
        self.on_refresh()

    def obtener_intervalo_ms(self):
        valor = self.spin_val.GetValue()
        unidad = self.choice_unit.GetSelection()  # 0 = Segundos, 1 = Minutos
        if unidad == 1:
            segundos = valor * 60
        else:
            segundos = valor
        return max(1, segundos) * 1000

    def reiniciar_timer(self):
        if self.timer.IsRunning():
            self.timer.Stop()
        if self.chk_auto.GetValue():
            ms = self.obtener_intervalo_ms()
            self.timer.Start(ms)

    def on_toggle_auto(self, event):
        self.reiniciar_timer()
        if self.chk_auto.GetValue():
            self.lbl_status_bar.SetLabel("Estado: Actualización automática ACTIVADA.")
        else:
            self.lbl_status_bar.SetLabel("Estado: Actualización automática PAUSADA.")

    def on_interval_changed(self, event):
        self.reiniciar_timer()

    def on_manual_refresh(self, event):
        self.on_refresh()

    def on_timer(self, event):
        self.on_refresh()

    def on_show_help(self, event):
        dlg = HelpDialog(self)
        dlg.ShowModal()
        dlg.Destroy()

    def on_refresh(self):
        self.lbl_status_bar.SetLabel("Estado: Consultando estado de los servicios...")
        threading.Thread(target=self._cargar_datos_hilo, daemon=True).start()

    def _cargar_datos_hilo(self):
        data_openai = fetch_json(URL_OPENAI)
        data_anthropic = fetch_json(URL_ANTHROPIC)
        data_google_raw = fetch_json(URL_GOOGLE)

        wx.CallAfter(self._actualizar_ui, data_openai, data_anthropic, data_google_raw)

    def _generar_texto_servicio(self, nombre_servicio, status_global, componentes, incidentes):
        ahora = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        txt_est_gen = TEXTO_ESTADOS.get(status_global, f"[{status_global.upper()}]")

        lineas = []
        lineas.append(f"=========================================================")
        lineas.append(f" ESTADO DE {nombre_servicio.upper()} - {ahora}")
        lineas.append(f"=========================================================")
        lineas.append(f"ESTADO GLOBAL: {txt_est_gen}")
        lineas.append(f"---------------------------------------------------------\n")

        # Incidentes
        if incidentes:
            lineas.append(f"⚠️ INCIDENTES Y PROBLEMAS ACTIVOS ({len(incidentes)}):")
            for idx, inc in enumerate(incidentes, 1):
                nombre_inc = inc.get("name", "Incidente reportado")
                fase_inc = TEXTO_INCIDENTES.get(inc.get("status"), inc.get("status", "En proceso"))
                lineas.append(f" {idx}. Incidente: {nombre_inc}")
                lineas.append(f"    Fase actual: {fase_inc}")
                if "detalles" in inc and inc["detalles"]:
                    lineas.append(f"    Detalle: {inc['detalles']}")
                lineas.append("")
            lineas.append("---------------------------------------------------------\n")
        else:
            lineas.append("✅ INCIDENTES ACTIVOS: Ninguno reportado.\n")
            lineas.append("---------------------------------------------------------\n")

        # Componentes
        lineas.append("📊 COMPONENTES Y SERVICIOS DETALLADOS:")
        for comp in componentes:
            nom = comp.get("name", "Servicio")
            est_raw = comp.get("status", "operational")
            est_txt = TEXTO_ESTADOS.get(est_raw, f"[{est_raw}]")
            lineas.append(f" • {nom:<32} -> {est_txt}")

        lineas.append("\n=========================================================")
        return "\n".join(lineas)

    def _actualizar_ui(self, data_openai, data_anthropic, data_google_raw):
        ahora_short = datetime.now().strftime("%H:%M:%S")
        self.lbl_status_bar.SetLabel(f"Estado: Información actualizada a las {ahora_short}")

        # 1. OpenAI
        if data_openai:
            st_gen = data_openai.get("status", {}).get("indicator", "none")
            comps = data_openai.get("components", [])
            incidents_raw = data_openai.get("incidents", [])
            incidents = []
            for inc in incidents_raw:
                det = inc.get("incident_updates", [{}])[0].get("body", "")
                incidents.append({"name": inc.get("name"), "status": inc.get("status"), "detalles": det})

            status_map = {"none": "operational", "minor": "degraded_performance", "major": "major_outage", "critical": "major_outage"}
            txt_val = self._generar_texto_servicio("OpenAI", status_map.get(st_gen, st_gen), comps, incidents)
            
            self.txt_openai.SetValue(txt_val)
            self.txt_openai.SetInsertionPoint(0)  # Dejar cursor/scroll al inicio arriba

            # Color de estado para la pestaña
            if st_gen == "none":
                tag = "[VERDE]"
            elif st_gen == "minor":
                tag = "[AMARILLO]"
            elif st_gen == "major":
                tag = "[NARANJA]"
            elif st_gen == "critical":
                tag = "[ROJO]"
            else:
                tag = "[VERDE]"
            self.notebook.SetPageText(0, f"OpenAI {tag}")

        # 2. Anthropic
        if data_anthropic:
            st_gen = data_anthropic.get("status", {}).get("indicator", "none")
            comps = data_anthropic.get("components", [])
            incidents_raw = data_anthropic.get("incidents", [])
            incidents = []
            for inc in incidents_raw:
                det = inc.get("incident_updates", [{}])[0].get("body", "")
                incidents.append({"name": inc.get("name"), "status": inc.get("status"), "detalles": det})

            status_map = {"none": "operational", "minor": "degraded_performance", "major": "major_outage", "critical": "major_outage"}
            txt_val = self._generar_texto_servicio("Anthropic Claude", status_map.get(st_gen, st_gen), comps, incidents)

            self.txt_anthropic.SetValue(txt_val)
            self.txt_anthropic.SetInsertionPoint(0)  # Dejar cursor/scroll al inicio arriba

            if st_gen == "none":
                tag = "[VERDE]"
            elif st_gen == "minor":
                tag = "[AMARILLO]"
            elif st_gen == "major":
                tag = "[NARANJA]"
            elif st_gen == "critical":
                tag = "[ROJO]"
            else:
                tag = "[VERDE]"
            self.notebook.SetPageText(2, f"Anthropic {tag}")

        # 3. Google
        if data_google_raw is not None:
            incidents_activos = []
            servicios_afectados = set()

            for item in data_google_raw:
                if not item.get("end"):
                    desc = item.get("external_desc", item.get("id", "Incidente en Google Cloud"))
                    serv_name = item.get("service_name", "Google Cloud / AI Services")
                    servicios_afectados.add(serv_name)
                    
                    det = ""
                    updates = item.get("updates", [])
                    if updates:
                        det = updates[0].get("text", "")[:250] + "..."
                    
                    incidents_activos.append({
                        "name": f"{serv_name}: {desc[:80]}",
                        "status": "investigating",
                        "detalles": det
                    })

            componentes_google = [
                {"name": "Vertex AI / Gemini API", "status": "SERVICE_DISRUPTION" if "Vertex AI" in servicios_afectados or "Generative AI" in servicios_afectados else "AVAILABLE"},
                {"name": "Google AI Studio", "status": "AVAILABLE"},
                {"name": "Google Cloud Infrastructure", "status": "SERVICE_DISRUPTION" if len(incidents_activos) > 0 else "AVAILABLE"},
                {"name": "Compute Engine & Cloud Run", "status": "SERVICE_DISRUPTION" if "Compute Engine" in servicios_afectados else "AVAILABLE"},
                {"name": "Cloud Storage & Databases", "status": "AVAILABLE"}
            ]

            status_google_gen = "SERVICE_DISRUPTION" if len(incidents_activos) > 0 else "AVAILABLE"
            txt_val = self._generar_texto_servicio("Google Gemini / Cloud", status_google_gen, componentes_google, incidents_activos)

            self.txt_google.SetValue(txt_val)
            self.txt_google.SetInsertionPoint(0)  # Dejar cursor/scroll al inicio arriba

            tag = "[VERDE]" if len(incidents_activos) == 0 else "[AMARILLO]"
            self.notebook.SetPageText(1, f"Google {tag}")


def main():
    app = wx.App(False)
    frame = MainFrame()
    frame.Center()
    frame.Show()
    app.MainLoop()

if __name__ == "__main__":
    main()
