"""
Endpoints de administración — Solo accesibles para usuarios con role='admin'.

Operan directamente contra Supabase (RLS bypaseado por service_role).
"""
import traceback
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException

from app.core.deps import get_current_user, require_role
from app.core.supabase_client import supabase_admin
from app.services import notifications
from app.schemas.admin import (
    AdminUser,
    AdminUserCreate,
    AdminUserUpdate,
    AdminRoute,
    AdminRouteCreate,
    AdminRouteUpdate,
    AdminUnit,
    AdminUnitCreate,
    AdminUnitUpdate,
    AdminDriver,
    AdminDriverCreate,
    AdminDriverUpdate,
)

router = APIRouter(
    prefix="/admin",
    tags=["admin"],
    dependencies=[Depends(require_role("admin"))],
)


# ── Helpers ───────────────────────────────────────────────────────────────────
def _auth_user_map() -> dict[str, dict]:
    """Devuelve {user_id: {email, phone}} desde Supabase Auth (paginado)."""
    mapping: dict[str, dict] = {}
    try:
        page = 1
        while True:
            resp = supabase_admin.auth.admin.list_users(page=page, per_page=200)
            users = getattr(resp, "users", None) or (
                resp if isinstance(resp, list) else []
            )
            if not users:
                break
            for u in users:
                mapping[str(u.id)] = {
                    "email": getattr(u, "email", None),
                    "phone": getattr(u, "phone", None),
                }
            if len(users) < 200:
                break
            page += 1
    except Exception as e:
        print(f"[admin] list_users falló: {e}")
    return mapping


def _auth_user(user_id: str) -> dict:
    try:
        resp = supabase_admin.auth.admin.get_user_by_id(user_id)
        u = getattr(resp, "user", None) or resp
        return {
            "email": getattr(u, "email", None),
            "phone": getattr(u, "phone", None),
        }
    except Exception:
        return {"email": None, "phone": None}


# ── Users ─────────────────────────────────────────────────────────────────────
@router.get("/users", response_model=list[AdminUser])
def list_users():
    res = supabase_admin.table("users").select("id, name, role").execute()
    rows = res.data or []
    auth_map = _auth_user_map()
    return [
        AdminUser(
            id=str(r["id"]),
            name=r.get("name"),
            role=r.get("role", "citizen"),
            email=auth_map.get(str(r["id"]), {}).get("email"),
            phone=auth_map.get(str(r["id"]), {}).get("phone"),
        )
        for r in rows
    ]


@router.post("/users", response_model=AdminUser, status_code=201)
def create_user(body: AdminUserCreate):
    if not body.email and not body.phone:
        raise HTTPException(400, "Se requiere email o teléfono")
    if len(body.password) < 6:
        raise HTTPException(400, "La contraseña debe tener al menos 6 caracteres")

    create_attrs: dict = {"password": body.password}
    if body.email:
        create_attrs["email"] = body.email
        create_attrs["email_confirm"] = True
    else:
        create_attrs["phone"] = body.phone
        create_attrs["phone_confirm"] = True

    try:
        resp = supabase_admin.auth.admin.create_user(create_attrs)
    except Exception as e:
        raise HTTPException(400, f"Error al crear el usuario en Supabase Auth: {e}")

    auth_user = getattr(resp, "user", None)
    if not auth_user:
        raise HTTPException(500, "Supabase Auth no devolvió un usuario válido")

    try:
        supabase_admin.table("users").upsert(
            {"id": str(auth_user.id), "name": body.name, "role": body.role}
        ).execute()
    except Exception as e:
        raise HTTPException(500, f"Error al guardar el usuario en public.users: {e}")

    return AdminUser(
        id=str(auth_user.id),
        name=body.name,
        email=body.email,
        phone=body.phone,
        role=body.role,
    )


