"""
Panel de venta: metodo de pago, monto, boton VENDER y resultado.
Estados: IDLE -> WAITING -> SUCCESS / TIMEOUT / ERROR
"""
import threading
import customtkinter as ctk
from typing import Callable, Optional
import api
from ui.kb_shortcuts import bind_entry

# Estados internos del panel
IDLE = "idle"
WAITING = "waiting"
SUCCESS = "success"
TIMEOUT = "timeout"
ERROR = "error"

PAYMENT_METHODS = [
    ("Efectivo", "cash"),
    ("Transferencia", "transfer"),
    ("Tarjeta", "card"),
]


class SalePanel(ctk.CTkFrame):
    """
    Panel de venta. Se muestra cuando el usuario selecciona un paquete.
    Llama a `on_sale_complete(session_data)` cuando la venta termina con exito.
    """

    def __init__(self, parent, on_sale_complete: Optional[Callable] = None, **kwargs):
        super().__init__(parent, fg_color=("gray85", "#0d1117"), corner_radius=10,
                         border_width=1, border_color="#333355", **kwargs)
        self.on_sale_complete = on_sale_complete

        self._package: Optional[dict] = None
        self._state = IDLE
        self._result: Optional[dict] = None   # resultado del hilo secundario
        self._session_id: Optional[str] = None

        # Variable para metodo de pago
        self._payment_var = ctk.StringVar(value="cash")
        # Variable para monto recibido
        self._amount_var = ctk.StringVar(value="")

        self._build_ui()

    # ------------------------------------------------------------------
    # Construccion UI
    # ------------------------------------------------------------------

    def _build_ui(self):
        """Construye todos los widgets (algunos ocultos segun estado)."""
        # --- Titulo del paquete seleccionado ---
        self._lbl_pkg = ctk.CTkLabel(
            self,
            text="",
            font=ctk.CTkFont(size=16, weight="bold"),
            text_color="#4fc3f7",
        )
        self._lbl_pkg.pack(anchor="w", padx=16, pady=(14, 2))

        # --- Metodo de pago ---
        ctk.CTkLabel(
            self,
            text="Metodo de pago:",
            font=ctk.CTkFont(size=12),
            text_color="#aaaaaa",
        ).pack(anchor="w", padx=16, pady=(8, 2))

        payment_row = ctk.CTkFrame(self, fg_color="transparent")
        payment_row.pack(fill="x", padx=16, pady=(0, 8))

        self._payment_buttons = {}
        for label, value in PAYMENT_METHODS:
            btn = ctk.CTkButton(
                payment_row,
                text=label,
                width=110,
                height=36,
                corner_radius=8,
                fg_color=("#333333", "#222244"),
                hover_color="#1a237e",
                border_width=2,
                border_color="#333333",
                font=ctk.CTkFont(size=12),
                command=lambda v=value: self._set_payment(v),
            )
            btn.pack(side="left", padx=(0, 6))
            self._payment_buttons[value] = btn

        # Marcar efectivo por defecto
        self._set_payment("cash")

        # --- Monto recibido ---
        ctk.CTkLabel(
            self,
            text="Monto recibido ($):",
            font=ctk.CTkFont(size=12),
            text_color="#aaaaaa",
        ).pack(anchor="w", padx=16, pady=(0, 2))

        self._entry_amount = ctk.CTkEntry(
            self,
            textvariable=self._amount_var,
            placeholder_text="0.00",
            font=ctk.CTkFont(size=16),
            height=40,
            width=160,
        )
        self._entry_amount.pack(anchor="w", padx=16, pady=(0, 12))
        bind_entry(self._entry_amount)

        # --- Boton VENDER ---
        self._btn_sell = ctk.CTkButton(
            self,
            text="VENDER",
            font=ctk.CTkFont(size=18, weight="bold"),
            height=52,
            corner_radius=10,
            fg_color="#1565c0",
            hover_color="#0d47a1",
            command=self._on_sell_click,
        )
        self._btn_sell.pack(fill="x", padx=16, pady=(0, 10))

        # --- Panel de estado/resultado (oculto inicialmente) ---
        self._result_frame = ctk.CTkFrame(self, fg_color="transparent")
        self._result_frame.pack(fill="x", padx=16, pady=(0, 12))

        self._lbl_status = ctk.CTkLabel(
            self._result_frame,
            text="",
            font=ctk.CTkFont(size=13),
            wraplength=340,
            justify="center",
        )
        self._lbl_status.pack(pady=(4, 4))

        self._btn_retry = ctk.CTkButton(
            self._result_frame,
            text="Reintentar (acercar pulsera)",
            height=38,
            corner_radius=8,
            fg_color="#e65100",
            hover_color="#bf360c",
            command=self._on_retry_click,
        )
        # No se empaqueta hasta que haya timeout/error

    # ------------------------------------------------------------------
    # Logica publica
    # ------------------------------------------------------------------

    def load_package(self, pkg: dict):
        """Carga un paquete seleccionado y muestra el formulario."""
        self._package = pkg
        self._session_id = None
        self._set_state(IDLE)

        mins = pkg["minutes"]
        if mins >= 60:
            time_str = f"{mins // 60}h {mins % 60}min" if mins % 60 else f"{mins // 60}h"
        else:
            time_str = f"{mins} min"

        self._lbl_pkg.configure(
            text=f"{pkg['name']}  —  {time_str}  |  ${pkg['price']:.2f}"
        )
        self._amount_var.set(str(pkg["price"]))

    # ------------------------------------------------------------------
    # Metodo de pago
    # ------------------------------------------------------------------

    def _set_payment(self, value: str):
        """Resalta el boton de pago seleccionado."""
        self._payment_var.set(value)
        for v, btn in self._payment_buttons.items():
            if v == value:
                btn.configure(border_color="#4fc3f7", fg_color="#0d47a1")
            else:
                btn.configure(border_color="#333333", fg_color=("#333333", "#222244"))

    # ------------------------------------------------------------------
    # Flujo de venta: threading pattern
    # ------------------------------------------------------------------

    def _on_sell_click(self):
        """Valida y lanza la venta en hilo secundario."""
        if self._package is None:
            return
        if self._state == WAITING:
            return

        # Validar monto
        try:
            amount = float(self._amount_var.get().replace(",", "."))
            if amount <= 0:
                raise ValueError
        except (ValueError, AttributeError):
            self._set_status("Ingresa un monto valido mayor a 0.", "#f44336")
            return

        # Cambiar a estado WAITING
        self._result = None
        self._set_state(WAITING)

        # Lanzar en hilo secundario
        t = threading.Thread(target=self._do_sell, args=(amount,), daemon=True)
        t.start()

        # Polling desde el hilo principal
        self.after(200, self._poll_result)

    def _do_sell(self, amount: float):
        """Ejecuta en hilo secundario. NO toca widgets."""
        result = api.sell(
            package_id=self._package["id"],
            payment_method=self._payment_var.get(),
            amount_received=amount,
        )
        self._result = result

    def _poll_result(self):
        """Hilo principal: revisa si el hilo secundario termino."""
        if self._result is None:
            # Todavia esperando — animar el texto
            current = self._lbl_status.cget("text")
            dots = (current.count(".") % 3) + 1
            self._lbl_status.configure(
                text=f"Acerque la pulsera al programador{'.' * dots}"
            )
            self.after(200, self._poll_result)
            return

        # Resultado listo — procesarlo en el hilo principal
        result = self._result
        self._result = None

        if result.get("error"):
            self._session_id = None
            self._set_state(ERROR)
            self._set_status(f"Error: {result['error']}", "#f44336")

        elif result.get("status") == "ok":
            self._session_id = result.get("session_id")
            self._set_state(SUCCESS)
            mins = result.get("minutes", 0)
            self._set_status(
                f"Pulsera programada!\n"
                f"{result.get('package_name', '')} | {mins} min | "
                f"${result.get('amount', 0):.2f}",
                "#4caf50",
            )
            if self.on_sale_complete:
                self.on_sale_complete(result)

        elif result.get("status") == "timeout":
            self._session_id = result.get("session_id")
            self._set_state(TIMEOUT)
            self._set_status(
                "Pulsera no detectada (timeout).\n"
                "Acerca la pulsera y presiona Reintentar.",
                "#ff9800",
            )

        else:
            self._session_id = None
            self._set_state(ERROR)
            self._set_status(f"Respuesta inesperada del servidor.", "#f44336")

    def _on_retry_click(self):
        """Reintenta la programacion usando el session_id existente."""
        if self._session_id is None:
            # No hay session: venta nueva
            self._on_sell_click()
            return

        self._result = None
        self._set_state(WAITING)

        t = threading.Thread(target=self._do_retry, daemon=True)
        t.start()
        self.after(200, self._poll_result)

    def _do_retry(self):
        """Ejecuta retry en hilo secundario."""
        result = api.retry_sell(self._session_id)
        self._result = result

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

    def _set_state(self, state: str):
        """Actualiza el estado visual segun el flujo."""
        self._state = state

        if state == IDLE:
            self._btn_sell.configure(
                text="VENDER",
                state="normal",
                fg_color="#1565c0",
                hover_color="#0d47a1",
            )
            self._entry_amount.configure(state="normal")
            self._lbl_status.configure(text="")
            self._btn_retry.pack_forget()

        elif state == WAITING:
            self._btn_sell.configure(
                text="Esperando pulsera...",
                state="disabled",
                fg_color="#424242",
            )
            self._entry_amount.configure(state="disabled")
            self._set_status("Acerque la pulsera al programador...", "#4fc3f7")
            self._btn_retry.pack_forget()

        elif state == SUCCESS:
            self._btn_sell.configure(
                text="Nueva venta",
                state="normal",
                fg_color="#1b5e20",
                hover_color="#2e7d32",
            )
            self._entry_amount.configure(state="normal")
            self._btn_retry.pack_forget()

        elif state in (TIMEOUT, ERROR):
            self._btn_sell.configure(
                text="Nueva venta",
                state="normal",
                fg_color="#1565c0",
                hover_color="#0d47a1",
            )
            self._entry_amount.configure(state="normal")
            if self._session_id:
                self._btn_retry.pack(fill="x", pady=(4, 0))

    def _set_status(self, text: str, color: str = "#cccccc"):
        self._lbl_status.configure(text=text, text_color=color)
