"""Teste US-001/US-002 (PRD 5.17): app/plans.py — definitia planurilor + helperi tier/consum."""

from __future__ import annotations

import os
import tempfile
from datetime import datetime, timedelta, timezone

import pytest


@pytest.fixture()
def conn(monkeypatch):
    tmp = tempfile.mkdtemp()
    monkeypatch.setenv("AUTOPASS_DB_PATH", os.path.join(tmp, "test_plans.db"))
    from app.config import get_settings
    get_settings.cache_clear()
    from app.db import get_connection, init_db
    init_db()
    c = get_connection()
    yield c
    c.close()
    get_settings.cache_clear()


# ---------------------------------------------------------------------------
# PLANS — sursa de adevar
# ---------------------------------------------------------------------------

def test_plan_definitii_free():
    from app.plans import PLANS, FREE_MONTHLY_LIMIT
    p = PLANS["free"]
    assert p["monthly_limit"] == FREE_MONTHLY_LIMIT
    assert p["monthly_limit"] == 60
    assert p["api_access"] is False
    assert p["label"] == "Gratuit"


def test_plan_definitii_standard():
    from app.plans import PLANS
    p = PLANS["standard"]
    assert p["monthly_limit"] is None
    assert p["api_access"] is False
    assert "label" in p


def test_plan_definitii_pro():
    from app.plans import PLANS
    p = PLANS["pro"]
    assert p["monthly_limit"] is None
    assert p["api_access"] is True
    assert "label" in p


def test_plan_definitii_premium():
    from app.plans import PLANS
    p = PLANS["premium"]
    assert p["monthly_limit"] is None
    assert p["api_access"] is True
    assert "label" in p


def test_toate_tierurile_prezente():
    from app.plans import PLANS
    assert set(PLANS.keys()) == {"free", "standard", "pro", "premium"}


def test_consumed_statuses_exportata():
    from app.plans import CONSUMED_STATUSES
    assert "queued" in CONSUMED_STATUSES
    assert "sending" in CONSUMED_STATUSES
    assert "sent" in CONSUMED_STATUSES
    # statusuri blocate nu se numara
    assert "error" not in CONSUMED_STATUSES
    assert "needs_mapping" not in CONSUMED_STATUSES
    assert "needs_data" not in CONSUMED_STATUSES


def test_free_monthly_limit_constanta():
    """FREE_MONTHLY_LIMIT e o singura constanta (DRY), referita din PLANS."""
    from app.plans import FREE_MONTHLY_LIMIT, PLANS
    assert isinstance(FREE_MONTHLY_LIMIT, int)
    assert FREE_MONTHLY_LIMIT == 60
    # PLANS["free"]["monthly_limit"] refera aceeasi valoare (nu hardcodat separat)
    assert PLANS["free"]["monthly_limit"] == FREE_MONTHLY_LIMIT


# ---------------------------------------------------------------------------
# effective_tier
# ---------------------------------------------------------------------------

def _now_utc():
    return datetime.now(timezone.utc)


def test_effective_tier_trial_activ_returneaza_pro():
    from app.plans import effective_tier
    now = _now_utc()
    trial_until = (now + timedelta(days=15)).strftime("%Y-%m-%d %H:%M:%S")
    account = {"tier": "free", "trial_until": trial_until}
    assert effective_tier(account, now) == "pro"


def test_effective_tier_trial_expirat_returneaza_tier_baza():
    from app.plans import effective_tier
    now = _now_utc()
    trial_until = (now - timedelta(days=1)).strftime("%Y-%m-%d %H:%M:%S")
    account = {"tier": "free", "trial_until": trial_until}
    assert effective_tier(account, now) == "free"


def test_effective_tier_fara_trial_returneaza_tier():
    from app.plans import effective_tier
    now = _now_utc()
    account = {"tier": "standard", "trial_until": None}
    assert effective_tier(account, now) == "standard"


def test_effective_tier_plan_platit_nu_downgradat_de_trial_expirat():
    """Un cont pro setat de admin NU e downgradat de expirarea trial-ului."""
    from app.plans import effective_tier
    now = _now_utc()
    # tier=pro, trial_until in trecut: downgrade nu se produce (pro > free)
    trial_until = (now - timedelta(days=5)).strftime("%Y-%m-%d %H:%M:%S")
    account = {"tier": "pro", "trial_until": trial_until}
    # tier de baza e pro, deci effective = pro (nu se coboara la free)
    assert effective_tier(account, now) == "pro"


def test_effective_tier_trial_malformat_fallback_defensiv():
    from app.plans import effective_tier
    now = _now_utc()
    account = {"tier": "free", "trial_until": "nu-e-o-data-valida"}
    # malformat -> fallback la tier de baza, fara exceptie
    assert effective_tier(account, now) == "free"