@router.patch("/users/{user_id}", response_model=AdminUser)
def update_user(user_id: str, body: AdminUserUpdate):
    public_payload: dict = {}
    if body.name is not None:
        public_payload["name"] = body.name
    if body.role is not None:
        public_payload["role"] = body.role
    if public_payload:
        try:
            supabase_admin.table("users").update(public_payload).eq(
                "id", user_id
            ).execute()
        except Exception as e:
            raise HTTPException(500, f"Error al actualizar public.users: {e}")

    if body.email is not None:
        try:
            supabase_admin.auth.admin.update_user_by_id(
                user_id, {"email": body.email}
            )
        except Exception as e:
            raise HTTPException(500, f"Error al actualizar email: {e}")

    res = (
        supabase_admin.table("users")
        .select("id, name, role")
        .eq("id", user_id)
        .maybe_single()
        .execute()
    )
    if not res.data:
        raise HTTPException(404, "Usuario no encontrado")
    auth = _auth_user(user_id)
    return AdminUser(
        id=str(res.data["id"]),
        name=res.data.get("name"),
        role=res.data.get("role", "citizen"),
        email=auth.get("email"),
        phone=auth.get("phone"),
    )


@router.delete("/users/{user_id}", status_code=204)
def delete_user(user_id: str):
    try:
        supabase_admin.auth.admin.delete_user(user_id)
    except Exception as e:
        raise HTTPException(500, f"Error al borrar el usuario: {e}")
    try:
        supabase_admin.table("users").delete().eq("id", user_id).execute()
    except Exception:
        pass
    return None


# ── Routes ────────────────────────────────────────────────────────────────────
_ROUTE_COLS = "id, name, truck_id, turno, status, current_position_id"


@router.get("/routes", response_model=list[AdminRoute])
def list_routes():
    res = supabase_admin.table("routes").select(_ROUTE_COLS).execute()
    return [AdminRoute(**r) for r in (res.data or [])]


@router.post("/routes", response_model=AdminRoute, status_code=201)
def create_route(body: AdminRouteCreate):
    payload = body.model_dump(exclude_none=True)
    try:
        res = (
            supabase_admin.table("routes")
            .insert(payload)
            .execute()
        )
    except Exception as e:
        raise HTTPException(400, f"Error al crear la ruta: {e}")
    row = (res.data or [None])[0]
    if not row:
        raise HTTPException(500, "Supabase no devolvió la fila creada")
    return AdminRoute(**row)


@router.patch("/routes/{route_id}", response_model=AdminRoute)
def update_route(route_id: str, body: AdminRouteUpdate):
    payload = body.model_dump(exclude_none=True)
    if not payload:
        raise HTTPException(400, "Sin cambios")
        
    try:
        old_res = supabase_admin.table("routes").select("truck_id").eq("id", route_id).maybe_single().execute()
        old_truck_id = old_res.data.get("truck_id") if old_res.data else None
    except Exception:
        old_truck_id = None

    try:
        supabase_admin.table("routes").update(payload).eq("id", route_id).execute()
    except Exception as e:
        raise HTTPException(400, f"Error al actualizar la ruta: {e}")
        
    if body.truck_id is not None and old_truck_id != body.truck_id:
        try:
            notifications.send_to_topic(
                f"topic_{route_id}",
                {
                    "title": "Ruta reasignada 🚛",
                    "body": f"Tu recolección ha sido reasignada a la unidad #{body.truck_id}. El servicio se reanudará en breve.",
                }
            )
        except Exception as e:
            print(f"Error al enviar alerta ciudadana por reasignación: {e}")

    res = (
        supabase_admin.table("routes")
        .select(_ROUTE_COLS)
        .eq("id", route_id)
        .maybe_single()
        .execute()
    )
    if not res.data:
        raise HTTPException(404, "Ruta no encontrada")
    return AdminRoute(**res.data)


@router.delete("/routes/{route_id}", status_code=204)
def delete_route(route_id: str):
    try:
        supabase_admin.table("routes").delete().eq("id", route_id).execute()
    except Exception as e:
        raise HTTPException(400, f"Error al borrar la ruta: {e}")
    return None


# ── Units ─────────────────────────────────────────────────────────────────────
@router.get("/units", response_model=list[AdminUnit])
def list_units():
    res = supabase_admin.table("units").select("id, plate, status").execute()
    return [AdminUnit(**r) for r in (res.data or [])]


