"""Billing accounts store — Spec 023."""

from __future__ import annotations

import json
import re
from datetime import datetime, timezone
from typing import Any

FOSSBILLING_URL = "https://financeiro.ligbox.com.br"
ODOO_URL = "https://financeiro.ligbox.com.br/odoo/web/login?db=ligbox"

TAX_ID_RE = re.compile(r"\d")


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


def init_schema(conn) -> None:
    conn.executescript(
        """
        CREATE TABLE IF NOT EXISTS billing_accounts (
            id INTEGER PRIMARY KEY,
            domain TEXT NOT NULL,
            session_id TEXT,
            ticket_id INTEGER,
            tax_id TEXT,
            legal_name TEXT,
            trade_name TEXT,
            email_billing TEXT,
            company_profile_json TEXT,
            billing_state TEXT NOT NULL DEFAULT 'awaiting_billing_validation',
            recurrence_active INTEGER NOT NULL DEFAULT 0,
            external_customer_id TEXT,
            external_subscription_id TEXT,
            payment_provider TEXT,
            plan_code TEXT,
            odoo_partner_id TEXT,
            provision_json TEXT,
            activated_at TEXT,
            activated_by TEXT,
            created_at TEXT NOT NULL,
            updated_at TEXT NOT NULL
        );
        CREATE UNIQUE INDEX IF NOT EXISTS idx_billing_domain ON billing_accounts(domain);
        """
    )
    _ensure_columns(conn)


def _ensure_columns(conn) -> None:
    cols = {row[1] for row in conn.execute("PRAGMA table_info(billing_accounts)")}
    if "odoo_partner_id" not in cols:
        conn.execute("ALTER TABLE billing_accounts ADD COLUMN odoo_partner_id TEXT")
    if "provision_json" not in cols:
        conn.execute("ALTER TABLE billing_accounts ADD COLUMN provision_json TEXT")
    conn.commit()


def _mask_tax_id(tax_id: str | None) -> str:
    if not tax_id:
        return "—"
    digits = TAX_ID_RE.sub("", tax_id)
    if len(digits) < 4:
        return "***"
    return f"{'*' * (len(digits) - 4)}{digits[-4:]}"


def _mask_email(email: str | None) -> str:
    if not email or "@" not in email:
        return "—"
    local, dom = email.split("@", 1)
    if len(local) <= 2:
        return f"**@{dom}"
    return f"{local[:2]}***@{dom}"


def _row_dict(row, *, mask: bool = False) -> dict[str, Any]:
    profile = {}
    if row["company_profile_json"]:
        try:
            profile = json.loads(row["company_profile_json"])
        except json.JSONDecodeError:
            profile = {}
    out = {
        "id": row["id"],
        "domain": row["domain"],
        "session_id": row["session_id"],
        "ticket_id": row["ticket_id"],
        "tax_id": _mask_tax_id(row["tax_id"]) if mask else row["tax_id"],
        "legal_name": row["legal_name"],
        "trade_name": row["trade_name"],
        "email_billing": _mask_email(row["email_billing"]) if mask else row["email_billing"],
        "company_profile": profile if not mask else _mask_profile(profile),
        "billing_state": row["billing_state"],
        "recurrence_active": bool(row["recurrence_active"]),
        "external_customer_id": row["external_customer_id"],
        "external_subscription_id": row["external_subscription_id"],
        "odoo_partner_id": row["odoo_partner_id"] if "odoo_partner_id" in row.keys() else None,
        "payment_provider": row["payment_provider"],
        "plan_code": row["plan_code"],
        "activated_at": row["activated_at"],
        "activated_by": row["activated_by"],
        "provision_log": _provision_summary(row),
        "created_at": row["created_at"],
        "updated_at": row["updated_at"],
        "links": {
            "fossbilling": FOSSBILLING_URL,
            "odoo": ODOO_URL,
        },
    }
    if out.get("odoo_partner_id"):
        out["links"]["odoo_partner"] = f"{ODOO_URL}&partner_id={out['odoo_partner_id']}"
    return out


def _provision_summary(row) -> dict[str, Any] | None:
    raw = row["provision_json"] if "provision_json" in row.keys() else None
    if not raw:
        return None
    try:
        data = json.loads(raw)
    except json.JSONDecodeError:
        return None
    return {
        "ok": data.get("ok"),
        "activated_at": data.get("activated_at"),
        "activated_by": data.get("activated_by"),
        "partial_errors": data.get("partial_errors") or [],
    }


def _mask_profile(profile: dict) -> dict:
    p = dict(profile)
    if p.get("tax_id"):
        p["tax_id"] = _mask_tax_id(str(p["tax_id"]))
    if p.get("email_billing"):
        p["email_billing"] = _mask_email(str(p["email_billing"]))
    return p


