"""Catálogo de acções Desk + links externos + ranking técnicos — Spec 010 Fase C/F."""

from __future__ import annotations

import os
import sqlite3
from collections import defaultdict
from datetime import datetime, timedelta, timezone
from typing import Any

FUNNEL_RANK_BY_STAGE = {
    "started": 1,
    "domain_validated": 2,
    "dns_applied": 3,
    "account_created": 4,
    "infra_synced": 5,
    "completed": 6,
    "failed": 99,
}

DESK_ACTIONS = {
    "dns.revalidate": {
        "label": "Revalidar DNS",
        "min_rank": 3,
        "method": "GET",
        "path": "/onboarding/dns/verify/{domain}",
    },
    "dns.reapply": {
        "label": "Reaplicar DNS Cloudflare",
        "min_rank": 3,
        "method": "POST",
        "path": "/onboarding/dns/cloudflare/apply",
        "body": lambda domain, _payload: {"domain": domain},
    },
    "account.retry_sync": {
        "label": "Reverificar infra/conta",
        "min_rank": 4,
        "method": "GET",
        "path": "/onboarding/infrastructure/status/{domain}",
    },
    "infra.resync": {
        "label": "Resync infra (Traefik/cert)",
        "min_rank": 5,
        "method": "POST",
        "path": "/onboarding/infrastructure/provision",
        "body": lambda domain, _payload: {"domain": domain},
    },
}

ABORT_ACTION = "onboarding.abort"
MARK_STEP_ACTION = "onboarding.mark_step_complete"

PROXMOX_URL = os.getenv("DESK_LINK_PROXMOX", "https://proxmox.itecnologys.com")
TRAEFIK_URL = os.getenv("DESK_LINK_TRAEFIK", "https://traefik.itecnologys.com/dashboard/")
CARBONIO_ADMIN = os.getenv("DESK_LINK_CARBONIO", "https://mail.ibytera.com/admin")


def _now() -> str:
    return datetime.now(timezone.utc).isoformat()


def funnel_rank(stage: str | None) -> int:
    return FUNNEL_RANK_BY_STAGE.get(stage or "", 0)


def list_actions_for_session(funnel_stage: str | None, is_assisting: bool, role: str) -> list[dict]:
    rank = funnel_rank(funnel_stage)
    out = []
    for action_id, spec in DESK_ACTIONS.items():
        if rank < spec["min_rank"]:
            continue
        if not is_assisting and action_id not in ("dns.revalidate", "account.retry_sync"):
            continue
        out.append({"id": action_id, "label": spec["label"], "requires_assisting": action_id not in ("dns.revalidate", "account.retry_sync")})
    if is_assisting and role in ("super_admin", "ops_lead", "technician"):
        out.append({"id": MARK_STEP_ACTION, "label": "Marcar passo concluído", "requires_assisting": True})
    if role in ("super_admin", "ops_lead"):
        out.append({"id": ABORT_ACTION, "label": "Abortar onboarding", "requires_assisting": False, "danger": True})
    return out


def build_vm112_request(action_id: str, domain: str, ticket_payload: dict | None) -> tuple[str, str, dict | None]:
    if action_id not in DESK_ACTIONS:
        raise ValueError(f"acção desconhecida: {action_id}")
    spec = DESK_ACTIONS[action_id]
    path = spec["path"].format(domain=domain)
    body = None
    if "body" in spec:
        body = spec["body"](domain, ticket_payload or {})
    return spec["method"], path, body


def external_links(domain: str | None) -> list[dict[str, str]]:
    dom = (domain or "").strip().lower()
    links = [
        {"id": "proxmox", "label": "Proxmox", "url": PROXMOX_URL, "system": "proxmox"},
        {"id": "traefik", "label": "Traefik", "url": TRAEFIK_URL, "system": "traefik"},
        {"id": "carbonio", "label": "Carbonio Admin", "url": CARBONIO_ADMIN, "system": "carbonio"},
    ]
    if dom:
        links.append({
            "id": "webmail",
            "label": f"Webmail {dom}",
            "url": f"https://mail.{dom}/",
            "system": "carbonio",
        })
        links.append({
            "id": "cloudflare",
            "label": f"Cloudflare DNS ({dom})",
            "url": f"https://dash.cloudflare.com/?to=/:{dom}/dns",
            "system": "cloudflare",
        })
    return links


def technician_ranking(conn: sqlite3.Connection, window_days: int = 30) -> list[dict[str, Any]]:
    cutoff = (datetime.now(timezone.utc) - timedelta(days=window_days)).isoformat()
    rows = conn.execute(
        """
        SELECT aa.actor, aa.action, aa.created_at, s.initiated_by_user
        FROM assist_actions aa
        LEFT JOIN assist_sessions s ON s.id = aa.assist_session_id
        WHERE aa.created_at >= ?
        ORDER BY aa.id DESC
        """,
        (cutoff,),
    ).fetchall()

    skip_actors = frozenset({"client", "system", "worker", ""})
    stats: dict[str, dict[str, int]] = defaultdict(
        lambda: {"escalados": 0, "assumidos": 0, "handoffs": 0, "acoes": 0, "movimentos": 0}
    )

    for row in rows:
        actor = (row["actor"] or "").strip()
        if actor in skip_actors:
            continue
        action = row["action"] or ""
        bucket = stats[actor]
        bucket["movimentos"] += 1
        if action == "escalate":
            bucket["escalados"] += 1
        elif action == "takeover":
            bucket["assumidos"] += 1
        elif action == "handoff":
            bucket["handoffs"] += 1
        elif action.startswith("action."):
            bucket["acoes"] += 1

    assigned = conn.execute(
        """
        SELECT assigned_to, COUNT(*) c
        FROM tickets
        WHERE assigned_to IS NOT NULL AND assigned_at >= ?
        GROUP BY assigned_to
        """,
        (cutoff,),
    ).fetchall()
    for row in assigned:
        user = (row["assigned_to"] or "").strip()
        if user:
            stats[user]["atribuidos"] = int(row["c"])

    ranking = []
    for username, data in stats.items():
        assumidos = data["assumidos"]
        escalados = data["escalados"]
        handoffs = data["handoffs"]
        acoes = data["acoes"]
        movimentos = data["movimentos"]
        atribuidos = data.get("atribuidos", 0)
        score = assumidos * 5 + escalados * 2 + acoes * 3 + handoffs + atribuidos
        ranking.append({
            "username": username,
            "assumidos": assumidos,
            "escalados": escalados,
            "handoffs": handoffs,
            "acoes": acoes,
            "movimentos": movimentos,
            "atribuidos": atribuidos,
            "score": score,
        })
    ranking.sort(key=lambda x: (x["score"], x["assumidos"], x["movimentos"]), reverse=True)
    return ranking
