import re

from fastapi import APIRouter, HTTPException, Request
from pydantic import BaseModel, EmailStr, Field, field_validator
from sqlalchemy import text

from app.core.config import get_settings
from app.core.db import db_session
from app.core.security import encrypt_text, keyed_hash, normalize_email
from app.services.turnstile import verify_turnstile


router = APIRouter(prefix="/portal/contacto", tags=["contacto-publico"])
TOPICS = {"TRAMITES", "PERSONAS", "PRO", "ENTIDADES", "INTEGRACIONES", "OTRO"}


class ContactIn(BaseModel):
    tema: str = Field(max_length=30)
    nombre: str = Field(min_length=2, max_length=150)
    email: EmailStr
    telefono: str | None = Field(default=None, max_length=30)
    organizacion: str | None = Field(default=None, max_length=180)
    mensaje: str = Field(min_length=10, max_length=3000)
    captcha_token: str = Field(min_length=10, max_length=3000)
    website: str | None = Field(default=None, max_length=200)

    @field_validator("tema")
    @classmethod
    def validate_topic(cls, value: str) -> str:
        normalized = value.strip().upper()
        if normalized not in TOPICS:
            raise ValueError("Selecciona un motivo de contacto válido")
        return normalized


def _ip(request: Request) -> str | None:
    forwarded = request.headers.get("x-forwarded-for", "")
    return forwarded.split(",")[0].strip() if forwarded else (request.client.host if request.client else None)


@router.post("", status_code=201)
def create_contact(payload: ContactIn, request: Request):
    if payload.website:
        return {"ok": True}
    remote_ip = _ip(request)
    if not verify_turnstile(payload.captcha_token, remote_ip):
        raise HTTPException(422, "No fue posible validar la verificación de seguridad")
    phone = (payload.telefono or "").strip()
    if phone and not re.fullmatch(r"[+0-9 ()-]{7,30}", phone):
        raise HTTPException(422, "Ingresa un teléfono válido")
    ip_hash = keyed_hash(remote_ip, get_settings().access_token_hmac_key) if remote_ip else None
    with db_session() as db:
        recent = db.execute(text("""
          SELECT COUNT(*) FROM contacto_solicitudes
          WHERE ip_hash=:ip AND creado_en>DATE_SUB(UTC_TIMESTAMP(6),INTERVAL 15 MINUTE)
        """), {"ip": ip_hash}).scalar() if ip_hash else 0
        if int(recent or 0) >= 5:
            raise HTTPException(429, "Alcanzaste el máximo temporal de mensajes. Intenta más tarde")
        reference = db.execute(text("""
          INSERT INTO contacto_solicitudes
            (tema,nombre_cifrado,email_cifrado,telefono_cifrado,organizacion_cifrada,
             mensaje_cifrado,ip_hash,estado)
          VALUES (:topic,:name,:email,:phone,:organization,:message,:ip,'NUEVO')
        """), {
            "topic": payload.tema, "name": encrypt_text(payload.nombre.strip()),
            "email": encrypt_text(normalize_email(str(payload.email))),
            "phone": encrypt_text(phone) if phone else None,
            "organization": encrypt_text(payload.organizacion.strip()) if payload.organizacion else None,
            "message": encrypt_text(payload.mensaje.strip()), "ip": ip_hash,
        }).lastrowid
    return {"ok": True, "referencia": f"CT-{int(reference):08d}"}
