"""Orquestração activação cliente — Spec 043 Fases 2–5."""

from __future__ import annotations

import json
import logging
import secrets
from datetime import datetime, timezone
from typing import Any

from app import billing_store
from app.activation_mapper import (
    ACTIVATABLE_STATES,
    build_activation_preview,
    map_foss_client,
    map_odoo_partner,
    map_openpanel,
    map_wizard_mail_bundle,
    normalize_company_profile,
    resolve_plan_config,
)
from app.vm123 import foss_client, odoo_client, openpanel_client, wizard_client

log = logging.getLogger(__name__)


class ActivationError(RuntimeError):
    pass


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


def activate_billing_account(
    conn,
    account_id: int,
    *,
    plan_code: str | None = None,
    config: dict[str, Any] | None = None,
    provision_mail: bool = True,
    notes: str | None = None,
    activated_by: str,
    skip_openpanel: bool = False,
) -> dict[str, Any]:
    """Sequência FOSS → OpenPanel → Odoo → wizard mail-bundle."""
    acc = billing_store.get_account(conn, account_id, mask=False)
    if not acc:
        raise ActivationError("conta não encontrada")
    if acc.get("recurrence_active") or acc.get("billing_state") == "billing_active":
        raise ActivationError("conta já activa")
    if acc.get("billing_state") not in ACTIVATABLE_STATES:
        raise ActivationError(f"estado {acc.get('billing_state')} não permite activação")

    preview = build_activation_preview(acc, plan_code=plan_code, config=config)
    domain = preview["domain"]
    profile = preview["company_profile"]
    code = preview["plan_code"]
    cfg = preview["config"]
    steps: dict[str, Any] = {}
    partial_errors: list[str] = []

    billing_store.patch_account(
        conn,
        account_id,
        billing_state="provisioning",
        plan_code=code,
        activated_by=activated_by,
        activated_at=_now(),
    )

    foss_client_id = acc.get("external_customer_id")
    foss_order_id = acc.get("external_subscription_id")

    # —— Fase 2: FOSS client + order ——
    try:
        if foss_client_id:
            steps["foss"] = {
                "client_id": foss_client_id,
                "created": False,
                "reused": True,
            }
        else:
            mapped_client = map_foss_client(profile, domain)
            foss_step = foss_client.create_client(mapped=mapped_client)
            foss_client_id = foss_step.get("client_id")
            steps["foss"] = {
                "client_id": foss_client_id,
                "created": bool(foss_step.get("created")),
                "reused": bool(foss_step.get("reused")),
            }
            if foss_client_id:
                billing_store.patch_account(
                    conn,
                    account_id,
                    external_customer_id=str(foss_client_id),
                )
    except Exception as exc:
        log.warning("FOSS client failed domain=%s: %s", domain, exc)
        steps["foss"] = {"error": str(exc)}
        partial_errors.append(f"FOSS client: {exc}")

    if foss_client_id and not foss_order_id:
        try:
            order_step = foss_client.create_order(
                client_id=foss_client_id,
                product_slug=code,
                domain=domain,
                config=cfg,
                manager_email=profile.get("manager_email"),
                manager_name=profile.get("manager_name"),
                activate=True,
            )
            foss_order_id = order_step.get("order_id")
            steps["foss"]["order_id"] = foss_order_id
            steps["foss"]["order_created"] = True
            if foss_order_id:
                billing_store.patch_account(
                    conn,
                    account_id,
                    external_subscription_id=str(foss_order_id),
                )
        except Exception as exc:
            log.warning("FOSS order failed domain=%s: %s", domain, exc)
            steps.setdefault("foss", {})["order_error"] = str(exc)
            partial_errors.append(f"FOSS order: {exc}")
    elif foss_order_id:
        steps.setdefault("foss", {})["order_id"] = foss_order_id
        steps["foss"]["order_created"] = False

    # —— Fase 3: OpenPanel (fallback directo se módulo FOSS não provisionou) ——
    op_mapped = map_openpanel(domain=domain, profile=profile, plan_code=code, config=cfg)
    username = op_mapped["username"]
    if skip_openpanel or not openpanel_client.bridge_configured():
        steps["openpanel"] = {
            "skipped": True,
            "reason": "bridge não configurado" if not openpanel_client.bridge_configured() else "skip_openpanel",
            "username": username,
        }
    elif profile.get("openpanel_username"):
        steps["openpanel"] = {
            "username": profile.get("openpanel_username"),
            "domain": domain,
            "created": False,
            "reused": True,
        }
    else:
        try:
            panel_pwd = secrets.token_urlsafe(12)
            op_step = openpanel_client.provision_user_safe(
                username=username,
                password=panel_pwd,
                email=str(profile.get("manager_email") or ""),
                domain=domain,
                plan_name=code,
                metadata=op_mapped.get("metadata"),
            )
            steps["openpanel"] = {
                "username": username,
                "domain": domain,
                "success": True,
                "created": bool(op_step.get("created", True)),
                "reused": bool(op_step.get("reused")),
            }
            billing_store.merge_company_profile(
                conn,
                account_id,
                {
                    "openpanel_username": username,
                    "openpanel_domain": domain,
                },
            )
        except Exception as exc:
            log.warning("OpenPanel failed domain=%s: %s", domain, exc)
            steps["openpanel"] = {"username": username, "error": str(exc)}
            partial_errors.append(f"OpenPanel: {exc}")

    # —— Fase 4: Odoo partner ——
    odoo_partner_id = acc.get("odoo_partner_id")
    try:
        partner_mapped = map_odoo_partner(profile, domain, foss_client_id=foss_client_id)
        if odoo_partner_id:
            steps["odoo"] = {
                "partner_id": int(odoo_partner_id),
                "created": False,
                "reused": True,
            }
        else:
            odoo_step = odoo_client.upsert_customer_partner(mapped=partner_mapped)
            odoo_partner_id = odoo_step.get("partner_id")
            steps["odoo"] = {
                "partner_id": odoo_partner_id,
                "created": bool(odoo_step.get("created")),
                "updated": bool(odoo_step.get("updated")),
            }
            if odoo_partner_id:
                billing_store.patch_account(
                    conn,
                    account_id,
                    odoo_partner_id=str(odoo_partner_id),
                )
    except Exception as exc:
        log.warning("Odoo partner failed domain=%s: %s", domain, exc)
        steps["odoo"] = {"error": str(exc)}
        partial_errors.append(f"Odoo: {exc}")

    # —— Fase 5: Wizard mail-bundle ——
    if provision_mail and code.startswith("ligbox-mail"):
        try:
            mail_payload = map_wizard_mail_bundle(
                domain=domain,
                profile=profile,
                config=cfg,
                foss_order_id=foss_order_id,
            )
            wizard_step = wizard_client.provision_mail_bundle(mail_payload)
            steps["wizard"] = wizard_step
            if wizard_step.get("skipped"):
                steps["wizard"]["provisioned"] = False
            else:
                steps["wizard"]["provisioned"] = bool(wizard_step.get("provisioned"))
        except Exception as exc:
            log.warning("Wizard mail-bundle failed domain=%s: %s", domain, exc)
            steps["wizard"] = {"error": str(exc), "provisioned": False}
            partial_errors.append(f"Wizard: {exc}")
    else:
        steps["wizard"] = {"skipped": True, "reason": "provision_mail=false ou plano não-mail"}

    ok = not partial_errors
    final_state = "billing_active" if ok else "provisioning"
    billing_store.patch_account(
        conn,
        account_id,
        billing_state=final_state,
        recurrence_active=ok,
        plan_code=code,
    )
    billing_store.save_provision_log(
        conn,
        account_id,
        {
            "activated_at": _now(),
            "activated_by": activated_by,
            "notes": notes,
            "steps": steps,
            "partial_errors": partial_errors,
            "ok": ok,
        },
    )

    out = {
        "ok": ok,
        "billing_account_id": account_id,
        "domain": domain,
        "billing_state": final_state,
        "steps": steps,
        "activated_at": _now(),
        "activated_by": activated_by,
    }
    if partial_errors:
        out["message"] = " — ".join(partial_errors)
    return out
