"""Teste E2E enforcement plan pe canalul web de import (PRD 5.17 T3).

Verifica ca limita de volum (60/luna free) e respectata si pe canalul web
(web_confirma_import in routes.py), nu doar pe canalul API.
"""

from __future__ import annotations

import csv
import io
import os
import re
import tempfile
from datetime import datetime, timezone

import pytest
from fastapi.testclient import TestClient


# ---------------------------------------------------------------------------
# Fixture client web izolat (WEB_AUTH_REQUIRED=false -> fara login, cont 1)
# ---------------------------------------------------------------------------

@pytest.fixture()
def client(monkeypatch):
    """Client cu DB izolata, WEB_AUTH_REQUIRED=false (dev — fara login necesar)."""
    tmp = tempfile.mkdtemp()
    monkeypatch.setenv("AUTOPASS_DB_PATH", os.path.join(tmp, "web-e2e-plan.db"))
    monkeypatch.setenv("AUTOPASS_WEB_AUTH_REQUIRED", "false")
    from app.config import get_settings
    get_settings.cache_clear()
    from app.crypto import reset_cache
    reset_cache()
    from app.main import app
    with TestClient(app) as c:
        yield c
    get_settings.cache_clear()
    reset_cache()


# ---------------------------------------------------------------------------
# Utilitare
# ---------------------------------------------------------------------------

def _csv_bytes(rows: list[dict], sep: str = ";") -> bytes:
    buf = io.StringIO()
    writer = csv.DictWriter(buf, fieldnames=list(rows[0].keys()), delimiter=sep)
    writer.writeheader()
    writer.writerows(rows)
    return buf.getvalue().encode("utf-8")


def _seed_nomenclator_si_mapare(cod_prestatie: str = "OE-1", cod_op: str = "OP-WEB-PLAN") -> None:
    """Semeaza nomenclatorul RAR si o mapare operatie->cod (necesare pentru randuri ok)."""
    from app.db import get_connection
    conn = get_connection()
    try:
        conn.execute(
            "INSERT OR REPLACE INTO nomenclator_rar (cod_prestatie, nume_prestatie) VALUES (?,?)",
            (cod_prestatie, "Operatie test plan"),
        )
        conn.execute(
            "INSERT OR IGNORE INTO operations_mapping "
            "(account_id, cod_op_service, cod_prestatie, auto_send) VALUES (1,?,?,1)",
            (cod_op, cod_prestatie),
        )
        conn.commit()
    finally:
        conn.close()


def _insert_60_submissions_luna() -> None:
    """Insereaza 60 submissions queued in luna curenta pentru contul 1 (la limita free)."""
    from app.db import get_connection
    conn = get_connection()
    try:
        now_str = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
        for i in range(60):
            conn.execute(
                "INSERT INTO submissions "
                "(idempotency_key, account_id, status, payload_json, created_at) "
                "VALUES (?, 1, 'queued', '{}', ?)",
                (f"web-vol60-{i}-{os.urandom(4).hex()}", now_str),
            )
        conn.commit()
    finally:
        conn.close()


def _upload_preview_si_commit(client: TestClient, rows: list[dict]):  # type: ignore[return]
    """Parcurge fluxul web: upload -> mapare coloane (daca e necesar) -> confirma.

    Intoarce (import_id, raspuns_confirma). Presupune nomenclatorul si maparea semanate.
    """
    data = _csv_bytes(rows)
    r = client.post(
        "/_import/upload",
        files={"file": ("plan_test.csv", io.BytesIO(data), "text/csv")},
    )
    assert r.status_code == 200, f"Upload esuat: {r.text[:300]}"

    m = re.search(r"/_import/(\d+)/", r.text)
    assert m, f"import_id negasit in raspunsul de upload: {r.text[:400]}"
    iid = int(m.group(1))

    if f"/_import/{iid}/mapare-coloane" in r.text:
        r2 = client.post(
            f"/_import/{iid}/mapare-coloane",
            data={
                "colname": ["VIN", "Nr", "Data", "KM", "Operatie"],
                "canon":   ["vin", "nr_inmatriculare", "data_prestatie", "odometru_final", "operatie"],
                "format_data": "YYYY-MM-DD",
            },
        )
        assert r2.status_code == 200, f"Mapare coloane esuata: {r2.text[:300]}"

    # GET preview pentru n_ok
    rp = client.get(f"/_import/{iid}/preview")
    assert rp.status_code == 200, f"Preview esuat: {rp.text[:300]}"
    m_ok = re.search(r'id="n-confirmat"[^>]*?value="(\d+)"', rp.text)
    n_ok = int(m_ok.group(1)) if m_ok else len(rows)

    r_conf = client.post(
        f"/_import/{iid}/confirma",
        data={
            "csrf_token": "",
            "n_confirmat": str(n_ok),
            "confirmed_by": "test-plan@autopass.ro",
        },
    )
    return iid, r_conf


# Date CSV: un singur rand ok
_ROWS_PLAN_WEB = [
    {
        "VIN": "WVWZZZ1KZAW700001",
        "Nr": "B700TST",
        "Data": "2026-06-15",
        "KM": "70000",
        "Operatie": "OP-WEB-PLAN",
    },
]


# ---------------------------------------------------------------------------
# Test T3 — volum pe canalul web
# ---------------------------------------------------------------------------

def test_free_peste_60_respins_import_web(client):
    """Canal WEB de import: free la 60/60 → commit respins cu mesaj de limita plan.

    T3 PRD 5.17: enforcement volum pe canalul web (web_confirma_import in routes.py).
    Contul 1 e pe tier=free, fara trial, la 60/60 prestatii in luna curenta.
    Commit-ul unui lot nou trebuie respins (intregul lot, nu partial) cu mesaj clar.
    """
    from app.db import get_connection

    # Seteaza contul 1 (implicit web in dev mode) pe free fara trial
    conn = get_connection()
    try:
        conn.execute("UPDATE accounts SET tier='free', trial_until=NULL WHERE id=1")
        conn.commit()
    finally:
        conn.close()

    # Seed nomenclator si mapare operatie->cod
    _seed_nomenclator_si_mapare()

    # Insereaza 60 submissions (la limita)
    _insert_60_submissions_luna()

    # Parcurge fluxul web pana la commit
    _iid, r_conf = _upload_preview_si_commit(client, _ROWS_PLAN_WEB)

    assert r_conf.status_code == 200, (  # type: ignore[union-attr]
        f"Commit trebuia sa intoarca 200 HTML (nu 5xx): {r_conf.status_code}"  # type: ignore[union-attr]
    )

    # Raspunsul HTML trebuie sa contina mesajul de limita de plan
    html = r_conf.text.lower()  # type: ignore[union-attr]
    assert ("limita" in html or "gratuit" in html or "60" in html), (
        f"Mesajul de limita plan lipseste din raspunsul HTML al commit-ului:\n{r_conf.text[:600]}"  # type: ignore[union-attr]
    )

    # Verifica ca nu s-au creat submissions noi (lotul a fost respins total)
    from app.plans import monthly_usage
    conn2 = get_connection()
    try:
        usage = monthly_usage(conn2, 1, datetime.now(timezone.utc))
    finally:
        conn2.close()
    assert usage == 60, (
        f"Lotul respins nu trebuia sa adauge submissions: asteptat usage=60, primit {usage}"
    )
