"""Rotas VM123 — Spec 027 Fase 3."""

from __future__ import annotations

from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel, Field

from app import auth
from app.permissions import (
    can_access_foss_admin,
    can_create_foss_order,
    can_manage_users,
    can_openpanel_autologin,
    can_read_billing,
)
from app.platform_role_catalog import catalog_export
from app.vm123 import foss_client, odoo_client, openpanel_client, provision, provision_store
from app.vm123.role_map import PROVISIONABLE_DESK_ROLES

router = APIRouter(prefix="/api/v1/vm123", tags=["vm123"])


class FossOrderBody(BaseModel):
    client_id: int | None = None
    domain: str | None = None
    product_id: int | None = None
    note: str | None = None


class ProvisionUserBody(BaseModel):
    desk_username: str = Field(min_length=3)
    desk_role: str | None = None


@router.get("/platform/catalog")
def platform_role_catalog(user: auth.DeskUser = Depends(auth.get_current_user)):
    """Catálogo mestre função → serviços (padrão Odoo res.groups na plataforma DevOps)."""
    return catalog_export()


@router.get("/health")
def vm123_health(user: auth.DeskUser = Depends(auth.get_current_user)):
    if user.role not in ("super_admin", "devops", "developer"):
        raise HTTPException(403, "permissão insuficiente")
    out: dict = {"odoo": {"configured": odoo_client._configured()}}
    try:
        out["odoo"]["role_model_sales_admin"] = odoo_client.list_role_model("sales_admin")
    except Exception as exc:
        out["odoo"]["error"] = str(exc)
    out["foss"] = {"configured": foss_client._configured()}
    out["openpanel"] = openpanel_client.health()
    return out


@router.get("/odoo/role-model/{role}")
def odoo_role_model(role: str, user: auth.DeskUser = Depends(auth.get_current_user)):
    if not can_manage_users(user.role) and user.role not in ("devops", "developer"):
        raise HTTPException(403, "permissão insuficiente")
    try:
        return odoo_client.list_role_model(role)
    except odoo_client.OdooConfigError as exc:
        raise HTTPException(503, str(exc)) from exc


@router.get("/odoo/partner")
def odoo_partner(email: str = Query(..., min_length=3), user: auth.DeskUser = Depends(auth.get_current_user)):
    if not can_read_billing(user.role):
        raise HTTPException(403, "permissão insuficiente")
    try:
        partner = odoo_client.find_partner_by_email(email)
    except odoo_client.OdooConfigError as exc:
        raise HTTPException(503, str(exc)) from exc
    if not partner:
        raise HTTPException(404, "parceiro não encontrado")
    return {
        "partner": partner,
        "login_url": odoo_client.ODOO_PUBLIC_URL,
    }


@router.get("/foss/client/{domain}")
def foss_client_by_domain(domain: str, user: auth.DeskUser = Depends(auth.get_current_user)):
    if not can_read_billing(user.role):
        raise HTTPException(403, "permissão insuficiente")
    try:
        client_row = foss_client.find_client_by_domain(domain)
    except foss_client.FossConfigError as exc:
        raise HTTPException(503, str(exc)) from exc
    if not client_row:
        raise HTTPException(404, "cliente FOSS não encontrado")
    return {
        "client": client_row,
        "admin_url": foss_client.FOSS_PUBLIC_ADMIN,
        "can_order": can_create_foss_order(user.role),
        "can_admin": can_access_foss_admin(user.role),
    }


@router.post("/foss/order")
def foss_create_order(body: FossOrderBody, user: auth.DeskUser = Depends(auth.get_current_user)):
    if not can_create_foss_order(user.role):
        raise HTTPException(403, "permissão insuficiente")
    if not body.client_id and not body.domain:
        raise HTTPException(400, "informe client_id ou domain")
    # MVP: delegar criação real à UI FOSS até mapear product_id
    return {
        "accepted": True,
        "message": "Pedido registado — criação FOSS via Admin até product_id estar mapeado",
        "payload": body.model_dump(),
        "foss_admin": foss_client.FOSS_PUBLIC_ADMIN,
    }


@router.post("/openpanel/autologin/{username}")
def openpanel_autologin(username: str, user: auth.DeskUser = Depends(auth.get_current_user)):
    if not can_openpanel_autologin(user.role):
        raise HTTPException(403, "permissão insuficiente")
    return openpanel_client.autologin_payload(username)


@router.get("/identity/{desk_username}")
def get_identity_map(desk_username: str, user: auth.DeskUser = Depends(auth.get_current_user)):
    if not can_manage_users(user.role):
        raise HTTPException(403, "permissão insuficiente")
    with auth.db() as conn:
        row = provision_store.get_map(conn, desk_username)
    if not row:
        raise HTTPException(404, "sem registo VM123")
    return row


@router.post("/provision/user")
def provision_user(body: ProvisionUserBody, user: auth.DeskUser = Depends(auth.get_current_user)):
    if not can_manage_users(user.role):
        raise HTTPException(403, "permissão insuficiente")
    with auth.db() as conn:
        urow = conn.execute(
            "SELECT username, role, display_name, email FROM desk_users WHERE username = ?",
            (body.desk_username.strip().lower(),),
        ).fetchone()
        if not urow:
            raise HTTPException(404, "utilizador Desk não encontrado")
        role = body.desk_role or urow["role"]
        if role not in PROVISIONABLE_DESK_ROLES:
            raise HTTPException(400, f"role {role} não provisionável")
        email = urow["email"] or urow["username"]
        result = provision.provision_desk_user(
            conn,
            desk_username=urow["username"],
            desk_role=role,
            display_name=urow["display_name"] or email,
            email=email,
        )
    return result


@router.get("/links/client")
def client_deep_links(
    domain: str = Query(..., min_length=3),
    email: str = "",
    user: auth.DeskUser = Depends(auth.get_current_user),
):
    """Deep-links drawer «Conta do cliente» — Spec 023 + 027."""
    if not can_read_billing(user.role):
        raise HTTPException(403, "permissão insuficiente")
    links = {
        "domain": domain.strip().lower(),
        "foss": {"url": foss_client.FOSS_PUBLIC_ADMIN, "label": "FOSSBilling Admin"},
        "odoo": {"url": odoo_client.ODOO_PUBLIC_URL, "label": "Odoo ligbox"},
        "openpanel": {"url": openpanel_client.OPENADMIN_URL, "label": "OpenAdmin"},
    }
    out: dict = {"links": links, "role": user.role}
    if foss_client._configured():
        try:
            fc = foss_client.find_client_by_domain(domain)
            if fc:
                out["foss"]["client_id"] = fc.get("id")
                out["foss"]["client_email"] = fc.get("email")
        except Exception:
            pass
    bill_email = (email or "").strip()
    if bill_email and odoo_client._configured():
        try:
            partner = odoo_client.find_partner_by_email(bill_email)
            if partner:
                out["odoo"]["partner_id"] = partner.get("id")
                out["odoo"]["partner_name"] = partner.get("name")
        except Exception:
            pass
    out["permissions"] = {
        "can_order": can_create_foss_order(user.role),
        "can_foss_admin": can_access_foss_admin(user.role),
        "can_openpanel_autologin": can_openpanel_autologin(user.role),
    }
    return out
