"""
Dialogo para otorgar una cortesia (pulsera gratuita).

El PIN de supervisor ya fue validado en SupervisorPinDialog.
Este dialogo solo pide: seleccionar paquete + nombre del cliente.

Flujo:
  1. Seleccionar paquete e ingresar nombre del cliente.
  2. Clic OTORGAR CORTESIA -> llama api.cortesia() en hilo (espera pulsera ~30s).
  3. Exito: muestra folio + supervisor_nombre. Se cierra en 3 segundos.
  4. Timeout: permite reintentar.

Diseño: popup flotante always-on-top, sin bordes del OS (estilo ICEBERG).
"""
import threading
import uuid
import customtkinter as ctk
from typing import Optional, Callable
import api
import wristband_tracker
from ui.kb_shortcuts import bind_entry

# ---------------------------------------------------------------------------
# Colores ICEBERG
# ---------------------------------------------------------------------------
_BG_CARD     = "#0f1228"
_ACCENT_GREEN = "#4caf50"
_ACCENT_DIM  = "#1b5e20"
_BTN_OK      = "#1b5e20"
_BTN_OK_HV   = "#2e7d32"
_BTN_CANCEL  = "transparent"
_BTN_CANCEL_HV = "#1a2440"
_BTN_RETRY   = "#e65100"
_BTN_RETRY_HV = "#bf360c"
_TEXT_DIM    = "#666677"
_TEXT_MID    = "#9999aa"
_ERR_RED     = "#f44336"
_OK_GREEN    = "#4caf50"
_CYAN        = "#4fc3f7"
_ORANGE      = "#ff9800"
_TOP_BAR     = "#2e7d32"
_SEPARATOR   = "#1a2440"

_STATE_IDLE    = "idle"
_STATE_WAITING = "waiting"
_STATE_OK      = "ok"
_STATE_TIMEOUT = "timeout"
_STATE_ERROR   = "error"


