"""
Panel de login del sistema ICEBERG Manillas POS.

Disenado como CTkFrame para embeber dentro de AppWindow (ventana unica).

Flujo:
  1. USB polling externo llama set_usb_status() para habilitar/bloquear login
  2. Usuario ingresa usuario + password
  3. Auth contra Operator Cloud / servidor local / cache offline
  4. Si tiene multiples sedes -> selector de sede
  5. Si tiene solo una sede -> llama on_success(user)
"""
import threading
import customtkinter as ctk
from typing import Callable, Optional
import auth
import api
from ui.kb_shortcuts import bind_entry


class LoginScreen(ctk.CTkFrame):
    """Panel de inicio de sesion, embebible en AppWindow."""

    def __init__(self, parent, on_success: Callable[[dict], None],
                 on_close: Optional[Callable] = None):
        super().__init__(parent, fg_color="transparent", width=480, height=540)
        self.pack_propagate(False)
        self.grid_propagate(False)

        from config import TEST_MODE
        self.on_success   = on_success
        self._on_close    = on_close
        self._busy        = False
        self._show_pw     = False
        self._usb_ok      = TEST_MODE  # en TEST_MODE no bloquea por USB
        self._usb_bypass  = False      # bypass controlado desde AppWindow
        self._usb_real    = False      # estado real del USB (del polling)
        self._server_ok   = False
        self._auth_result: dict | None = None
        self._username    = ""

        self._build_login()

    # ==================================================================
    # Paso 1 — Formulario de login
    # ==================================================================

    def _build_login(self):
        self._login_frame = ctk.CTkFrame(
            self, fg_color="#111827", corner_radius=16,
            border_width=1, border_color="#1e2a3a",
        )
        self._login_frame.place(
            relx=0.5, rely=0.5, anchor="center", relwidth=0.92, relheight=0.96)

        # Logo
        ctk.CTkLabel(
            self._login_frame, text="ICEBERG",
            font=ctk.CTkFont(family="Segoe UI", size=32, weight="bold"),
            text_color="#4fc3f7",
        ).pack(pady=(28, 0))
        ctk.CTkLabel(
            self._login_frame, text="Manillas POS",
            font=ctk.CTkFont(size=14), text_color="#888888",
        ).pack(pady=(2, 16))

        # Estado del servidor
        self._lbl_server = ctk.CTkLabel(
            self._login_frame,
            text="Verificando servidor...",
            font=ctk.CTkFont(size=12, weight="bold"),
            text_color="#ff9800",
        )
        self._lbl_server.pack(pady=(0, 4))

        # Estado USB (siempre visible, cambia de color/texto)
        self._lbl_usb = ctk.CTkLabel(
            self._login_frame,
            text="Verificando controlador...",
            font=ctk.CTkFont(size=12, weight="bold"),
            text_color="#ff9800",
            wraplength=340, justify="center",
        )
        self._lbl_usb.pack(pady=(0, 12))

        # Usuario
        ctk.CTkLabel(self._login_frame, text="Usuario",
                     font=ctk.CTkFont(size=12), text_color="#aaaaaa",
        ).pack(anchor="w", padx=36, pady=(0, 4))
        self._entry_email = ctk.CTkEntry(
            self._login_frame, placeholder_text="usuario",
            font=ctk.CTkFont(size=14), height=42, corner_radius=8,
        )
        self._entry_email.pack(fill="x", padx=36, pady=(0, 14))
        # Return en email -> mover foco a password
        self._entry_email.bind("<Return>", lambda e: self._entry_pass.focus_set())

        # Contrasena + ojo
        ctk.CTkLabel(self._login_frame, text="Contrasena",
                     font=ctk.CTkFont(size=12), text_color="#aaaaaa",
        ).pack(anchor="w", padx=36, pady=(0, 4))

        pw_row = ctk.CTkFrame(self._login_frame, fg_color="transparent")
        pw_row.pack(fill="x", padx=36, pady=(0, 14))

        self._btn_eye = ctk.CTkButton(
            pw_row, text="👁", width=42, height=42, corner_radius=8,
            fg_color=("#1e1e2e", "#16192a"),
            hover_color=("#2e2e44", "#22263a"),
            font=ctk.CTkFont(size=18),
            text_color="#555577",
            command=self._toggle_password,
        )
        self._btn_eye.pack(side="right")

        self._entry_pass = ctk.CTkEntry(
            pw_row, placeholder_text="contrasena",
            show="*", font=ctk.CTkFont(size=14), height=42, corner_radius=8,
        )
        self._entry_pass.pack(side="left", fill="x", expand=True, padx=(0, 6))
        # Return en password -> intentar login
        self._entry_pass.bind("<Return>", lambda e: self._attempt_login())

        # Toast state
        self._toast = None
        self._toast_timer = None

        # Boton ingresar — inicia deshabilitado hasta confirmar USB
        self._btn = ctk.CTkButton(
            self._login_frame, text="INGRESAR",
            font=ctk.CTkFont(size=15, weight="bold"),
            height=48, corner_radius=10,
            fg_color="#1565c0", hover_color="#0d47a1",
            state="disabled",
            command=self._attempt_login,
        )
        self._btn.pack(fill="x", padx=36)

        # Boton cerrar app
        if self._on_close:
            ctk.CTkButton(
                self._login_frame, text="Cerrar App",
                font=ctk.CTkFont(size=12, weight="bold"),
                height=36, corner_radius=8,
                fg_color="#7f1d1d", hover_color="#b91c1c",
                border_width=1, border_color="#dc2626",
                text_color="#fca5a5",
                command=self._on_close,
            ).pack(pady=(14, 2))

        # Version (esquina inferior izquierda, sutil)
        from config import APP_VERSION
        ctk.CTkLabel(
            self._login_frame, text=f"v{APP_VERSION}",
            font=ctk.CTkFont(size=11), text_color="#444444",
        ).place(relx=0.04, rely=0.96, anchor="sw")

        # F10 config servidor (atajo oculto)
        self.winfo_toplevel().bind("<F10>", lambda e: self._open_server_config())

        self._entry_email.focus_set()
        bind_entry(self._entry_email)
        bind_entry(self._entry_pass)

    def _toggle_password(self):
        self._show_pw = not self._show_pw
        if self._show_pw:
            self._entry_pass.configure(show="")
            self._btn_eye.configure(text_color="#4fc3f7")
        else:
            self._entry_pass.configure(show="*")
            self._btn_eye.configure(text_color="#555577")

    # ==================================================================
    # Status indicators — llamados desde AppWindow cada ~3s
    # ==================================================================

    def _update_login_btn(self):
        """Habilita el boton solo si USB y servidor estan OK."""
        if not self._busy:
            can = self._usb_ok and self._server_ok
            self._btn.configure(state="normal" if can else "disabled")

    def set_server_status(self, reachable: bool):
        """Actualiza el indicador de servidor."""
        self._server_ok = reachable
        if reachable:
            self._lbl_server.configure(
                text="● Servidor conectado",
                text_color="#4caf50",
            )
        else:
            self._lbl_server.configure(
                text="● Servidor apagado",
                text_color="#f44336",
            )
        self._update_login_btn()

    def set_usb_status(self, connected: bool):
        """Actualiza el indicador USB."""
        self._usb_real = connected
        if self._usb_bypass:
            # Bypass activo: siempre OK, no cambiar el label de USB
            self._usb_ok = True
        else:
            self._usb_ok = connected
        if connected:
            self._lbl_usb.configure(
                text="● Controlador conectado",
                text_color="#4caf50",
            )
        elif self._usb_bypass:
            self._lbl_usb.configure(
                text="● USB no obligatorio",
                text_color="#ff9800",
            )
        else:
            self._lbl_usb.configure(
                text="⚠  Controlador USB no conectado.\n"
                     "Conecta el programador para ingresar.",
                text_color="#f44336",
            )
        self._update_login_btn()

    def set_usb_bypass(self, bypass: bool):
        """Llamado desde AppWindow cuando F5 cambia el bypass."""
        self._usb_bypass = bypass
        if bypass:
            self._usb_ok = True
            if not self._usb_real:
                self._lbl_usb.configure(
                    text="● USB no obligatorio",
                    text_color="#ff9800",
                )
        else:
            self._usb_ok = self._usb_real
            self.set_usb_status(self._usb_real)
        self._update_login_btn()

    # ==================================================================
    # Configuracion de servidor
    # ==================================================================

    def _open_server_config(self):
        """Abre un dialogo para configurar server_url y agent_url."""
        cfg = api.load_config()
        dialog = ctk.CTkToplevel(self)
        dialog.title("Configuracion de conexion")
        dialog.geometry("420x300")
        dialog.resizable(False, False)
        dialog.grab_set()
        dialog.configure(fg_color="#111827")

        ctk.CTkLabel(
            dialog, text="Configuracion de conexion",
            font=ctk.CTkFont(size=16, weight="bold"), text_color="#4fc3f7",
        ).pack(pady=(18, 14))

        # Server URL
        ctk.CTkLabel(dialog, text="URL del Servidor",
                     font=ctk.CTkFont(size=12), text_color="#aaaaaa",
        ).pack(anchor="w", padx=28)
        entry_server = ctk.CTkEntry(dialog, font=ctk.CTkFont(size=13),
                                    height=38, corner_radius=8)
        entry_server.pack(fill="x", padx=28, pady=(2, 10))
        entry_server.insert(0, cfg.get("server_url", "http://127.0.0.1:8000"))

        # Agent URL
        ctk.CTkLabel(dialog, text="URL del Agente",
                     font=ctk.CTkFont(size=12), text_color="#aaaaaa",
        ).pack(anchor="w", padx=28)
        entry_agent = ctk.CTkEntry(dialog, font=ctk.CTkFont(size=13),
                                   height=38, corner_radius=8)
        entry_agent.pack(fill="x", padx=28, pady=(2, 14))
        entry_agent.insert(0, cfg.get("agent_url", "http://127.0.0.1:5555"))

        # Mensaje de estado
        lbl_status = ctk.CTkLabel(dialog, text="", font=ctk.CTkFont(size=11))
        lbl_status.pack(pady=(0, 6))

        def _save():
            server_val = entry_server.get().strip().rstrip("/")
            agent_val = entry_agent.get().strip().rstrip("/")
            if not server_val or not agent_val:
                lbl_status.configure(text="Completa ambos campos", text_color="#f44336")
                return
            cfg["server_url"] = server_val
            cfg["agent_url"] = agent_val
            api.save_config(cfg)
            lbl_status.configure(text="Guardado", text_color="#4caf50")
            dialog.after(600, dialog.destroy)

        btn_row = ctk.CTkFrame(dialog, fg_color="transparent")
        btn_row.pack(fill="x", padx=28)

        ctk.CTkButton(
            btn_row, text="Cancelar", width=100, height=36,
            fg_color="transparent", hover_color="#1a1a2a",
            text_color="#888888", corner_radius=8,
            command=dialog.destroy,
        ).pack(side="left")

        ctk.CTkButton(
            btn_row, text="Guardar", width=100, height=36,
            fg_color="#1565c0", hover_color="#0d47a1",
            corner_radius=8, command=_save,
        ).pack(side="right")

    # ==================================================================
    # Login
    # ==================================================================

    def _attempt_login(self):
        if self._busy or not self._usb_ok or not self._server_ok:
            return
        email = self._entry_email.get().strip()
        pwd   = self._entry_pass.get()
        if not email or not pwd:
            self._show_toast("Completa usuario y contrasena.",
                             color="#3e2700", border="#ff9800")
            return

        self._username = email
        self._busy     = True
        self._btn.configure(state="disabled", text="Verificando...")
        self._dismiss_toast()

        def _do():
            result = auth.authenticate(email, pwd)
            self.after(0, lambda: self._on_auth(result))

        threading.Thread(target=_do, daemon=True).start()

    def _on_auth(self, result):
        self._busy = False
        can = self._usb_ok and self._server_ok
        self._btn.configure(
            state="normal" if can else "disabled",
            text="INGRESAR",
        )

        if result is None:
            self._show_toast(
                "Usuario o contrasena incorrectos.",
                color="#5a0000", border="#f44336",
            )
            self._entry_pass.delete(0, "end")
            self._entry_pass.focus_set()
            return

        err = result.get("error") if isinstance(result, dict) else None

        if err == "no_venue_access":
            self._show_toast(
                "Este usuario no tiene acceso a ninguna sede.\n"
                "Contacta al administrador.",
                color="#5a0000", border="#f44336",
            )
            return

        if err == "sin_conexion":
            self._show_toast(
                "No se pudo conectar al servidor.\n"
                "Verifica que el servidor este encendido\n"
                "y que estes conectado a la red.",
                color="#3e2700", border="#ff9800",
            )
            return

        if err == "server_error":
            self._show_toast(
                "El servidor respondio con un error.\n"
                "Contacta al administrador.",
                color="#3e2700", border="#ff9800",
            )
            return

        self._auth_result = result
        venues = result.get("venues", [])
        local_venue = api.get_venue_id()

        # Verificar que el usuario tenga acceso a la sede de este deploy
        venue_ids = [v["id"] for v in venues] if venues else []
        if venues and local_venue not in venue_ids:
            self._show_toast(
                f"No tienes acceso a esta sede ({local_venue}).\n"
                "Contacta al administrador.",
                color="#5a0000", border="#f44336",
            )
            return

        # Sede fija por deploy — login directo sin selector
        self._finalize(local_venue)

    # ==================================================================
    # Toast no-invasivo (popup flotante arriba, auto-dismiss)
    # ==================================================================

    def _show_toast(self, message: str, color: str = "#5a0000",
                    border: str = "#f44336", duration: int = 5000):
        """Muestra un popup flotante en la parte superior con auto-dismiss."""
        self._dismiss_toast()

        toast = ctk.CTkFrame(
            self, fg_color=color, corner_radius=12,
            border_width=2, border_color=border,
        )
        toast.place(relx=0.5, y=18, anchor="n")

        ctk.CTkLabel(
            toast, text=message,
            font=ctk.CTkFont(size=13, weight="bold"),
            text_color="#ffffff", justify="center", wraplength=340,
        ).pack(padx=28, pady=(14, 14))

        toast.lift()
        self._toast = toast
        self._toast_timer = self.after(duration, self._dismiss_toast)

    def _dismiss_toast(self):
        """Oculta el toast actual si existe."""
        if hasattr(self, "_toast_timer") and self._toast_timer:
            self.after_cancel(self._toast_timer)
            self._toast_timer = None
        if hasattr(self, "_toast") and self._toast:
            self._toast.place_forget()
            self._toast.destroy()
            self._toast = None

    # ==================================================================
    # Paso 2 — Selector de sede (legacy, ya no se usa con deploy por ciudad)
    # ==================================================================

    def _show_venue_selector(self, venues: list):
        self._login_frame.place_forget()

        self._venue_frame = ctk.CTkFrame(
            self, fg_color="#111827", corner_radius=16,
            border_width=1, border_color="#1e2a3a",
        )
        self._venue_frame.place(
            relx=0.5, rely=0.5, anchor="center", relwidth=0.92, relheight=0.96)

        ctk.CTkLabel(
            self._venue_frame, text="ICEBERG",
            font=ctk.CTkFont(family="Segoe UI", size=32, weight="bold"),
            text_color="#4fc3f7",
        ).pack(pady=(28, 0))
        ctk.CTkLabel(
            self._venue_frame, text="Selecciona tu sede",
            font=ctk.CTkFont(size=14), text_color="#888888",
        ).pack(pady=(4, 24))

        for venue in venues:
            ctk.CTkButton(
                self._venue_frame,
                text=venue["name"],
                font=ctk.CTkFont(size=15, weight="bold"),
                height=52, corner_radius=10,
                fg_color="#1565c0", hover_color="#0d47a1",
                command=lambda vid=venue["id"]: self._finalize(vid),
            ).pack(fill="x", padx=36, pady=6)

        ctk.CTkButton(
            self._venue_frame, text="<- Volver",
            font=ctk.CTkFont(size=12), height=32, corner_radius=8,
            fg_color="transparent", hover_color="#1e2232",
            text_color="#666688",
            command=self._back_to_login,
        ).pack(pady=(12, 0))

    def _back_to_login(self):
        if hasattr(self, "_venue_frame"):
            self._venue_frame.place_forget()
        self._auth_result = None
        self._login_frame.place(
            relx=0.5, rely=0.5, anchor="center", relwidth=0.92, relheight=0.96)
        self._entry_pass.delete(0, "end")
        self._entry_email.focus_set()

    # ==================================================================
    # Finalizar login
    # ==================================================================

    def _finalize(self, venue_id: str):
        result = self._auth_result
        user = dict(result["user"])
        user["display_name"] = user.get("name", "Cajero")
        user["username"]     = user.get("email", self._username)
        user["permissions"]  = result.get("permissions", [])
        user["venues"]       = result.get("venues", [])
        user["venue_id"]     = venue_id
        user["offline"]      = result.get("offline", False)

        api.set_venue_id(venue_id)
        self.after(50, lambda: self.on_success(user))