@router.post("/units", response_model=AdminUnit, status_code=201)
def create_unit(body: AdminUnitCreate):
    try:
        res = (
            supabase_admin.table("units")
            .insert(body.model_dump(exclude_none=True))
            .execute()
        )
    except Exception as e:
        raise HTTPException(400, f"Error al crear la unidad: {e}")
    row = (res.data or [None])[0]
    if not row:
        raise HTTPException(500, "Supabase no devolvió la fila creada")
    return AdminUnit(**row)


@router.patch("/units/{unit_id}", response_model=AdminUnit)
def update_unit(unit_id: int, body: AdminUnitUpdate):
    payload = body.model_dump(exclude_none=True)
    if not payload:
        raise HTTPException(400, "Sin cambios")
    try:
        supabase_admin.table("units").update(payload).eq("id", unit_id).execute()
    except Exception as e:
        raise HTTPException(400, f"Error al actualizar la unidad: {e}")
        
    # ── ALERTA EN VIVO: Notificar a ciudadanos si la unidad se inhabilita o va a taller ──
    if body.status in ["inactive", "maintenance"]:
        try:
            routes_res = supabase_admin.table("routes").select("id").eq("truck_id", unit_id).execute()
            for route in (routes_res.data or []):
                route_id = route["id"]
                    
                if route_id == "RUTA-01":
                    msg_title = "Aviso de reprogramación ⚠️"
                    msg_body = "El camión de tu ruta ha presentado una falla. El servicio matutino se suspende y tu recolección se retomará en la tarde. Por favor, resguarda tus residuos."
                else:
                    msg_title = "Aviso sobre tu recolección ⚠️"
                    msg_body = "El camión de tu ruta ha sido enviado a taller o inhabilitado. El servicio podría sufrir retrasos. Trabajamos para reasignar la ruta."

                notifications.send_to_topic(
                    f"topic_{route_id}",
                    {
                            "title": msg_title,
                            "body": msg_body,
                    }
                )
        except Exception as e:
            print(f"Error al enviar alerta ciudadana por falla de unidad: {e}")
            
    # ── Salvavidas Anti-Desconexión para el Hackathon ──
    try:
        res = (
            supabase_admin.table("units")
            .select("id, plate, status")
            .eq("id", unit_id)
            .maybe_single()
            .execute()
        )
    except Exception as e:
        print(f"Reintentando lectura por micro-corte de red en Supabase: {e}")
        res = (
            supabase_admin.table("units")
            .select("id, plate, status")
            .eq("id", unit_id)
            .maybe_single()
            .execute()
        )

    if not res.data:
        raise HTTPException(404, "Unidad no encontrada")
    return AdminUnit(**res.data)


@router.delete("/units/{unit_id}", status_code=204)
def delete_unit(unit_id: int):
    try:
        supabase_admin.table("units").delete().eq("id", unit_id).execute()
    except Exception as e:
        raise HTTPException(400, f"Error al borrar la unidad: {e}")
    return None


# ── Drivers ───────────────────────────────────────────────────────────────────
def _hydrate_driver(row: dict, users_map: dict[str, dict], units_map: dict[int, dict]) -> AdminDriver:
    user_id = str(row.get("user_id"))
    unit_id: Optional[int] = row.get("unit_id")
    u = users_map.get(user_id, {})
    unit = units_map.get(unit_id, {}) if unit_id is not None else {}
    return AdminDriver(
        id=str(row["id"]),
        user_id=user_id,
        user_name=u.get("name"),
        user_email=u.get("email"),
        unit_id=unit_id,
        plate=unit.get("plate"),
    )


def _drivers_context() -> tuple[dict[str, dict], dict[int, dict]]:
    users_res = supabase_admin.table("users").select("id, name").execute()
    auth_map = _auth_user_map()
    users_map: dict[str, dict] = {
        str(u["id"]): {
            "name": u.get("name"),
            "email": auth_map.get(str(u["id"]), {}).get("email"),
        }
        for u in (users_res.data or [])
    }
    units_res = supabase_admin.table("units").select("id, plate").execute()
    units_map: dict[int, dict] = {u["id"]: u for u in (units_res.data or [])}
    return users_map, units_map


