import secrets
import json
import logging
import uuid
from datetime import datetime, timedelta
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from app.config import settings
from app.models.database import get_db
from app.models.client import Client
from app.models.audit import AuditLog
from app.security.auth import hash_api_key, create_purpose_token
from app.security.dependencies import verify_admin
from app.services.email import send_email
from app.schemas.api import ClientCreate, ClientResponse, ClientCreateResponse, AuditLogResponse, PackageGrant

router = APIRouter(tags=["admin"])
logger = logging.getLogger(__name__)


def _send_invite(client: Client) -> None:
    token = create_purpose_token(client.id, "pwd_set", expire_hours=72)
    link = f"https://{settings.PRIMARY_HOST or 'mt2mx.cl'}/cuenta?token={token}"
    try:
        send_email(
            to=client.email,
            subject="MT2MX — Activa tu cuenta",
            body=(
                f"Hola {client.name},\n\n"
                "Tu acceso a MT2MX ya está listo. Define tu contraseña para entrar a tu panel "
                f"(válido por 72 horas):\n{link}\n\n"
                "Desde tu panel vas a poder ver tu API key, tu consumo, y probar conversiones.\n"
            ),
        )
    except Exception as e:
        logger.error(f"Fallo al enviar correo de invitación a {client.email}: {e}", exc_info=True)


@router.post("/admin/clients", response_model=ClientCreateResponse)
def create_client(
    body: ClientCreate,
    db: Session = Depends(get_db),
    _: bool = Depends(verify_admin),
):
    api_key = "sk_live_" + secrets.token_urlsafe(32)
    client = Client(
        id=str(uuid.uuid4()),
        name=body.name,
        email=body.email,
        api_key_hash=hash_api_key(api_key),
        api_key_preview=api_key[-8:],
        rate_limit_per_min=body.rate_limit_per_min,
        scopes=json.dumps(body.scopes),
        active=True,
    )
    db.add(client)
    db.commit()
    db.refresh(client)

    _send_invite(client)

    return ClientCreateResponse(
        **ClientResponse.model_validate(client).model_dump(),
        api_key=api_key,
    )


@router.get("/admin/clients", response_model=list[ClientResponse])
def list_clients(
    include_deleted: bool = False,
    db: Session = Depends(get_db),
    _: bool = Depends(verify_admin),
):
    query = db.query(Client)
    if not include_deleted:
        query = query.filter(Client.deleted_at == None)  # noqa: E711
    return query.all()


@router.get("/admin/clients/{client_id}/logs", response_model=list[AuditLogResponse])
def get_client_logs(
    client_id: str,
    page: int = 1,
    limit: int = 50,
    db: Session = Depends(get_db),
    _: bool = Depends(verify_admin),
):
    client = db.query(Client).filter(Client.id == client_id).first()
    if not client:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Cliente no encontrado")

    offset = (page - 1) * limit
    logs = (
        db.query(AuditLog)
        .filter(AuditLog.client_id == client_id)
        .order_by(AuditLog.timestamp.desc())
        .offset(offset)
        .limit(limit)
        .all()
    )
    return logs


@router.post("/admin/clients/{client_id}/package", response_model=ClientResponse)
def grant_package(
    client_id: str,
    body: PackageGrant,
    db: Session = Depends(get_db),
    _: bool = Depends(verify_admin),
):
    client = db.query(Client).filter(
        Client.id == client_id,
        Client.deleted_at == None,  # noqa: E711
    ).first()
    if not client:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Cliente no encontrado")

    if body.credits <= 0 or body.days_valid <= 0:
        raise HTTPException(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
            detail="credits y days_valid deben ser mayores a 0",
        )

    client.credits_remaining = (client.credits_remaining or 0) + body.credits
    client.credits_expire_at = datetime.utcnow() + timedelta(days=body.days_valid)
    db.commit()
    db.refresh(client)
    return client


@router.post("/admin/clients/{client_id}/regenerate-key", response_model=ClientCreateResponse)
def regenerate_key(
    client_id: str,
    db: Session = Depends(get_db),
    _: bool = Depends(verify_admin),
):
    client = db.query(Client).filter(
        Client.id == client_id,
        Client.deleted_at == None,  # noqa: E711
    ).first()
    if not client:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Cliente no encontrado")

    api_key = "sk_live_" + secrets.token_urlsafe(32)
    client.api_key_hash = hash_api_key(api_key)
    client.api_key_preview = api_key[-8:]
    db.commit()
    db.refresh(client)

    return ClientCreateResponse(
        **ClientResponse.model_validate(client).model_dump(),
        api_key=api_key,
    )


@router.post("/admin/clients/{client_id}/send-invite", status_code=status.HTTP_204_NO_CONTENT)
def resend_invite(
    client_id: str,
    db: Session = Depends(get_db),
    _: bool = Depends(verify_admin),
):
    client = db.query(Client).filter(
        Client.id == client_id,
        Client.deleted_at == None,  # noqa: E711
    ).first()
    if not client:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Cliente no encontrado")
    _send_invite(client)


@router.post("/admin/clients/{client_id}/reactivate", response_model=ClientResponse)
def reactivate_client(
    client_id: str,
    db: Session = Depends(get_db),
    _: bool = Depends(verify_admin),
):
    client = db.query(Client).filter(Client.id == client_id).first()
    if not client:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Cliente no encontrado")

    client.active = True
    client.deleted_at = None
    db.commit()
    db.refresh(client)
    return client


@router.delete("/admin/clients/{client_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_client(
    client_id: str,
    db: Session = Depends(get_db),
    _: bool = Depends(verify_admin),
):
    client = db.query(Client).filter(
        Client.id == client_id,
        Client.deleted_at == None,  # noqa: E711
    ).first()
    if not client:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Cliente no encontrado")

    client.active = False
    client.deleted_at = datetime.utcnow()
    db.commit()