def test_effective_tier_trial_null_fallback():
    from app.plans import effective_tier
    now = _now_utc()
    account = {"tier": "free", "trial_until": None}
    assert effective_tier(account, now) == "free"


def test_effective_tier_injectat_determinist():
    """now injectabil: putem simula orice moment — teste deterministe fara datetime.now()."""
    from app.plans import effective_tier
    # trial_until fix
    trial_until = "2026-07-10 12:00:00"
    account = {"tier": "free", "trial_until": trial_until}

    # inainte de expirare
    now_before = datetime(2026, 7, 5, 12, 0, 0, tzinfo=timezone.utc)
    assert effective_tier(account, now_before) == "pro"

    # dupa expirare
    now_after = datetime(2026, 7, 15, 12, 0, 0, tzinfo=timezone.utc)
    assert effective_tier(account, now_after) == "free"


def test_effective_tier_premium_cu_trial_pro():
    """premium are api_access=True oricum; trial_until viitor nu strica."""
    from app.plans import effective_tier
    now = _now_utc()
    trial_until = (now + timedelta(days=10)).strftime("%Y-%m-%d %H:%M:%S")
    account = {"tier": "premium", "trial_until": trial_until}
    # trial activ -> 'pro', dar premium e oricum superior (nu ne intereseaza downgrade)
    # functia intoarce 'pro' cand trial e activ; consumatorul vede pro (care are api_access)
    assert effective_tier(account, now) == "pro"


# ---------------------------------------------------------------------------
# monthly_usage
# ---------------------------------------------------------------------------

def _uid():
    """Cheie idempotenta unica per apel (pentru INSERT in teste)."""
    import binascii
    return binascii.hexlify(os.urandom(8)).decode()


def _insert_submission(conn, account_id, status, created_at_str):
    """Insereaza o submisie de test cu timestamp explicit."""
    conn.execute(
        "INSERT INTO submissions (idempotency_key, account_id, status, payload_json, created_at) "
        "VALUES (?, ?, ?, '{}', ?)",
        (_uid(), account_id, status, created_at_str),
    )


def test_consum_lunar_numara_consumed_statuses(conn):
    from app.plans import monthly_usage
    from app.accounts import create_account
    now = _now_utc()
    now_str = now.strftime("%Y-%m-%d %H:%M:%S")

    account_id = create_account(conn, "Test Consum", cui="RO1001")

    # 3 statusuri consumate
    _insert_submission(conn, account_id, "queued", now_str)
    _insert_submission(conn, account_id, "sending", now_str)
    _insert_submission(conn, account_id, "sent", now_str)

    assert monthly_usage(conn, account_id, now) == 3


def test_consum_lunar_exclude_statusuri_blocate(conn):
    from app.plans import monthly_usage
    from app.accounts import create_account
    now = _now_utc()
    now_str = now.strftime("%Y-%m-%d %H:%M:%S")

    account_id = create_account(conn, "Test Blocat", cui="RO1002")

    # statusuri care NU se numara
    for status in ("error", "needs_mapping", "needs_data"):
        _insert_submission(conn, account_id, status, now_str)

    assert monthly_usage(conn, account_id, now) == 0


def test_consum_lunar_scoped_pe_cont(conn):
    from app.plans import monthly_usage
    from app.accounts import create_account
    now = _now_utc()
    now_str = now.strftime("%Y-%m-%d %H:%M:%S")

    acct_a = create_account(conn, "Cont A", cui="RO1003")
    acct_b = create_account(conn, "Cont B", cui="RO1004")

    _insert_submission(conn, acct_a, "sent", now_str)
    _insert_submission(conn, acct_a, "sent", now_str)
    _insert_submission(conn, acct_b, "sent", now_str)

    assert monthly_usage(conn, acct_a, now) == 2
    assert monthly_usage(conn, acct_b, now) == 1


def test_consum_lunar_luna_trecuta_nu_se_numara(conn):
    from app.plans import monthly_usage
    from app.accounts import create_account
    now = _now_utc()

    account_id = create_account(conn, "Test Luna Trecuta", cui="RO1005")

    # Calculam o data din luna trecuta (prima zi a lunii curente - 1 zi)
    first_of_month = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
    last_of_prev_month = first_of_month - timedelta(days=1)
    prev_str = last_of_prev_month.strftime("%Y-%m-%d %H:%M:%S")

    _insert_submission(conn, account_id, "sent", prev_str)

    # luna curenta: 0
    assert monthly_usage(conn, account_id, now) == 0