@router.get("/drivers", response_model=list[AdminDriver])
def list_drivers():
    res = supabase_admin.table("drivers").select("id, user_id, unit_id").execute()
    users_map, units_map = _drivers_context()
    return [_hydrate_driver(r, users_map, units_map) for r in (res.data or [])]


@router.post("/drivers", response_model=AdminDriver, status_code=201)
def create_driver(body: AdminDriverCreate):
    try:
        res = (
            supabase_admin.table("drivers")
            .insert(body.model_dump(exclude_none=True))
            .execute()
        )
    except Exception as e:
        raise HTTPException(400, f"Error al crear el conductor: {e}")
    row = (res.data or [None])[0]
    if not row:
        raise HTTPException(500, "Supabase no devolvió la fila creada")
    users_map, units_map = _drivers_context()
    return _hydrate_driver(row, users_map, units_map)


@router.patch("/drivers/{driver_id}", response_model=AdminDriver)
def update_driver(driver_id: str, body: AdminDriverUpdate):
    payload = body.model_dump(exclude_none=True)
    if not payload:
        raise HTTPException(400, "Sin cambios")
    try:
        supabase_admin.table("drivers").update(payload).eq("id", driver_id).execute()
    except Exception as e:
        raise HTTPException(400, f"Error al actualizar el conductor: {e}")
    res = (
        supabase_admin.table("drivers")
        .select("id, user_id, unit_id")
        .eq("id", driver_id)
        .maybe_single()
        .execute()
    )
    if not res.data:
        raise HTTPException(404, "Conductor no encontrado")
    users_map, units_map = _drivers_context()
    return _hydrate_driver(res.data, users_map, units_map)


@router.delete("/drivers/{driver_id}", status_code=204)
def delete_driver(driver_id: str):
    try:
        supabase_admin.table("drivers").delete().eq("id", driver_id).execute()
    except Exception as e:
        raise HTTPException(400, f"Error al borrar el conductor: {e}")
    return None


# ── Incidents por unidad ──────────────────────────────────────────────────────
_INCIDENT_CATEGORIES = {
    "derrame",
    "dano_propiedad",
    "conducta",
    "no_recoleccion",
    "otro",
}


def _route_for_unit(unit_id: int) -> Optional[str]:
    """Devuelve el route_id que actualmente tiene asignada la unidad
    (vía routes.truck_id), o None si no está asignada a ninguna ruta."""
    try:
        res = (
            supabase_admin.table("routes")
            .select("id")
            .eq("truck_id", unit_id)
            .limit(1)
            .execute()
        )
        rows = res.data or []
        return rows[0]["id"] if rows else None
    except Exception:
        return None


def _driver_for_unit(unit_id: int, users_map: dict[str, dict]) -> Optional[str]:
    """Devuelve el nombre del chofer asignado a la unidad (drivers.unit_id)."""
    try:
        res = (
            supabase_admin.table("drivers")
            .select("user_id")
            .eq("unit_id", unit_id)
            .limit(1)
            .execute()
        )
        rows = res.data or []
        if not rows:
            return None
        user_id = str(rows[0].get("user_id"))
        return (users_map.get(user_id) or {}).get("name")
    except Exception:
        return None


def _serialize_incident(row: dict, route_id: Optional[str], driver_name: Optional[str]) -> dict:
    """Da la forma que espera el cliente Flutter (admin_incident.dart)."""
    return {
        "id": str(row.get("id")),
        "unit_id": row.get("unit_id"),
        "route_id": route_id,
        "type": row.get("type"),
        "description": row.get("description"),
        "driver_name": driver_name,
        "status": row.get("status") or "open",
        "photo_url": row.get("photo_url"),
        "created_at": row.get("created_at") and str(row["created_at"]),
    }