class CortesiaDialog(ctk.CTkToplevel):
    """
    Popup flotante ICEBERG para otorgar cortesia.
    El PIN/motivo ya fueron validados en SupervisorPinDialog.
    on_done(result) se llama cuando la cortesia se concede con exito.
    """

    def __init__(
        self,
        parent,
        packages: list,
        cashier: str = "caja1",
        supervisor: str = "",
        motivo: str = "",
        on_done: Optional[Callable] = None,
    ):
        super().__init__(parent)
        self._packages  = packages
        self._cashier   = cashier
        self._supervisor = supervisor
        self._motivo    = motivo
        self._on_done   = on_done
        self._state     = _STATE_IDLE
        self._result    = None
        self._pkg_var   = ctk.StringVar()
        self._last_pkg  = None

        # Ventana sin bordes del OS, siempre encima
        self.overrideredirect(True)
        self.attributes("-topmost", True)
        self.configure(fg_color=_BG_CARD)

        # Tamaño y posicion centrada sobre el padre
        self._win_w = 440
        self._win_h = 480
        self.geometry(f"{self._win_w}x{self._win_h}")
        self._center_on_parent(parent)

        # Grab modal
        self.grab_set()
        self.focus_force()

        # Card principal
        self._card = ctk.CTkFrame(
            self,
            fg_color=_BG_CARD,
            corner_radius=0,
            border_width=2,
            border_color=_ACCENT_DIM,
        )
        self._card.pack(fill="both", expand=True)

        # Bind Escape para cancelar
        self.bind("<Escape>", lambda e: self._close())
        self.bind("<Return>", lambda e: self._on_submit())

        # Permitir mover la ventana arrastrando
        self._drag_data = {"x": 0, "y": 0}
        self._card.bind("<Button-1>", self._start_drag)
        self._card.bind("<B1-Motion>", self._do_drag)

        self._build()

    # ------------------------------------------------------------------
    # Posicion y arrastre
    # ------------------------------------------------------------------

    def _center_on_parent(self, parent):
        self.update_idletasks()
        px = parent.winfo_rootx() + parent.winfo_width() // 2
        py = parent.winfo_rooty() + parent.winfo_height() // 2
        x = px - self._win_w // 2
        y = py - self._win_h // 2
        self.geometry(f"{self._win_w}x{self._win_h}+{x}+{y}")

    def _start_drag(self, event):
        self._drag_data["x"] = event.x
        self._drag_data["y"] = event.y

    def _do_drag(self, event):
        x = self.winfo_x() + (event.x - self._drag_data["x"])
        y = self.winfo_y() + (event.y - self._drag_data["y"])
        self.geometry(f"+{x}+{y}")

    # ------------------------------------------------------------------
    # UI
    # ------------------------------------------------------------------

    def _build(self):
        card = self._card

        # Barra verde superior
        bar = ctk.CTkFrame(card, fg_color=_TOP_BAR, height=4, corner_radius=0)
        bar.pack(fill="x", side="top")

        # Icono y titulo
        ctk.CTkLabel(
            card, text="\U0001F381",
            font=ctk.CTkFont(size=36),
        ).pack(pady=(18, 0))

        ctk.CTkLabel(
            card, text="Cortesia",
            font=ctk.CTkFont(size=20, weight="bold"),
            text_color=_ACCENT_GREEN,
        ).pack(pady=(4, 0))

        ctk.CTkLabel(
            card, text="Pulsera gratuita",
            font=ctk.CTkFont(size=11),
            text_color=_TEXT_DIM,
        ).pack(pady=(0, 10))

        # Separador
        ctk.CTkFrame(card, fg_color=_SEPARATOR, height=1, corner_radius=0).pack(
            fill="x", padx=30, pady=(0, 12)
        )

        # Paquete
        ctk.CTkLabel(
            card, text="Paquete:",
            font=ctk.CTkFont(size=12),
            text_color=_TEXT_MID,
        ).pack(anchor="w", padx=30, pady=(0, 2))

        pkg_names = [f"{p['name']}  ({p.get('minutes', 0)} min)" for p in self._packages]
        if pkg_names:
            self._pkg_var.set(pkg_names[0])
        self._pkg_dropdown = ctk.CTkComboBox(
            card, variable=self._pkg_var,
            values=pkg_names if pkg_names else ["Sin paquetes"],
            width=380, height=36,
            font=ctk.CTkFont(size=13),
            state="readonly",
            fg_color="#1a2440",
            border_color="#2a3a5a",
            button_color="#2a3a5a",
            button_hover_color="#3a4a6a",
            dropdown_fg_color="#1a2440",
        )
        self._pkg_dropdown.pack(padx=30, pady=(0, 10))

        # Nombre del cliente
        ctk.CTkLabel(
            card, text="Nombre del cliente:",
            font=ctk.CTkFont(size=12),
            text_color=_TEXT_MID,
        ).pack(anchor="w", padx=30, pady=(0, 2))

        self._entry_name = ctk.CTkEntry(
            card,
            placeholder_text="Nombre (opcional)",
            font=ctk.CTkFont(size=13), height=36,
            fg_color="#1a2440",
            border_color="#2a3a5a",
        )
        self._entry_name.pack(fill="x", padx=30, pady=(0, 12))

        # Info de autorizacion (solo lectura)
        if self._supervisor:
            info_frame = ctk.CTkFrame(card, fg_color="#111530", corner_radius=6)
            info_frame.pack(fill="x", padx=30, pady=(0, 12))

            ctk.CTkLabel(
                info_frame,
                text=f"Autorizado por:  {self._supervisor}",
                font=ctk.CTkFont(size=11),
                text_color=_ACCENT_GREEN,
            ).pack(anchor="w", padx=12, pady=(8, 2))

            if self._motivo:
                # Truncar motivo largo
                motivo_display = self._motivo if len(self._motivo) <= 50 else self._motivo[:47] + "..."
                ctk.CTkLabel(
                    info_frame,
                    text=f"Motivo:  {motivo_display}",
                    font=ctk.CTkFont(size=11),
                    text_color=_TEXT_MID,
                ).pack(anchor="w", padx=12, pady=(0, 8))

        # Boton principal
        self._btn_submit = ctk.CTkButton(
            card,
            text="OTORGAR CORTESIA  \u2192  ACERCAR PULSERA",
            font=ctk.CTkFont(size=14, weight="bold"), height=50,
            corner_radius=10, fg_color=_BTN_OK, hover_color=_BTN_OK_HV,
            command=self._on_submit,
        )
        self._btn_submit.pack(fill="x", padx=30, pady=(0, 6))

        # Estado / resultado
        self._lbl_status = ctk.CTkLabel(
            card, text="",
            font=ctk.CTkFont(size=13), wraplength=380, justify="center",
        )
        self._lbl_status.pack(pady=(0, 4))

        # Reintentar (oculto hasta timeout)
        self._btn_retry = ctk.CTkButton(
            card, text="Reintentar (acercar pulsera nuevamente)",
            height=36, corner_radius=8,
            fg_color=_BTN_RETRY, hover_color=_BTN_RETRY_HV,
            command=self._on_retry,
        )

        # Cancelar (ghost button)
        self._btn_cancel = ctk.CTkButton(
            card, text="Cancelar",
            font=ctk.CTkFont(size=12),
            fg_color=_BTN_CANCEL, hover_color=_BTN_CANCEL_HV,
            text_color=_TEXT_DIM, height=30,
            command=self._close,
        )
        self._btn_cancel.pack(pady=(0, 10))

        bind_entry(self._entry_name)
        self._entry_name.focus_set()

    # ------------------------------------------------------------------
    # Helpers
    # ------------------------------------------------------------------

    def _get_selected_pkg(self) -> Optional[dict]:
        selected = self._pkg_var.get()
        for p in self._packages:
            if f"{p['name']}  ({p.get('minutes', 0)} min)" == selected:
                return p
        return self._packages[0] if self._packages else None

    # ------------------------------------------------------------------
    # Flujo
    # ------------------------------------------------------------------

    def _on_submit(self):
        if self._state == _STATE_WAITING:
            return

        pkg = self._get_selected_pkg()
        if not pkg:
            self._lbl_status.configure(text="Selecciona un paquete.", text_color=_ERR_RED)
            return

        self._last_pkg = pkg
        self._start_request()

    def _on_retry(self):
        if self._last_pkg is None:
            return
        self._start_request()

    def _start_request(self):
        self._result = None
        self._set_state(_STATE_WAITING)
        threading.Thread(target=self._do_cortesia, daemon=True).start()
        self.after(200, self._poll)

    def _do_cortesia(self):
        pkg = self._last_pkg
        self._result = api.cortesia(
            package_id=str(pkg["id"]),
            cashier=self._cashier,
            motivo=self._motivo,
            supervisor=self._supervisor,
            red_minutes=pkg.get("minutes_red"),
            green_minutes=pkg.get("minutes_green"),
            blue_minutes=pkg.get("minutes_blue"),
        )

    def _poll(self):
        if self._result is None:
            dots = (self._lbl_status.cget("text").count(".") % 3) + 1
            self._lbl_status.configure(
                text=f"Acerque la pulsera al programador{'.' * dots}",
                text_color=_CYAN,
            )
            self.after(200, self._poll)
            return

        r = self._result
        self._result = None

        if r.get("error"):
            self._set_state(_STATE_ERROR)
            self._lbl_status.configure(
                text=f"Error: {r['error']}", text_color=_ERR_RED,
            )

        elif r.get("status") == "ok":
            pkg = self._last_pkg
            session_id = r.get("session_id", str(uuid.uuid4()))
            wristband_tracker.add(
                name=self._entry_name.get().strip() or "Cortesia",
                reference="",
                session_id=session_id,
                package_id=pkg["id"],
                package_name=pkg["name"],
                real_play_minutes=r.get("minutes", pkg.get("minutes", 0)),
            )
            self._show_success(r)

        elif r.get("status") == "timeout":
            self._set_state(_STATE_TIMEOUT)
            self._lbl_status.configure(
                text="Pulsera no detectada.\nAcerca la pulsera y presiona Reintentar.",
                text_color=_ORANGE,
            )

        elif r.get("status") == "error":
            msg = r.get("message", "Error desconocido.")
            self._set_state(_STATE_ERROR)
            self._lbl_status.configure(text=msg, text_color=_ERR_RED)

        else:
            self._set_state(_STATE_ERROR)
            self._lbl_status.configure(
                text="Respuesta inesperada del servidor.", text_color=_ERR_RED,
            )

    # ------------------------------------------------------------------
    # Pantalla de exito
    # ------------------------------------------------------------------

    def _show_success(self, result: dict):
        """Reemplaza la UI con la pantalla de exito."""
        self._set_state(_STATE_OK)

        # Limpiar card
        for widget in self._card.winfo_children():
            widget.destroy()

        # Barra verde
        ctk.CTkFrame(self._card, fg_color=_TOP_BAR, height=4, corner_radius=0).pack(
            fill="x", side="top"
        )

        # Checkmark grande
        ctk.CTkLabel(
            self._card, text="\u2713",
            font=ctk.CTkFont(size=52, weight="bold"),
            text_color=_OK_GREEN,
        ).pack(pady=(40, 8))

        ctk.CTkLabel(
            self._card, text="Cortesia otorgada!",
            font=ctk.CTkFont(size=20, weight="bold"),
            text_color=_OK_GREEN,
        ).pack(pady=(0, 6))

        folio = result.get("folio_number", "")
        if folio:
            ctk.CTkLabel(
                self._card, text=f"Folio: {folio}",
                font=ctk.CTkFont(size=14),
                text_color="#ffffff",
            ).pack(pady=(0, 4))

        sup = result.get("supervisor_nombre", "") or self._supervisor
        if sup:
            ctk.CTkLabel(
                self._card, text=f"Autorizado por: {sup}",
                font=ctk.CTkFont(size=12),
                text_color=_TEXT_MID,
            ).pack(pady=(0, 4))

        # Borde verde
        self._card.configure(border_color=_OK_GREEN)

        if self._on_done:
            self._on_done(result)
        self.after(3000, self._close)

    # ------------------------------------------------------------------
    # Estado visual
    # ------------------------------------------------------------------

    def _set_state(self, state: str):
        self._state = state
        if state == _STATE_IDLE:
            self._btn_submit.configure(
                state="normal",
                text="OTORGAR CORTESIA  \u2192  ACERCAR PULSERA",
                fg_color=_BTN_OK,
            )
            self._btn_retry.pack_forget()
            self._btn_cancel.pack(pady=(0, 10))
        elif state == _STATE_WAITING:
            self._btn_submit.configure(
                state="disabled", text="Esperando pulsera...",
                fg_color="#424242",
            )
            self._btn_retry.pack_forget()
            self._btn_cancel.pack_forget()
        elif state == _STATE_OK:
            pass  # _show_success maneja la UI
        elif state == _STATE_TIMEOUT:
            self._btn_submit.configure(
                state="normal",
                text="OTORGAR CORTESIA  \u2192  ACERCAR PULSERA",
                fg_color=_BTN_OK,
            )
            self._btn_retry.pack(fill="x", padx=30, pady=(0, 6))
            self._btn_cancel.pack(pady=(0, 10))
        elif state == _STATE_ERROR:
            self._btn_submit.configure(
                state="normal",
                text="OTORGAR CORTESIA  \u2192  ACERCAR PULSERA",
                fg_color=_BTN_OK,
            )
            self._btn_retry.pack_forget()
            self._btn_cancel.pack(pady=(0, 10))

    # ------------------------------------------------------------------

    def _close(self):
        self._state = _STATE_IDLE
        try:
            self.grab_release()
        except Exception:
            pass
        self.destroy()
