"""
Capa de Datos — Supabase PostgreSQL con caché
"""
from datetime import datetime, timedelta
from typing import Optional

from app.db.database import get_db
from app.domain.entities.ruta import (
    Coordenada, EstadoCamion, ETAResult,
    NotificationPreferences, PuntoRuta, Ruta, TruckStatus,
)


class SupabaseRutaRepository:

    def __init__(self):
        self.db = get_db()

    # ── Rutas y puntos ────────────────────────────────────────────────

    def obtener_ruta(self, route_id: str) -> Optional[Ruta]:
        try:
            ruta_data = self.db.table("rutas").select("*").eq("id", route_id).execute()
            if not ruta_data.data:
                return None

            ruta_row = ruta_data.data[0]
            puntos_data = self.db.table("puntos_ruta").select("*").eq("ruta_id", route_id).order("orden").execute()

            puntos = [
                PuntoRuta(
                    orden=p["orden"],
                    nombre=p["nombre"],
                    coordenada=Coordenada(p["lat"], p["lng"]),
                    tiempo_estimado_min=p["tiempo_estimado_min"],
                )
                for p in puntos_data.data
            ]

            return Ruta(
                id=ruta_row["id"],
                nombre=ruta_row["nombre"],
                puntos=puntos,
                turno=ruta_row["turno"]
            )
        except Exception as e:
            print(f"Error obtener_ruta: {e}")
            return None

    def obtener_ruta_por_address(self, address_id: int) -> Optional[Ruta]:
        try:
            addr_data = self.db.table("addresses").select("route_id").eq("id", address_id).execute()
            if not addr_data.data:
                return None
            return self.obtener_ruta(addr_data.data[0]["route_id"])
        except Exception as e:
            print(f"Error obtener_ruta_por_address: {e}")
            return None

    # ── truck_status ──────────────────────────────────────────

    def obtener_truck_status(self, route_id: str) -> Optional[TruckStatus]:
        try:
            ts_data = self.db.table("truck_status").select("*").eq("route_id", route_id).execute()
            if not ts_data.data:
                return None

            row = ts_data.data[0]
            return TruckStatus(
                route_id=row["route_id"],
                current_position_id=row["current_position_id"],
                last_update=datetime.fromisoformat(row["last_update"].replace("Z", "+00:00")),
                status=EstadoCamion(row["status"]),
            )
        except Exception as e:
            print(f"Error obtener_truck_status: {e}")
            return None

    def guardar_truck_status(self, ts: TruckStatus) -> None:
        try:
            self.db.table("truck_status").upsert({
                "route_id": ts.route_id,
                "current_position_id": ts.current_position_id,
                "last_update": ts.last_update.isoformat(),
                "status": ts.status.value,
            }).execute()

            # Invalidar caché
            from app.core.cache import invalidate_route_cache
            import asyncio
            asyncio.create_task(invalidate_route_cache(ts.route_id))
        except Exception as e:
            print(f"Error guardar_truck_status: {e}")

    # ── Preferencias de notificación ─────────────────────────────────

    def obtener_preferencias(self, user_id: str) -> NotificationPreferences:
        try:
            prefs_data = self.db.table("notification_preferences").select("*").eq("user_id", user_id).execute()
            if not prefs_data.data:
                return NotificationPreferences(user_id=user_id)

            row = prefs_data.data[0]
            return NotificationPreferences(
                user_id=user_id,
                notify_proximity=row["notify_proximity"],
                notify_breakdown=row["notify_breakdown"],
                notify_delay=row["notify_delay"],
                notify_route_start=row["notify_route_start"],
            )
        except Exception as e:
            print(f"Error obtener_preferencias: {e}")
            return NotificationPreferences(user_id=user_id)

    def obtener_usuarios_por_ruta(self, route_id: str) -> list[dict]:
        try:
            users_data = self.db.table("addresses").select("id, user_id").eq("route_id", route_id).execute()
            return [{"address_id": u["id"], "user_id": u["user_id"]} for u in users_data.data]
        except Exception as e:
            print(f"Error obtener_usuarios_por_ruta: {e}")
            return []

    # ── Templates de notificación ─────────────────────────────────────

    def obtener_template(self, trigger_event: str) -> Optional[dict]:
        try:
            template_data = self.db.table("notification_templates").select("*").eq("trigger_event", trigger_event).execute()
            if not template_data.data:
                return None
            return template_data.data[0]
        except Exception as e:
            print(f"Error obtener_template: {e}")
            return None

    # ── ETA calculado ────────────────────────────────────────────────

    def calcular_eta(self, address_id: int) -> Optional[ETAResult]:
        ruta = self.obtener_ruta_por_address(address_id)
        if not ruta:
            return None

        ts = self.obtener_truck_status(ruta.id)
        if not ts:
            return ETAResult(
                address_id=address_id, route_id=ruta.id,
                status="SIN_INICIAR", eta_minutos=None,
                ventana_inicio=None, ventana_fin=None,
                mensaje="El camión aún no ha iniciado su ruta.",
            )

        pos = ts.current_position_id
        puntos = {p.orden: p for p in ruta.puntos}
        ultimo = ruta.puntos[-1]
        actual = puntos.get(pos, ruta.puntos[0])

        eta_min = max(0, ultimo.tiempo_estimado_min - actual.tiempo_estimado_min)

        ahora = datetime.now()
        llegada = ahora + timedelta(minutes=eta_min)
        v_ini = (llegada - timedelta(minutes=7)).strftime("%I:%M %p").lstrip("0")
        v_fin = (llegada + timedelta(minutes=7)).strftime("%I:%M %p").lstrip("0")

        if ts.status == EstadoCamion.APROXIMANDOSE:
            msg = f"El camión llegará a tu zona entre las {v_ini} y {v_fin}."
        elif ts.status in (EstadoCamion.AVERIADA, EstadoCamion.RETRASADA):
            msg = "El camión reportó una incidencia. Te notificaremos cuando se reanude."
            v_ini = v_fin = None
        else:
            msg = f"El camión está en camino. Llegada estimada: {v_ini} – {v_fin}."

        return ETAResult(
            address_id=address_id,
            route_id=ruta.id,
            status=ts.status.value,
            eta_minutos=eta_min,
            ventana_inicio=v_ini,
            ventana_fin=v_fin,
            mensaje=msg,
        )

    def guardar_notificacion(self, tipo: str, route_id: str,
                              address_id: int, mensaje: str,
                              eta_minutos: Optional[int]) -> None:
        try:
            self.db.table("notificaciones").insert({
                "tipo": tipo,
                "ruta_id": route_id,
                "address_id": address_id,
                "mensaje": mensaje,
                "eta_minutos": eta_minutos,
                "creada_en": datetime.utcnow().isoformat(),
            }).execute()
        except Exception as e:
            print(f"Error guardar_notificacion: {e}")


# Alias para compatibilidad
SQLiteRutaRepository = SupabaseRutaRepository