@router.get("/units/{unit_id}/incidents")
def list_unit_incidents(unit_id: int):
    """Reportes ciudadanos asociados a esta unidad, más reciente primero."""
    print(f"[admin] GET /admin/units/{unit_id}/incidents")
    # Verifica que la unidad exista. Usamos limit(1) (no maybe_single)
    # porque maybe_single() lanza APIError cuando no hay filas en supabase-py 2.x.
    try:
        unit_res = (
            supabase_admin.table("units")
            .select("id")
            .eq("id", unit_id)
            .limit(1)
            .execute()
        )
    except Exception as e:
        traceback.print_exc()
        raise HTTPException(500, f"verificar unidad: {type(e).__name__}: {e}")
    if not (unit_res.data or []):
        raise HTTPException(404, f"Unidad {unit_id} no existe en la base de datos")

    try:
        res = (
            supabase_admin.table("incidents")
            .select("id, unit_id, user_id, type, description, status, photo_url, created_at")
            .eq("unit_id", unit_id)
            .order("created_at", desc=True)
            .execute()
        )
        rows = res.data or []
    except Exception as e:
        traceback.print_exc()
        if "Could not find the table" in str(e):
            print("⚠️ ADVERTENCIA: La tabla 'incidents' no existe en Supabase.")
            rows = []
        else:
            raise HTTPException(500, f"listar incidencias: {type(e).__name__}: {e}")
    print(f"[admin] incidents para unit {unit_id}: {len(rows)} filas")

    # Hidratación route_id y driver_name (no debe romper la respuesta).
    try:
        route_id = _route_for_unit(unit_id)
    except Exception as e:
        traceback.print_exc()
        route_id = None

    try:
        users_res = supabase_admin.table("users").select("id, name").execute()
        users_map: dict[str, dict] = {
            str(u["id"]): {"name": u.get("name")} for u in (users_res.data or [])
        }
    except Exception as e:
        traceback.print_exc()
        users_map = {}

    try:
        driver_name = _driver_for_unit(unit_id, users_map)
    except Exception as e:
        traceback.print_exc()
        driver_name = None

    return [_serialize_incident(r, route_id, driver_name) for r in rows]


@router.post("/units/{unit_id}/incidents", status_code=201)
def create_unit_incident(
    unit_id: int,
    body: dict,
    current_user: dict = Depends(get_current_user),
):
    """Crea una incidencia para esta unidad. El admin queda como reporter."""
    category = (body.get("type") or body.get("category") or "").strip()
    description = (body.get("description") or "").strip()

    if category not in _INCIDENT_CATEGORIES:
        raise HTTPException(
            400,
            f"Categoría inválida. Use una de: {sorted(_INCIDENT_CATEGORIES)}",
        )
    if len(description) < 3:
        # La tabla requiere description NOT NULL y un mínimo razonable.
        description = description or category

    # La unidad debe existir
    try:
        unit_res = (
            supabase_admin.table("units")
            .select("id")
            .eq("id", unit_id)
            .limit(1)
            .execute()
        )
    except Exception as e:
        raise HTTPException(500, f"Error al verificar la unidad: {e}")
    if not (unit_res.data or []):
        raise HTTPException(404, f"Unidad {unit_id} no existe en la base de datos")

    payload = {
        "user_id": current_user["user_id"],
        "unit_id": unit_id,
        "type": category,
        "description": description,
    }
    try:
        res = supabase_admin.table("incidents").insert(payload).execute()
    except Exception as e:
        raise HTTPException(500, f"Error al crear la incidencia: {e}")

    row = (res.data or [None])[0]
    if not row:
        raise HTTPException(500, "Supabase no devolvió la fila creada")

    route_id = _route_for_unit(unit_id)
    users_res = supabase_admin.table("users").select("id, name").execute()
    users_map: dict[str, dict] = {
        str(u["id"]): {"name": u.get("name")} for u in (users_res.data or [])
    }
    driver_name = _driver_for_unit(unit_id, users_map)
    return _serialize_incident(row, route_id, driver_name)
