"""Teste US-009 (PRD 5.20) — Import web: selector mediu RAR conditionat de disponibilitate.

Verifica:
  - La 0 medii: banner avertisment non-blocant (upload functioneaza, commit foloseste ancora globala).
  - La 1 mediu: eticheta statica, fara selector; submissions primesc acel mediu.
  - La 2 medii: selector vizibil pre-bifat pe default-ul contului.
  - La commit: toate submission-urile lotului primesc rar_env ales (sau fallback ancora globala).
"""

from __future__ import annotations

import csv
import io
import os
import re
import tempfile

import pytest
from fastapi.testclient import TestClient


# --------------------------------------------------------------------------- #
# Fixture client cu DB izolat                                                   #
# --------------------------------------------------------------------------- #

@pytest.fixture()
def client(monkeypatch):
    tmp = tempfile.mkdtemp()
    monkeypatch.setenv("AUTOPASS_DB_PATH", os.path.join(tmp, "rar_env_test.db"))
    monkeypatch.setenv("AUTOPASS_WEB_AUTH_REQUIRED", "false")
    monkeypatch.setenv("AUTOPASS_RAR_ENV", "test")  # ancora globala = test
    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(client: TestClient) -> None:
    """Semeaza nomenclatorul si o mapare 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 (?,?)",
            ("R-FRANE", "Reparatie frane"),
        )
        conn.execute(
            "INSERT OR IGNORE INTO operations_mapping "
            "(account_id, cod_op_service, cod_prestatie, auto_send) VALUES (1,?,?,1)",
            ("OP-FRANE", "R-FRANE"),
        )
        conn.commit()
    finally:
        conn.close()


def _configureaza_un_mediu(client: TestClient, env: str = "test") -> None:
    """Activeaza un singur mediu RAR pe contul 1 (simulate creds disponibile)."""
    from app.db import get_connection
    from app.crypto import encrypt_creds
    conn = get_connection()
    try:
        fake_creds = encrypt_creds({"email": "test@rar.ro", "password": "pass"})
        if env == "test":
            conn.execute(
                "UPDATE accounts SET rar_test_enabled=1, rar_creds_test_enc=?, "
                "rar_prod_enabled=0, rar_creds_prod_enc=NULL, rar_env_default='test' WHERE id=1",
                (fake_creds,),
            )
        else:
            conn.execute(
                "UPDATE accounts SET rar_prod_enabled=1, rar_creds_prod_enc=?, "
                "rar_test_enabled=0, rar_creds_test_enc=NULL, rar_env_default='prod' WHERE id=1",
                (fake_creds,),
            )
        conn.commit()
    finally:
        conn.close()


def _configureaza_doua_medii(client: TestClient, default_env: str = "test") -> None:
    """Activeaza ambele medii RAR pe contul 1."""
    from app.db import get_connection
    from app.crypto import encrypt_creds
    conn = get_connection()
    try:
        fake_test = encrypt_creds({"email": "test@rar.ro", "password": "pass_test"})
        fake_prod = encrypt_creds({"email": "prod@rar.ro", "password": "pass_prod"})
        conn.execute(
            "UPDATE accounts SET "
            "rar_test_enabled=1, rar_creds_test_enc=?, "
            "rar_prod_enabled=1, rar_creds_prod_enc=?, "
            "rar_env_default=? WHERE id=1",
            (fake_test, fake_prod, default_env),
        )
        conn.commit()
    finally:
        conn.close()


_ROWS_OK = [
    {
        "VIN": "WVWZZZ1KZAW009001",
        "Nr": "B009TST",
        "Data": "2026-06-15",
        "KM": "77000",
        "Operatie": "OP-FRANE",
    },
]


def _upload_si_mapare(client: TestClient, rows: list[dict]) -> int:
    """Upload CSV si seteaza mapare coloane. Intoarce import_id."""
    data = _csv_bytes(rows)
    r = client.post(
        "/_import/upload",
        files={"file": ("test.csv", io.BytesIO(data), "text/csv")},
    )
    assert r.status_code == 200, r.text
    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))

    # Seteaza maparea daca nu e deja
    if f"/_import/{iid}/mapare-coloane" in r.text or "mapare-coloane" in r.text.lower():
        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, r2.text

    return iid


def _get_preview(client: TestClient, iid: int) -> str:
    rp = client.get(f"/_import/{iid}/preview")
    assert rp.status_code == 200, rp.text
    return rp.text


def _commit(client: TestClient, iid: int, n_ok: int, rar_env: str | None = None) -> object:
    data = {
        "csrf_token": "",
        "n_confirmat": str(n_ok),
        "confirmed_by": "test@us009.ro",
    }
    if rar_env:
        data["rar_env"] = rar_env
    return client.post(f"/_import/{iid}/confirma", data=data)


# --------------------------------------------------------------------------- #
# Tests                                                                         #
# --------------------------------------------------------------------------- #

def test_selector_ascuns_la_un_mediu(client):
    """La 1 mediu disponibil: nu apare selector; apare eticheta statica cu mediul."""
    _seed_nomenclator_si_mapare(client)
    _configureaza_un_mediu(client, env="test")

    # GET fragment/import: verifica ca nu exista selector si apare eticheta
    r = client.get("/_fragments/import")
    assert r.status_code == 200, r.text
    html = r.text

    # Eticheta statica "Testare" trebuie sa fie prezenta
    assert "Testare" in html, "Eticheta mediu 'Testare' lipseste la 1 mediu disponibil"

    # Selectorul nu trebuie sa apara (input cu name=rar_env hidden, dar fara <select>)
    assert "<select" not in html or 'name="rar_env"' not in html or "rar-env-select" not in html, (
        "Selector mediu RAR nu trebuie sa apara la 1 mediu disponibil"
    )


def test_selector_prezent_si_prebifat_la_doua(client):
    """La 2 medii disponibile: selectorul apare si e pre-bifat pe default-ul contului."""
    _seed_nomenclator_si_mapare(client)
    _configureaza_doua_medii(client, default_env="test")

    r = client.get("/_fragments/import")
    assert r.status_code == 200, r.text
    html = r.text

    # Selectorul trebuie sa apara
    assert "rar-env-select" in html, "Selectorul mediu RAR lipseste la 2 medii disponibile"
    assert 'name="rar_env"' in html, 'Atribut name="rar_env" lipsa din selector'

    # Default pre-selectat = "test" (default contului)
    # Optiunea Testare trebuie sa fie selectata
    assert 'value="test"' in html and "selected" in html, (
        "Optiunea Testare nu e pre-selectata (default cont = test)"
    )


def test_banner_avertisment_la_zero_medii(client):
    """La 0 medii configurate: apare un banner de avertisment (non-blocant)."""
    # Contul 1 implicit nu are medii configurate
    r = client.get("/_fragments/import")
    assert r.status_code == 200, r.text
    html = r.text

    # Banner avertisment sau link catre configurare credentiale
    assert "mediu" in html.lower() or "configureaza" in html.lower() or "credentiale" in html.lower(), (
        "Bannerul de avertisment pentru 0 medii lipseste din pagina de upload"
    )

    # Upload-ul NU e blocat: formularul de upload trebuie sa fie prezent
    assert "upload-form" in html, (
        "Formularul de upload lipseste — la 0 medii upload-ul nu trebuie blocat"
    )


def test_commit_seteaza_env_pe_submissions(client):
    """La commit: submissions primesc rar_env ales (fallback la ancora globala pt 0 medii)."""
    _seed_nomenclator_si_mapare(client)
    # Contul 1 fara medii configurate -> ancora globala = "test"

    iid = _upload_si_mapare(client, _ROWS_OK)
    preview_html = _get_preview(client, iid)

    m_ok = re.search(r'id="n-confirmat"[^>]*?value="(\d+)"', preview_html)
    n_ok = int(m_ok.group(1)) if m_ok else 1

    r = _commit(client, iid, n_ok)
    assert r.status_code == 200, r.text
    assert any(kw in r.text.lower() for kw in ("coada", "prezenta", "trimiter")), (
        "Mesajul de succes lipseste din raspunsul de commit"
    )

    # Verifica ca submission-ul are rar_env setat (fallback "test" via ancora globala)
    from app.db import get_connection
    conn = get_connection()
    try:
        sub = conn.execute(
            "SELECT rar_env FROM submissions WHERE account_id=1 ORDER BY id DESC LIMIT 1"
        ).fetchone()
    finally:
        conn.close()

    assert sub is not None, "Niciun submission gasit dupa commit"
    assert sub["rar_env"] in ("test", "prod"), f"rar_env invalid: {sub['rar_env']!r}"
    # Cu AUTOPASS_RAR_ENV=test si 0 medii configurate, expect "test"
    assert sub["rar_env"] == "test", (
        f"Expected rar_env='test' (ancora globala) dar primit {sub['rar_env']!r}"
    )


def test_commit_cu_un_mediu_seteaza_acel_mediu(client):
    """La commit cu 1 mediu configurat: submission primeste mediul respectiv."""
    _seed_nomenclator_si_mapare(client)
    _configureaza_un_mediu(client, env="test")

    iid = _upload_si_mapare(client, _ROWS_OK)
    preview_html = _get_preview(client, iid)

    m_ok = re.search(r'id="n-confirmat"[^>]*?value="(\d+)"', preview_html)
    n_ok = int(m_ok.group(1)) if m_ok else 1

    r = _commit(client, iid, n_ok)
    assert r.status_code == 200, r.text

    from app.db import get_connection
    conn = get_connection()
    try:
        sub = conn.execute(
            "SELECT rar_env FROM submissions WHERE account_id=1 ORDER BY id DESC LIMIT 1"
        ).fetchone()
    finally:
        conn.close()

    assert sub is not None
    assert sub["rar_env"] == "test", (
        f"Expected rar_env='test' (singurul mediu disponibil) dar primit {sub['rar_env']!r}"
    )


def test_commit_cu_doua_medii_respecta_alegerea(client):
    """La 2 medii: commit cu rar_env explicit seteaza mediul ales pe submissions."""
    _seed_nomenclator_si_mapare(client)
    _configureaza_doua_medii(client, default_env="test")

    iid = _upload_si_mapare(client, _ROWS_OK)
    preview_html = _get_preview(client, iid)

    m_ok = re.search(r'id="n-confirmat"[^>]*?value="(\d+)"', preview_html)
    n_ok = int(m_ok.group(1)) if m_ok else 1

    # Commit explicit pe "prod"
    r = _commit(client, iid, n_ok, rar_env="prod")
    assert r.status_code == 200, r.text

    from app.db import get_connection
    conn = get_connection()
    try:
        sub = conn.execute(
            "SELECT rar_env FROM submissions WHERE account_id=1 ORDER BY id DESC LIMIT 1"
        ).fetchone()
    finally:
        conn.close()

    assert sub is not None
    assert sub["rar_env"] == "prod", (
        f"Expected rar_env='prod' (ales explicit) dar primit {sub['rar_env']!r}"
    )


def test_badge_mediu_in_preview(client):
    """Preview-ul afiseaza badge-ul cu mediul tinta (US-009, F9/F10)."""
    _seed_nomenclator_si_mapare(client)
    _configureaza_un_mediu(client, env="test")

    iid = _upload_si_mapare(client, _ROWS_OK)

    r = client.get(f"/_import/{iid}/preview")
    assert r.status_code == 200, r.text
    html = r.text

    # Badge cu mediul trebuie sa fie prezent in HTML
    assert "Testare" in html or "PRODUCTIE" in html or "rar_env" in html, (
        "Badge-ul de mediu RAR lipseste din preview"
    )


def test_rar_env_in_confirm_form(client):
    """Preview-ul contine un field hidden rar_env in formularul de confirmare."""
    _seed_nomenclator_si_mapare(client)
    _configureaza_un_mediu(client, env="test")

    iid = _upload_si_mapare(client, _ROWS_OK)

    r = client.get(f"/_import/{iid}/preview")
    assert r.status_code == 200, r.text
    html = r.text

    # Formularul de confirmare trebuie sa contina rar_env ca hidden field
    assert 'name="rar_env"' in html, (
        "Campul hidden 'rar_env' lipseste din formularul de confirmare preview"
    )
