"""Teste flux mapare operatie inline in preview (import web in staging).

Acopera gap-ul: operatiile nemapate dintr-un import in staging nu aveau unde sa
fie mapate din UI (editorul "Mapari de rezolvat" citea doar din submissions
comise, iar commit-ul arunca randurile needs_mapping). Acum:
  - camp canonic nou `denumire_op`: coloana descriptiva alimenteaza denumirea
    operatiei -> sugestia fuzzy devine utila (nu codul opac);
  - preview-ul expune `unmapped_ops` + panou inline de mapare;
  - POST /_import/{id}/mapare-operatie salveaza maparea (persistenta) si
    re-rezolva preview-ul -> randurile trec din needs_mapping in ok, fara re-upload.
"""

from __future__ import annotations

import csv as csv_mod
import io
import os
import re
import tempfile

import pytest


@pytest.fixture()
def client(monkeypatch):
    tmp = tempfile.mkdtemp()
    monkeypatch.setenv("AUTOPASS_DB_PATH", os.path.join(tmp, "t.db"))
    # Mod dev: fallback cont 1, fara login/CSRF (ca in test_import_ui).
    monkeypatch.setenv("AUTOPASS_WEB_AUTH_REQUIRED", "false")
    from app.config import get_settings

    get_settings.cache_clear()
    from app.main import app
    from fastapi.testclient import TestClient

    with TestClient(app) as c:
        yield c
    get_settings.cache_clear()


_HEADER = ["VIN", "Nr inmatriculare", "Data prestatie", "Odometru final", "Cod operatie", "Denumire"]
# Cod intern opac + descriere lizibila care se potriveste cu nomenclatorul RAR
# (OE-3 = "REVIZIE PERIODICA"; fuzzy "Revizie periodica" -> OE-3 la 100%).
_ROWS = [
    ["WVWZZZ1KZAW001111", "B100TST", "2026-06-15", "123456", "OP-REV", "Revizie periodica"],
    ["WVWZZZ1KZAW002222", "CJ200AB", "2026-05-20", "98765", "OP-REV", "Revizie periodica"],
]
_CANON = ["vin", "nr_inmatriculare", "data_prestatie", "odometru_final", "operatie", "denumire_op"]


def _csv_bytes(header, rows, sep=";") -> bytes:
    buf = io.StringIO()
    w = csv_mod.writer(buf, delimiter=sep)
    w.writerow(header)
    for r in rows:
        w.writerow(r)
    return buf.getvalue().encode("utf-8")


def _upload(client, header=_HEADER, rows=None) -> int:
    rows = _ROWS if rows is None else rows
    r = client.post(
        "/_import/upload",
        files={"file": ("t.csv", _csv_bytes(header, rows), "text/csv")},
    )
    assert r.status_code == 200, r.text
    m = re.search(r"/_import/(\d+)/mapare-coloane", r.text)
    assert m, f"form mapare-coloane lipsa: {r.text[:300]}"
    return int(m.group(1))


def _map_columns(client, import_id, canon=None):
    return client.post(
        f"/_import/{import_id}/mapare-coloane",
        data={
            "colname": _HEADER,
            "canon": canon or _CANON,
            "format_data": "YYYY-MM-DD",
        },
    )


# --------------------------------------------------------------------------- #
# 1. denumire_op alimenteaza denumirea -> sugestie fuzzy utila                 #
# --------------------------------------------------------------------------- #

def test_denumire_op_alimenteaza_denumirea_si_sugestia(client):
    import_id = _upload(client)
    _map_columns(client, import_id)

    from app.db import get_connection
    from app.web.routes import _web_compute_preview

    conn = get_connection()
    try:
        result = _web_compute_preview(conn, import_id, account_id=1)
    finally:
        conn.close()

    assert not isinstance(result, str), result
    ops = result["unmapped_ops"]
    assert len(ops) == 1, ops
    op = ops[0]
    assert op["cod_op_service"] == "OP-REV"
    # Cheia: denumirea e descrierea reala, NU codul opac.
    assert op["denumire"] == "Revizie periodica"
    assert op["blocked"] == 2
    # Sugestia fuzzy gaseste OE-3 (REVIZIE PERIODICA) sus, cu scor real.
    assert op["suggestions"], "fara sugestii"
    top = op["suggestions"][0]
    assert top["cod_prestatie"] == "OE-3"
    assert top["score"] >= 60


def test_fara_denumire_op_denumirea_e_codul(client):
    """Control: daca NU mapezi coloana descriptiva, denumirea ramane codul opac."""
    import_id = _upload(client)
    # operatie mapat, descrierea ignorata
    _map_columns(client, import_id, canon=[
        "vin", "nr_inmatriculare", "data_prestatie", "odometru_final", "operatie", "",
    ])

    from app.db import get_connection
    from app.web.routes import _web_compute_preview

    conn = get_connection()
    try:
        result = _web_compute_preview(conn, import_id, account_id=1)
    finally:
        conn.close()

    op = result["unmapped_ops"][0]
    assert op["denumire"] == "OP-REV"  # fara denumire_op -> codul