def upsert_from_company_validated(
    conn,
    *,
    domain: str,
    session_id: str | None,
    ticket_id: int | None,
    data: dict | None,
) -> dict[str, Any]:
    dom = domain.strip().lower()
    profile = (data or {}).get("company_profile") or {}
    billing_state = (data or {}).get("billing_state") or "awaiting_billing_validation"
    now = _now()
    existing = conn.execute(
        "SELECT id FROM billing_accounts WHERE domain = ?",
        (dom,),
    ).fetchone()
    if existing:
        conn.execute(
            """
            UPDATE billing_accounts SET
              session_id = COALESCE(?, session_id),
              ticket_id = COALESCE(?, ticket_id),
              tax_id = ?, legal_name = ?, trade_name = ?, email_billing = ?,
              company_profile_json = ?, billing_state = ?, updated_at = ?
            WHERE domain = ?
            """,
            (
                session_id,
                ticket_id,
                profile.get("tax_id"),
                profile.get("legal_name"),
                profile.get("trade_name"),
                profile.get("email_billing"),
                json.dumps(profile, ensure_ascii=False),
                billing_state,
                now,
                dom,
            ),
        )
        acc_id = int(existing["id"])
    else:
        cur = conn.execute(
            """
            INSERT INTO billing_accounts
            (domain, session_id, ticket_id, tax_id, legal_name, trade_name, email_billing,
             company_profile_json, billing_state, recurrence_active, created_at, updated_at)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?)
            """,
            (
                dom,
                session_id,
                ticket_id,
                profile.get("tax_id"),
                profile.get("legal_name"),
                profile.get("trade_name"),
                profile.get("email_billing"),
                json.dumps(profile, ensure_ascii=False),
                billing_state,
                now,
                now,
            ),
        )
        acc_id = int(cur.lastrowid)
    conn.commit()
    return get_account(conn, acc_id) or {}


def get_account(conn, account_id: int, *, mask: bool = False) -> dict[str, Any] | None:
    row = conn.execute("SELECT * FROM billing_accounts WHERE id = ?", (account_id,)).fetchone()
    return _row_dict(row, mask=mask) if row else None


def get_by_domain(conn, domain: str, *, mask: bool = False) -> dict[str, Any] | None:
    row = conn.execute(
        "SELECT * FROM billing_accounts WHERE domain = ?",
        (domain.strip().lower(),),
    ).fetchone()
    return _row_dict(row, mask=mask) if row else None


def list_accounts(
    conn,
    *,
    billing_state: str | None = None,
    domain: str | None = None,
    limit: int = 100,
    mask: bool = False,
) -> dict[str, Any]:
    limit = max(1, min(limit, 500))
    clauses = []
    params: list[Any] = []
    if billing_state:
        clauses.append("billing_state = ?")
        params.append(billing_state)
    if domain:
        clauses.append("domain LIKE ?")
        params.append(f"%{domain.strip().lower()}%")
    where = f"WHERE {' AND '.join(clauses)}" if clauses else ""
    rows = conn.execute(
        f"SELECT * FROM billing_accounts {where} ORDER BY updated_at DESC LIMIT ?",
        (*params, limit),
    ).fetchall()
    total = conn.execute(
        f"SELECT COUNT(*) FROM billing_accounts {where}",
        tuple(params),
    ).fetchone()[0]
    return {
        "accounts": [_row_dict(r, mask=mask) for r in rows],
        "total": total,
    }


def patch_account(conn, account_id: int, **fields) -> dict[str, Any] | None:
    allowed = {
        "billing_state",
        "recurrence_active",
        "external_customer_id",
        "external_subscription_id",
        "odoo_partner_id",
        "payment_provider",
        "plan_code",
        "activated_at",
        "activated_by",
        "ticket_id",
        "provision_json",
    }
    if fields.get("recurrence_active"):
        fields.setdefault("billing_state", "billing_active")
    sets = []
    params: list[Any] = []
    for key, val in fields.items():
        if key not in allowed:
            continue
        if key == "recurrence_active":
            val = 1 if val else 0
        sets.append(f"{key} = ?")
        params.append(val)
    if not sets:
        return get_account(conn, account_id)
    sets.append("updated_at = ?")
    params.append(_now())
    params.append(account_id)
    conn.execute(f"UPDATE billing_accounts SET {', '.join(sets)} WHERE id = ?", params)
    conn.commit()
    return get_account(conn, account_id)


def merge_company_profile(conn, account_id: int, updates: dict[str, Any]) -> dict[str, Any] | None:
    row = conn.execute(
        "SELECT company_profile_json FROM billing_accounts WHERE id = ?",
        (account_id,),
    ).fetchone()
    if not row:
        return None
    profile: dict[str, Any] = {}
    if row["company_profile_json"]:
        try:
            profile = json.loads(row["company_profile_json"])
        except json.JSONDecodeError:
            profile = {}
    profile.update(updates)
    conn.execute(
        "UPDATE billing_accounts SET company_profile_json = ?, updated_at = ? WHERE id = ?",
        (json.dumps(profile, ensure_ascii=False), _now(), account_id),
    )
    conn.commit()
    return get_account(conn, account_id)


def save_provision_log(conn, account_id: int, log: dict[str, Any]) -> None:
    conn.execute(
        "UPDATE billing_accounts SET provision_json = ?, updated_at = ? WHERE id = ?",
        (json.dumps(log, ensure_ascii=False), _now(), account_id),
    )
    conn.commit()


def summary(conn) -> dict[str, Any]:
    pending = conn.execute(
        "SELECT COUNT(*) FROM billing_accounts WHERE billing_state = 'awaiting_billing_validation'"
    ).fetchone()[0]
    active = conn.execute(
        "SELECT COUNT(*) FROM billing_accounts WHERE recurrence_active = 1"
    ).fetchone()[0]
    total = conn.execute("SELECT COUNT(*) FROM billing_accounts").fetchone()[0]
    recent = conn.execute(
        "SELECT * FROM billing_accounts ORDER BY updated_at DESC LIMIT 5"
    ).fetchall()
    return {
        "billing_pending": pending,
        "billing_active": active,
        "billing_total": total,
        "recent_validations": [_row_dict(r) for r in recent],
    }
