"""Unit tests — Spec 043 client activation orchestration."""

from __future__ import annotations

import importlib.util
import sqlite3
import sys
import types
import unittest
from pathlib import Path
from unittest.mock import MagicMock, patch

API_ROOT = Path(__file__).resolve().parents[1]


def _load(name: str, rel_path: str):
    path = API_ROOT / rel_path
    spec = importlib.util.spec_from_file_location(name, path)
    if spec is None or spec.loader is None:
        raise ImportError(path)
    mod = importlib.util.module_from_spec(spec)
    sys.modules[name] = mod
    spec.loader.exec_module(mod)
    return mod


billing_store = _load("billing_store_043", "app/billing_store.py")
activation_mapper = _load("activation_mapper_043b", "app/activation_mapper.py")

# Stubs vm123 para evitar import FastAPI em ambiente de teste mínimo
_mock_foss = types.ModuleType("app.vm123.foss_client")
_mock_odoo = types.ModuleType("app.vm123.odoo_client")
_mock_op = types.ModuleType("app.vm123.openpanel_client")
_mock_wizard = types.ModuleType("app.vm123.wizard_client")
_mock_vm123 = types.ModuleType("app.vm123")
_mock_vm123.foss_client = _mock_foss
_mock_vm123.odoo_client = _mock_odoo
_mock_vm123.openpanel_client = _mock_op
_mock_vm123.wizard_client = _mock_wizard
for key, mod in {
    "app": types.ModuleType("app"),
    "app.vm123": _mock_vm123,
    "app.vm123.foss_client": _mock_foss,
    "app.vm123.odoo_client": _mock_odoo,
    "app.vm123.openpanel_client": _mock_op,
    "app.vm123.wizard_client": _mock_wizard,
    "app.billing_store": billing_store,
    "app.activation_mapper": activation_mapper,
}.items():
    sys.modules.setdefault(key, mod)
sys.modules["app"].billing_store = billing_store

client_activation = _load("client_activation_043", "app/client_activation.py")


def _memory_conn():
    conn = sqlite3.connect(":memory:")
    conn.row_factory = sqlite3.Row
    billing_store.init_schema(conn)
    return conn


def _seed_account(conn, domain: str = "acme.com.br") -> int:
    billing_store.upsert_from_company_validated(
        conn,
        domain=domain,
        session_id="sess-1",
        ticket_id=99,
        data={
            "billing_state": "awaiting_billing_validation",
            "company_profile": {
                "legal_name": "ACME LTDA",
                "trade_name": "ACME",
                "tax_id": "00000000000191",
                "email_billing": "fin@acme.com",
                "manager_name": "João Silva",
                "manager_email": "admin@acme.com.br",
                "address": {"country": "BR", "city": "São Paulo", "postal_code": "01310-100"},
            },
        },
    )
    row = conn.execute("SELECT id FROM billing_accounts WHERE domain = ?", (domain,)).fetchone()
    return int(row["id"])


class TestClientActivation043(unittest.TestCase):
    def test_activate_full_happy_path(self):
        _mock_foss.create_client = MagicMock(return_value={"client_id": 101, "created": True, "reused": False})
        _mock_foss.create_order = MagicMock(return_value={"order_id": 55, "created": True})
        _mock_op.bridge_configured = MagicMock(return_value=True)
        _mock_op.provision_user_safe = MagicMock(return_value={"success": True, "created": True})
        _mock_odoo.upsert_customer_partner = MagicMock(return_value={"partner_id": 88, "created": True})
        _mock_wizard.provision_mail_bundle = MagicMock(
            return_value={"provisioned": True, "mail_host": "mail.acme.com.br"}
        )

        conn = _memory_conn()
        acc_id = _seed_account(conn)
        result = client_activation.activate_billing_account(
            conn,
            acc_id,
            plan_code="ligbox-mail-business",
            activated_by="roger",
        )
        self.assertTrue(result["ok"])
        self.assertEqual(result["steps"]["foss"]["client_id"], 101)
        self.assertEqual(result["steps"]["foss"]["order_id"], 55)
        self.assertEqual(result["steps"]["odoo"]["partner_id"], 88)
        acc = billing_store.get_account(conn, acc_id)
        self.assertEqual(acc["billing_state"], "billing_active")
        self.assertTrue(acc["recurrence_active"])
        self.assertEqual(acc["external_customer_id"], "101")

    def test_activate_idempotent_foss_client(self):
        _mock_foss.create_client = MagicMock()
        _mock_foss.create_order = MagicMock(return_value={"order_id": 12})
        _mock_op.bridge_configured = MagicMock(return_value=False)
        _mock_odoo.upsert_customer_partner = MagicMock(return_value={"partner_id": 3, "created": False})
        _mock_wizard.provision_mail_bundle = MagicMock(return_value={"skipped": True})

        conn = _memory_conn()
        acc_id = _seed_account(conn)
        billing_store.patch_account(conn, acc_id, external_customer_id="77")
        result = client_activation.activate_billing_account(
            conn, acc_id, plan_code="ligbox-mail-business", activated_by="roger"
        )
        _mock_foss.create_client.assert_not_called()
        self.assertTrue(result["steps"]["foss"]["reused"])

    def test_activate_rejects_active_account(self):
        conn = _memory_conn()
        acc_id = _seed_account(conn)
        billing_store.patch_account(conn, acc_id, recurrence_active=True, billing_state="billing_active")
        with self.assertRaises(client_activation.ActivationError):
            client_activation.activate_billing_account(
                conn, acc_id, plan_code="ligbox-mail-business", activated_by="roger"
            )


class TestBillingStore043(unittest.TestCase):
    def test_merge_company_profile(self):
        conn = _memory_conn()
        acc_id = _seed_account(conn)
        billing_store.merge_company_profile(conn, acc_id, {"openpanel_username": "acmex"})
        acc = billing_store.get_account(conn, acc_id)
        self.assertEqual(acc["company_profile"]["openpanel_username"], "acmex")


if __name__ == "__main__":
    unittest.main()
