"""Rutas para gestión de códigos de invitación."""

import logging
from typing import List, Optional

from core.database import get_core_db
from core.security import get_current_user, validate_access_to_resource
from fastapi import APIRouter, Depends, Query
from fastapi.security import HTTPBearer
from sqlalchemy.orm import Session

from .dto import (
    ConsumeInviteCodeResponseDTO,
    CreateInviteCodeDTO,
    InviteCodeResponseDTO,
    ValidateInviteCodeResponseDTO,
)
from .service import InviteCodeService

router = APIRouter(prefix="/invite-codes", tags=["Invite Codes"])
_bearer = HTTPBearer()

logger = logging.getLogger(__name__)


@router.post("", response_model=InviteCodeResponseDTO, status_code=201)
async def create_invite_code(
    data: CreateInviteCodeDTO,
    db: Session = Depends(get_core_db),
    current_user: dict = Depends(get_current_user),
    credentials=Depends(_bearer),
):
    """
    Genera un código de invitación reutilizable.
    Requiere permiso user.create sobre la empresa (o ser admin del tenant).
    """
    company_id = data.company_id
    if company_id is not None:
        validate_access_to_resource(
            db,
            company_id,
            current_user,
            required_permissions=["user.create"],
        )
    else:
        # Invitación a nivel tenant: solo roles admin del tenant
        roles = set(current_user.get("roles") or [])
        if "admin" not in roles and "hub_admin" not in roles:
            from fastapi import HTTPException
            raise HTTPException(
                status_code=403,
                detail="Se requiere rol admin para crear invitaciones de nivel tenant",
            )

    tenant_slug: str = current_user.get("tenant_slug") or ""
    created_by: str = current_user.get("sub") or ""

    service = InviteCodeService(db)
    return await service.create_code(
        data=data,
        created_by=created_by,
        tenant_slug=tenant_slug,
        user_access_token=credentials.credentials,
    )


@router.get("", response_model=List[InviteCodeResponseDTO])
def list_invite_codes(
    company_id: Optional[int] = Query(None, description="Filtrar por empresa"),
    include_inactive: bool = Query(False, description="Incluir códigos inactivos/agotados"),
    db: Session = Depends(get_core_db),
    current_user: dict = Depends(get_current_user),
):
    """
    Lista los códigos de invitación del tenant.
    Filtra opcionalmente por empresa.
    """
    if company_id is not None:
        validate_access_to_resource(
            db,
            company_id,
            current_user,
            required_permissions=["user.create"],
        )
    else:
        roles = set(current_user.get("roles") or [])
        if "admin" not in roles and "hub_admin" not in roles:
            from fastapi import HTTPException
            raise HTTPException(status_code=403, detail="Se requiere rol admin")

    tenant_slug: str = current_user.get("tenant_slug") or ""
    service = InviteCodeService(db)
    return service.list_codes(
        tenant_slug=tenant_slug,
        company_id=company_id,
        include_inactive=include_inactive,
    )


@router.delete("/{code}", status_code=204)
def revoke_invite_code(
    code: str,
    db: Session = Depends(get_core_db),
    current_user: dict = Depends(get_current_user),
):
    """Revoca (desactiva) un código de invitación."""
    roles = set(current_user.get("roles") or [])
    if "admin" not in roles and "hub_admin" not in roles:
        from fastapi import HTTPException
        raise HTTPException(status_code=403, detail="Se requiere rol admin")

    tenant_slug: str = current_user.get("tenant_slug") or ""
    service = InviteCodeService(db)
    service.revoke_code(code=code, tenant_slug=tenant_slug)


@router.get("/validate/{code}", response_model=ValidateInviteCodeResponseDTO)
def validate_invite_code(
    code: str,
    db: Session = Depends(get_core_db),
):
    """
    Valida un código de invitación sin consumirlo.
    Endpoint público — no requiere autenticación.
    """
    service = InviteCodeService(db)
    return service.validate(code=code)


@router.post("/consume/{code}", response_model=ConsumeInviteCodeResponseDTO)
def consume_invite_code(
    code: str,
    db: Session = Depends(get_core_db),
    current_user: dict = Depends(get_current_user),
):
    """
    Canjea el código: incrementa el contador de usos y crea la relación
    UserTenant (usuario ↔ empresa) si el código tiene company_id definido.
    Requiere autenticación.
    """
    keycloak_user_id: str = current_user.get("sub") or ""
    tenant_id: int = current_user.get("tenant_id") or 0

    service = InviteCodeService(db)
    return service.consume(
        code=code,
        keycloak_user_id=keycloak_user_id,
        tenant_id=tenant_id,
    )
