"""Definitia planurilor de cont (sursa unica de adevar). Modul PUR, fara import DB/HTTP.

Pattern ca app/errors.py: catalog + helperi. Consumat de rutele de ingestie si dashboard.
Nu importa DB, HTTP, sau orice alt modul intern cu efecte secundare.

Decizii implementare (PRD 5.17 / autoplan 2026-06-28):
  - FREE_MONTHLY_LIMIT: constanta unica (T-CEO-2), tunabila fara arqueologie de cod.
  - CONSUMED_STATUSES: decizie #20 — prestatie consumata = acceptata in coada.
  - effective_tier: `now` injectabil (decizie #2) pentru teste deterministe.
  - monthly_usage: pattern E7/5.15 (strftime localtime), `now` injectabil.
"""

from __future__ import annotations

import sqlite3
from datetime import datetime, timezone

# Limita lunara pentru planul Gratuit.
# Decizie user T-CEO-2 (2026-06-28): o singura constanta, referita din PLANS.
# Tunabila fara a modifica logica de enforcement.
FREE_MONTHLY_LIMIT: int = 60

# Statusurile care consuma din cota lunara (decizie #20, 2026-06-28).
# Prestatie consumata = acceptata in coada (queued/sending/sent), nu cele respinse/blocate.
# Rationale: limita e pe ce trimitem la RAR, nu pe incercari esuate sau blocate.
CONSUMED_STATUSES: tuple[str, ...] = ("queued", "sending", "sent")

# Sursa unica de adevar pentru planuri. Fiecare plan are:
#   label        -- eticheta afisata in RO (UI, mesaje)
#   monthly_limit -- None = nelimitat; int = limita prestatii/luna
#   api_access   -- True = acces import prin API (/v1/*); False = doar web dashboard
#
# Aliniat landing-ului comercial (PRD 5.17 US-001):
#   Gratuit:  60/luna, fara API
#   Standard: nelimitat, fara API
#   Pro:      nelimitat, cu API
#   Premium:  nelimitat, cu API (suport dedicat)
PLANS: dict[str, dict] = {
    "free": {
        "label": "Gratuit",
        "monthly_limit": FREE_MONTHLY_LIMIT,
        "api_access": False,
    },
    "standard": {
        "label": "Standard",
        "monthly_limit": None,
        "api_access": False,
    },
    "pro": {
        "label": "Pro",
        "monthly_limit": None,
        "api_access": True,
    },
    "premium": {
        "label": "Premium",
        "monthly_limit": None,
        "api_access": True,
    },
}


def effective_tier(account_row, now: datetime) -> str:
    """Returneaza tier-ul efectiv al contului la momentul `now` (injectabil pentru determinism).

    Daca `trial_until` e in viitor -> 'pro' (trial Pro activ).
    Altfel -> `tier`-ul de baza al contului.
    trial_until malformat/NULL -> fallback defensiv la tier de baza (nu arunca niciodata).

    `now` TREBUIE injectat explicit (nu datetime.now() intern) — decizie #2 din autoplan.
    Suporta sqlite3.Row si dict.
    """
    # Citire robusta: suporta sqlite3.Row (IndexError pe key absent) si dict (KeyError)
    try:
        tier = account_row["tier"]
    except (KeyError, IndexError, TypeError):
        tier = "free"
    try:
        trial_until_str = account_row["trial_until"]
    except (KeyError, IndexError, TypeError):
        trial_until_str = None

    # Fallback defensiv la 'free' daca tier e None/gol
    if not tier:
        tier = "free"

    if not trial_until_str:
        return tier

    try:
        # Parseaza trial_until; stocam ca "YYYY-MM-DD HH:MM:SS" (UTC implicit) sau ISO
        tu = datetime.fromisoformat(trial_until_str.strip().replace(" ", "T"))
        # Daca fara timezone -> assume UTC (cum stocam in DB)
        if tu.tzinfo is None:
            tu = tu.replace(tzinfo=timezone.utc)
        # Normalizeaza `now` la aware daca e naive
        now_cmp = now
        if now_cmp.tzinfo is None:
            now_cmp = now_cmp.replace(tzinfo=timezone.utc)
        if tu > now_cmp:
            return "pro"
    except (ValueError, AttributeError, TypeError):
        pass  # malformat -> fallback defensiv la tier de baza

    return tier


def monthly_usage(conn: sqlite3.Connection, account_id: int, now: datetime) -> int:
    """Numara prestatiile contului acceptate in coada in luna calendaristica curenta.

    Definitia 'luna curenta': strftime('%Y-%m', created_at, 'localtime') corespunde
    lunii lui `now` (acelasi pattern ca E7/5.15 din routes.py — consistent cu 'localtime').
    `now` injectabil pentru teste deterministe. Scoped strict pe account_id.
    created_at NULL/malformat -> exclus defensiv (nu arunca niciodata).

    NOTA: containerul are /etc/localtime=UTC, deci 'localtime' = UTC in mediul de test.
    Testele de granita construiesc timestamp-uri relative la luna curenta calculata cu
    acelasi 'localtime', nu valori absolute care presupun +2/+3h.
    """
    # Formatam `now` ca string SQLite si folosim acelasi modificator 'localtime' ca routes.py
    now_str = now.strftime("%Y-%m-%d %H:%M:%S")
    placeholders = ",".join("?" * len(CONSUMED_STATUSES))
    row = conn.execute(
        f"SELECT COUNT(*) AS n FROM submissions "
        f"WHERE account_id = ? "
        f"  AND status IN ({placeholders}) "
        f"  AND created_at IS NOT NULL "
        f"  AND strftime('%Y-%m', created_at, 'localtime') = strftime('%Y-%m', ?, 'localtime')",
        (account_id, *CONSUMED_STATUSES, now_str),
    ).fetchone()
    return int(row["n"]) if row else 0