# --------------------------------------------------------------------------- #
# 2. Preview expune panoul inline                                             #
# --------------------------------------------------------------------------- #

def test_preview_arata_panoul_de_mapare(client):
    import_id = _upload(client)
    r = _map_columns(client, import_id)
    assert r.status_code == 200
    assert "Operatii de mapat la cod RAR" in r.text
    assert "OP-REV" in r.text
    # US-004: panoul foloseste ruta plurala (un singur form pentru toate operatiile)
    assert "/_import/%d/mapare-operatii" % import_id in r.text


# --------------------------------------------------------------------------- #
# 3. POST mapare-operatie deblocheaza randurile (needs_mapping -> ok)          #
# --------------------------------------------------------------------------- #

def test_mapare_operatie_deblocheaza_randurile(client):
    import_id = _upload(client)
    r = _map_columns(client, import_id)
    assert "needs_mapping" in r.text

    # Inainte: 2 needs_mapping, 0 ok
    from app.db import get_connection
    conn = get_connection()
    try:
        b = conn.execute(
            "SELECT ok, needs_mapping FROM import_batches WHERE id=?", (import_id,)
        ).fetchone()
        assert (b["ok"], b["needs_mapping"]) == (0, 2)
    finally:
        conn.close()

    # Mapeaza OP-REV -> OE-3 (auto_send)
    rm = client.post(f"/_import/{import_id}/mapare-operatie", data={
        "cod_op_service": "OP-REV",
        "cod_prestatie": "OE-3",
        "auto_send": "true",
    })
    assert rm.status_code == 200, rm.text
    # Preview re-randat: randurile sunt acum ok, panoul a disparut
    assert "2 gata de trimis" in rm.text or "s-ok" in rm.text
    assert f"/_import/{import_id}/mapare-operatie" not in rm.text

    conn = get_connection()
    try:
        b = conn.execute(
            "SELECT ok, needs_mapping FROM import_batches WHERE id=?", (import_id,)
        ).fetchone()
        assert (b["ok"], b["needs_mapping"]) == (2, 0), dict(b)
        # Maparea s-a persistat (operations_mapping)
        m = conn.execute(
            "SELECT cod_prestatie, auto_send FROM operations_mapping "
            "WHERE account_id=1 AND cod_op_service='OP-REV'"
        ).fetchone()
        assert m is not None and m["cod_prestatie"] == "OE-3" and m["auto_send"] == 1
        # import_rows reflecta noua stare (commit-ul citeste de aici)
        statuses = {
            row["resolved_status"]
            for row in conn.execute(
                "SELECT resolved_status FROM import_rows WHERE batch_id=?", (import_id,)
            )
        }
        assert statuses == {"ok"}, statuses
    finally:
        conn.close()


def test_mapare_operatie_cod_necunoscut_nu_salveaza(client):
    import_id = _upload(client)
    _map_columns(client, import_id)

    rm = client.post(f"/_import/{import_id}/mapare-operatie", data={
        "cod_op_service": "OP-REV",
        "cod_prestatie": "NUEXISTA",
        "auto_send": "true",
    })
    assert rm.status_code == 200
    assert "necunoscut" in rm.text.lower()
    # Inca needs_mapping, nimic salvat
    assert "Operatii de mapat la cod RAR" in rm.text

    from app.db import get_connection
    conn = get_connection()
    try:
        m = conn.execute(
            "SELECT 1 FROM operations_mapping WHERE cod_op_service='OP-REV'"
        ).fetchone()
        assert m is None
    finally:
        conn.close()


# --------------------------------------------------------------------------- #
# 4. A doua incarcare: maparea retinuta -> direct ok (zero config)            #
# --------------------------------------------------------------------------- #

def test_a_doua_incarcare_foloseste_maparea_retinuta(client):
    # Prima incarcare + mapare coloane + mapare operatie
    import_id = _upload(client)
    _map_columns(client, import_id)
    client.post(f"/_import/{import_id}/mapare-operatie", data={
        "cod_op_service": "OP-REV", "cod_prestatie": "OE-3", "auto_send": "true",
    })

    # A doua incarcare acelasi antet -> preview direct, fara operatii de mapat
    r = client.post(
        "/_import/upload",
        files={"file": ("t2.csv", _csv_bytes(_HEADER, _ROWS), "text/csv")},
    )
    assert r.status_code == 200, r.text
    assert "/mapare-operatie" not in r.text
    assert "gata de trimis" in r.text