def test_consum_lunar_granita_luna_noua(conn):
    """Submisii la granita intre luni sunt bucketate corect (timp local RO = UTC in container)."""
    from app.plans import monthly_usage
    from app.accounts import create_account
    now = _now_utc()
    now_str = now.strftime("%Y-%m-%d %H:%M:%S")

    account_id = create_account(conn, "Test Granita", cui="RO1006")

    # Prima secunda a lunii curente (calculata consistent cu 'localtime' = UTC in container)
    first_of_month = now.replace(day=1, hour=0, minute=0, second=1, microsecond=0)
    first_str = first_of_month.strftime("%Y-%m-%d %H:%M:%S")

    # Ultima secunda a lunii trecute
    last_of_prev_month = first_of_month - timedelta(seconds=2)
    prev_str = last_of_prev_month.strftime("%Y-%m-%d %H:%M:%S")

    _insert_submission(conn, account_id, "sent", first_str)   # luna curenta
    _insert_submission(conn, account_id, "sent", prev_str)    # luna trecuta
    _insert_submission(conn, account_id, "sent", now_str)     # luna curenta

    assert monthly_usage(conn, account_id, now) == 2


def test_consum_lunar_zero_pe_cont_gol(conn):
    from app.plans import monthly_usage
    from app.accounts import create_account
    now = _now_utc()

    account_id = create_account(conn, "Cont Gol", cui="RO1007")

    assert monthly_usage(conn, account_id, now) == 0


def test_consum_lunar_nu_numara_cross_account(conn):
    """Verificare scoping: contul default (id=1) nu influenteaza alt cont."""
    from app.plans import monthly_usage
    from app.accounts import create_account
    now = _now_utc()
    now_str = now.strftime("%Y-%m-%d %H:%M:%S")

    account_id = create_account(conn, "Cont Izolat", cui="RO1008")

    # Inseram pentru contul default (id=1)
    _insert_submission(conn, 1, "sent", now_str)
    _insert_submission(conn, 1, "sent", now_str)

    # Contul nou nu trebuie sa numere al celor de pe id=1
    assert monthly_usage(conn, account_id, now) == 0
    assert monthly_usage(conn, 1, now) == 2


# ---------------------------------------------------------------------------
# PRD 5.17 enforcement — logica de limita + kill-switch config
# ---------------------------------------------------------------------------

def test_volume_la_limita_exacta(conn):
    """La exact FREE_MONTHLY_LIMIT submissions, usage == limita (nu inca depasit).

    Enforcer-ul verifica usage + nr_cerut > limit, deci la usage=60, nr_cerut=1 ->
    61 > 60 -> respins; dar usage=60 in sine (inainte de cerere) e valid.
    """
    from app.plans import monthly_usage, FREE_MONTHLY_LIMIT
    from app.accounts import create_account
    now = _now_utc()
    now_str = now.strftime("%Y-%m-%d %H:%M:%S")

    account_id = create_account(conn, "Test La Limita", cui="RO2001")
    for _ in range(FREE_MONTHLY_LIMIT):
        _insert_submission(conn, account_id, "queued", now_str)
    conn.commit()

    usage = monthly_usage(conn, account_id, now)
    assert usage == FREE_MONTHLY_LIMIT, (
        f"La limita exacta: asteptat {FREE_MONTHLY_LIMIT}, primit {usage}"
    )
    # Simulam logica enforcer: 1 cerere noua depaseste limita
    assert usage + 1 > FREE_MONTHLY_LIMIT, "O cerere noua trebuia sa depaseasca limita"
    # La 0 cereri noi: nu depaseste
    assert usage + 0 <= FREE_MONTHLY_LIMIT, "La 0 cereri noi, limita nu e depasita"


def test_enforce_plans_config_default_true(monkeypatch):
    """AUTOPASS_ENFORCE_PLANS implicit True — enforcement activ de la deploy.

    Decizie user (autoplan 2026-06-28): nu exista conturi legacy, produs in TESTE,
    enforcement DUR activ implicit. Kill-switch oprit explicit cand e necesar.
    """
    from app.config import Settings
    # Creem Settings fresh (fara env var setata) -> default True
    monkeypatch.delenv("AUTOPASS_ENFORCE_PLANS", raising=False)
    s = Settings()
    assert s.enforce_plans is True, (
        "AUTOPASS_ENFORCE_PLANS trebuia sa fie True implicit (enforcement activ din start)"
    )


def test_enforce_plans_kill_switch_false(monkeypatch):
    """AUTOPASS_ENFORCE_PLANS=false dezactiveaza enforcement."""
    from app.config import Settings
    monkeypatch.setenv("AUTOPASS_ENFORCE_PLANS", "false")
    s = Settings()
    assert s.enforce_plans is False
