"""
Tracker de pulseras activas en memoria.
Se resetea al reiniciar la app.

Fases:
  VERDE  grace_minutes  = 1 min          (siempre)
  AZUL   play_minutes   = TEST_PLAY_MINUTES en prueba / minutos reales en produccion
  ROJO   red_minutes    = TEST_RED_MINUTES en prueba / RED_MINUTES en produccion
"""
from datetime import datetime
from typing import Optional
import uuid

from config import GRACE_MINUTES, TEST_MODE, TEST_PLAY_MINUTES, TEST_RED_MINUTES, RED_MINUTES

_active: list[dict] = []


def add(
    name: str,
    reference: str,
    session_id: Optional[str],
    package_id: str,
    package_name: str,
    real_play_minutes: int,
) -> dict:
    play_minutes = TEST_PLAY_MINUTES if TEST_MODE else real_play_minutes
    red_minutes  = TEST_RED_MINUTES  if TEST_MODE else RED_MINUTES

    entry = {
        "id":               str(uuid.uuid4()),
        "code":             _make_code(session_id),
        "name":             name.strip() or "(sin nombre)",
        "reference":        reference.strip(),
        "session_id":       session_id,
        "package_id":       package_id,
        "package_name":     package_name,
        "real_play_minutes": real_play_minutes,
        "play_minutes":     play_minutes,
        "grace_minutes":    GRACE_MINUTES,
        "red_minutes":      red_minutes,
        "start_time":       datetime.now(),
        "status":           "grace",
        "returned_at":      None,
    }
    _active.append(entry)
    return entry


def get_active() -> list[dict]:
    return [e for e in _active if e["status"] != "returned"]


def get_all() -> list[dict]:
    return list(_active)


def mark_returned(wristband_id: str):
    for e in _active:
        if e["id"] == wristband_id and e["status"] not in ("returned", "anulada"):
            e["status"] = "returned"
            e["returned_at"] = datetime.now()
            return


def mark_anulada(wristband_id: str):
    """Marca como anulada contablemente. La pulsera sigue activa fisicamente."""
    for e in _active:
        if e["id"] == wristband_id and e["status"] not in ("returned", "anulada"):
            e["status"] = "anulada"
            e["anulada_at"] = datetime.now()
            return


def update_reprogram(wristband_id: str, green_min: int, blue_min: int, red_min: int):
    """Actualiza tiempos y reinicia el reloj tras reprogramar una pulsera."""
    for e in _active:
        if e["id"] == wristband_id and e["status"] != "returned":
            e["grace_minutes"]    = green_min
            e["play_minutes"]     = blue_min
            e["red_minutes"]      = red_min
            e["real_play_minutes"] = blue_min
            e["start_time"]       = datetime.now()
            e["status"]           = "grace"
            return


def get_phase(entry: dict) -> tuple[str, float]:
    """
    Calcula fase actual y progreso de barra (1.0=llena, 0.0=vacia).
    Actualiza entry["status"] en cada llamada.
    Pulseras anuladas mantienen su estado sin cambiar fase.
    """
    # Anulada: no cambia de fase, se muestra como "anulada" fija
    if entry.get("status") == "anulada":
        return "anulada", 0.0

    now = datetime.now()
    elapsed = (now - entry["start_time"]).total_seconds()

    grace_secs = entry["grace_minutes"] * 60
    play_secs  = entry["play_minutes"]  * 60
    red_secs   = entry["red_minutes"]   * 60

    if elapsed < grace_secs:
        entry["status"] = "grace"
        progress = 1.0 - (elapsed / grace_secs)
        return "grace", max(0.0, min(1.0, progress))

    elif elapsed < grace_secs + play_secs:
        entry["status"] = "playing"
        play_elapsed = elapsed - grace_secs
        progress = 1.0 - (play_elapsed / play_secs)
        return "playing", max(0.0, min(1.0, progress))

    elif elapsed < grace_secs + play_secs + red_secs:
        entry["status"] = "expired"
        red_elapsed = elapsed - grace_secs - play_secs
        progress = 1.0 - (red_elapsed / red_secs)
        return "expired", max(0.0, min(1.0, progress))

    else:
        # Fase roja terminada: auto-devolver
        mark_returned(entry["id"])
        return "expired", 0.0


def get_stats() -> dict:
    """
    Retorna conteos de manillas por fase.
    Llamar DESPUES de que get_phase() haya actualizado los statuses en _tick.
    """
    all_entries = get_active()
    playing        = sum(1 for e in all_entries if e.get("status") in ("grace", "playing"))
    expired        = sum(1 for e in all_entries if e.get("status") == "expired")
    anuladas       = sum(1 for e in all_entries if e.get("status") == "anulada")
    returned_today = sum(1 for e in _active if e.get("status") == "returned")
    return {
        "total_active":   len(all_entries),
        "playing":        playing,         # verde + azul (en uso normal)
        "expired":        expired,         # rojo / vibrando (por retirar)
        "anuladas":       anuladas,        # anuladas contablemente (pulsera sigue ahi)
        "returned_today": returned_today,  # devueltas hoy (vencidas del dia)
    }


def _make_code(session_id: Optional[str]) -> str:
    if session_id and len(session_id) >= 6:
        return session_id[-6:].upper()
    return str(uuid.uuid4())[:6].upper()
