"""Teste UI web import (U5) — upload → mapare coloane → preview → confirmare.

Verifica:
  - Dashboard randeaza sectiunea de upload
  - Upload xlsx → mapare noua → fragment _mapcoloane returnat
  - Upload xlsx cu mapare existenta → preview direct
  - Salvare mapare coloane → preview randat
  - Preview afiseaza rezumat stari si randul tabelului
  - Confirmare cu N corect → succes (in coada)
  - Confirmare cu N gresit → eroare explicita
  - Reset → drop zone gol
  - Erori upload (fisier invalid, prea mare, header neclar)
  - Sheet selector la multi-sheet xlsx
"""

from __future__ import annotations

import io
import os
import tempfile

import pytest


@pytest.fixture()
def client(monkeypatch):
    tmp = tempfile.mkdtemp()
    monkeypatch.setenv("AUTOPASS_DB_PATH", os.path.join(tmp, "t.db"))
    # Comportament in mod dev (fallback cont 1, fara login/CSRF); auth web e
    # default ON in prod — testat separat in test_web_*.
    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()


def _make_xlsx_bytes(rows: list[dict]) -> bytes:
    """Construieste un xlsx minimal cu openpyxl pentru fixture teste."""
    openpyxl = pytest.importorskip("openpyxl")
    wb = openpyxl.Workbook()
    ws = wb.active
    if not rows:
        return b""
    headers = list(rows[0].keys())
    ws.append(headers)
    for row in rows:
        ws.append([row.get(h) for h in headers])
    buf = io.BytesIO()
    wb.save(buf)
    return buf.getvalue()


def _make_csv_bytes(rows: list[dict], sep: str = ";") -> bytes:
    """Construieste un CSV minimal pentru fixture teste."""
    import csv
    import io

    buf = io.StringIO()
    if not rows:
        return b""
    writer = csv.DictWriter(buf, fieldnames=list(rows[0].keys()), delimiter=sep)
    writer.writeheader()
    writer.writerows(rows)
    return buf.getvalue().encode("utf-8")


_SAMPLE_ROWS = [
    {
        "VIN": "WVWZZZ1KZAW000123",
        "Nr inmatriculare": "B001TST",
        "Data prestatie": "15.06.2026",
        "Odometru final": "123456",
        "Operatie": "Revizie",
    },
    {
        "VIN": "WVWZZZ1KZAW000456",
        "Nr inmatriculare": "B002TST",
        "Data prestatie": "16.06.2026",
        "Odometru final": "200000",
        "Operatie": "Revizie",
    },
]


def _seed_op_mapping(client, cod_op: str = "Revizie", cod_prest: str = "OE-1") -> None:
    """Seeda o mapare de operatii cod_op → cod_prestatie via API."""
    client.post("/v1/mapari", json={
        "cod_op_service": cod_op,
        "cod_prestatie": cod_prest,
        "auto_send": True,
    })


# --------------------------------------------------------------------------- #
# Dashboard                                                                    #
# --------------------------------------------------------------------------- #

def test_dashboard_contine_drop_zone(client):
    """Tab-ul Import randeaza sectiunea de upload cu drop zone si mesaj warmth.

    Dupa US-003 sectiunea de import e in tab-ul Import (?tab=import), nu pe pagina principala.
    """
    r = client.get("/?tab=import")
    assert r.status_code == 200
    assert "Primul fisier" in r.text
    assert "drop-zone" in r.text
    assert "NU se trimite nimic" in r.text
    assert "import-section" in r.text


# --------------------------------------------------------------------------- #
# Upload xlsx — mapare noua                                                    #
# --------------------------------------------------------------------------- #

def test_upload_xlsx_fara_mapare_arata_formular_mapare(client):
    """Upload xlsx fara mapare salvata → fragment mapare coloane."""
    xlsx = _make_xlsx_bytes(_SAMPLE_ROWS)
    r = client.post(
        "/_import/upload",
        files={"file": ("test.xlsx", xlsx, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")},
    )
    assert r.status_code == 200
    # Formular de mapare coloane
    assert "Mapare coloane" in r.text
    assert "mapare-coloane" in r.text  # URL in form action
    # Coloanele din fisier apar in formular
    assert "VIN" in r.text
    assert "Data prestatie" in r.text
    # Sugestii fuzzy pentru VIN
    assert "vin" in r.text.lower()


def test_upload_csv_fara_mapare_arata_formular_mapare(client):
    """Upload CSV cu separator ; → formular mapare coloane."""
    csv_bytes = _make_csv_bytes(_SAMPLE_ROWS)
    r = client.post(
        "/_import/upload",
        files={"file": ("test.csv", csv_bytes, "text/csv")},
    )
    assert r.status_code == 200
    assert "Mapare coloane" in r.text


# --------------------------------------------------------------------------- #
# Salvare mapare coloane → preview                                             #
# --------------------------------------------------------------------------- #

def _upload_and_get_import_id(client, rows=None) -> int:
    """Helper: incarca fisier si extrage import_id din raspuns."""
    xlsx = _make_xlsx_bytes(rows or _SAMPLE_ROWS)
    r = client.post(
        "/_import/upload",
        files={"file": ("test.xlsx", xlsx, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")},
    )
    assert r.status_code == 200
    # Extrage import_id din URL-ul form action din raspuns
    text = r.text
    # Form action contine /_import/{id}/mapare-coloane
    import re
    m = re.search(r"/_import/(\d+)/mapare-coloane", text)
    assert m, f"Nu s-a gasit import_id in raspuns: {text[:500]}"
    return int(m.group(1))


def test_salvare_mapare_coloane_arata_preview(client):
    """Dupa salvarea maparii de coloane, raspunsul contine preview-ul."""
    # Asigura ca nomenclatorul are OE-1 (seeding automat la init_db)
    import_id = _upload_and_get_import_id(client)

    r = client.post(
        f"/_import/{import_id}/mapare-coloane",
        data={
            "colname":      ["VIN", "Nr inmatriculare", "Data prestatie", "Odometru final", "Operatie"],
            "canon":        ["vin", "nr_inmatriculare", "data_prestatie", "odometru_final", "operatie"],
            "format_data":  "DD.MM.YYYY",
        },
    )
    assert r.status_code == 200
    # Preview trebuie sa contina elementele cheie
    assert "Preview" in r.text
    assert "confirm-form" in r.text
    assert "n-confirmat" in r.text
    # Rezumat stari
    assert "gata de trimis" in r.text or "ok" in r.text


def test_preview_arata_randul_vin(client):
    """Preview contine VIN-ul din fisier."""
    import_id = _upload_and_get_import_id(client)
    client.post(
        f"/_import/{import_id}/mapare-coloane",
        data={
            "colname":     ["VIN", "Nr inmatriculare", "Data prestatie", "Odometru final", "Operatie"],
            "canon":       ["vin", "nr_inmatriculare", "data_prestatie", "odometru_final", "operatie"],
            "format_data": "DD.MM.YYYY",
        },
    )
    r = client.get(f"/_import/{import_id}/preview")
    assert r.status_code == 200
    assert "WVWZZZ1KZAW000123" in r.text


# --------------------------------------------------------------------------- #
# Upload cu mapare existenta → preview direct                                  #
# --------------------------------------------------------------------------- #

def test_upload_cu_mapare_existenta_sare_direct_la_preview(client):
    """Al doilea upload cu acelasi antet → preview imediat (mapare retinuta)."""
    # Primul upload + salvare mapare
    import_id1 = _upload_and_get_import_id(client)
    client.post(
        f"/_import/{import_id1}/mapare-coloane",
        data={
            "colname":     ["VIN", "Nr inmatriculare", "Data prestatie", "Odometru final", "Operatie"],
            "canon":       ["vin", "nr_inmatriculare", "data_prestatie", "odometru_final", "operatie"],
            "format_data": "DD.MM.YYYY",
        },
    )

    # Al doilea upload cu acelasi antet
    xlsx = _make_xlsx_bytes(_SAMPLE_ROWS)
    r = client.post(
        "/_import/upload",
        files={"file": ("test2.xlsx", xlsx, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")},
    )
    assert r.status_code == 200
    # Trebuie sa ajunga direct la preview, nu la mapare
    assert "Preview" in r.text
    assert "confirm-form" in r.text
    assert "Mapare retinuta aplicata automat" in r.text


# --------------------------------------------------------------------------- #
# Confirmare (gate HARD)                                                       #
# --------------------------------------------------------------------------- #

def _setup_preview(client) -> int:
    """Upload + mapare + seeda operatii + intoarce import_id gata de confirmare."""
    _seed_op_mapping(client)  # "Revizie" → "OE-1"
    import_id = _upload_and_get_import_id(client)
    client.post(
        f"/_import/{import_id}/mapare-coloane",
        data={
            "colname":     ["VIN", "Nr inmatriculare", "Data prestatie", "Odometru final", "Operatie"],
            "canon":       ["vin", "nr_inmatriculare", "data_prestatie", "odometru_final", "operatie"],
            "format_data": "DD.MM.YYYY",
        },
    )
    return import_id


def test_confirmare_n_corect_pune_in_coada(client):
    """Confirmare cu N corect → randurile ok ajung in coada."""
    import_id = _setup_preview(client)

    # Compute preview pentru a afla n_ok
    r_prev = client.get(f"/_import/{import_id}/preview")
    assert r_prev.status_code == 200

    # Citeste summary din DB
    from app.db import get_connection

    conn = get_connection()
    try:
        batch = conn.execute(
            "SELECT ok FROM import_batches WHERE id=?", (import_id,)
        ).fetchone()
        n_ok = batch["ok"]
    finally:
        conn.close()

    assert n_ok > 0, "Asteptat cel putin un rand ok dupa seeding corect"

    r = client.post(
        f"/_import/{import_id}/confirma",
        data={"n_confirmat": str(n_ok), "confirmed_by": "test@test.ro"},
    )
    assert r.status_code == 200
    # Succes → drop zone cu mesaj
    assert "S-au pus in coada" in r.text or "prezentari" in r.text
    # Sectiunea se reseteaza la drop zone
    assert "drop-zone" in r.text

    # Verifica ca submissions au fost create
    conn2 = get_connection()
    try:
        n = conn2.execute(
            "SELECT COUNT(*) FROM submissions WHERE batch_id=?", (import_id,)
        ).fetchone()[0]
        assert n == n_ok, f"Asteptat {n_ok} submissions, gasit {n}"
    finally:
        conn2.close()


def test_confirmare_n_gresit_arata_eroare(client):
    """Confirmare cu N gresit → eroare clara, nu enqueue."""
    import_id = _setup_preview(client)
    client.get(f"/_import/{import_id}/preview")  # calculeaza si stocheaza starea

    r = client.post(
        f"/_import/{import_id}/confirma",
        data={"n_confirmat": "99", "confirmed_by": ""},
    )
    assert r.status_code == 200
    # Trebuie sa arate eroare de confirmare sau preview cu eroare
    assert (
        "difera" in r.text
        or "Numarul confirmat" in r.text
        or "Niciun rand ok" in r.text
    )


# --------------------------------------------------------------------------- #
# Reset                                                                        #
# --------------------------------------------------------------------------- #

def test_reset_arata_drop_zone_gol(client):
    """GET /_import/reset → drop zone gol fara mesaje."""
    r = client.get("/_import/reset")
    assert r.status_code == 200
    assert "drop-zone" in r.text
    assert "Primul fisier" in r.text
    assert "import-section" in r.text


# --------------------------------------------------------------------------- #
# Erori upload                                                                 #
# --------------------------------------------------------------------------- #

def test_upload_fisier_invalid_arata_eroare(client):
    """Upload fisier invalid → mesaj de eroare in drop zone."""
    r = client.post(
        "/_import/upload",
        files={"file": ("test.xlsx", b"not a real xlsx file", "application/octet-stream")},
    )
    assert r.status_code == 200
    # Trebuie sa arate drop zone cu eroare
    assert "drop-zone" in r.text or "import-section" in r.text
    # Eroare vizibila
    assert "nerecunoscut" in r.text.lower() or "invalid" in r.text.lower() or "eroare" in r.text.lower()


def test_upload_fisier_csv_antet_o_coloana_arata_eroare(client):
    """CSV cu o singura coloana reala → header acceptat sau eroare gestionata."""
    bad = b"date_fara_header\nval1\nval2\n"
    r = client.post(
        "/_import/upload",
        files={"file": ("test.csv", bad, "text/csv")},
    )
    # Fie detecteaza header OK fie arata eroare
    assert r.status_code == 200
    assert "import-section" in r.text


# --------------------------------------------------------------------------- #
# Multi-sheet xlsx                                                             #
# --------------------------------------------------------------------------- #

def test_upload_multi_sheet_arata_selector(client):
    """xlsx cu mai multe foi → selector de foaie in drop zone."""
    openpyxl = pytest.importorskip("openpyxl")
    wb = openpyxl.Workbook()
    ws1 = wb.active
    ws1.title = "Date"
    ws1.append(["VIN", "Data"])
    ws1.append(["WVW001", "15.06.2026"])
    ws2 = wb.create_sheet("Raport")
    ws2.append(["Total"])
    ws2.append(["1"])
    buf = io.BytesIO()
    wb.save(buf)
    xlsx = buf.getvalue()

    r = client.post(
        "/_import/upload",
        files={"file": ("multi.xlsx", xlsx, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")},
    )
    assert r.status_code == 200
    # Trebuie sa arate selector de foi
    assert "foi" in r.text.lower() or "sheet" in r.text.lower() or "foaie" in r.text.lower()
    # Foile trebuie sa apara ca optiuni
    assert "Date" in r.text or "Raport" in r.text


# --------------------------------------------------------------------------- #
# Elemente a11y (D10/D11/D12)                                                 #
# --------------------------------------------------------------------------- #

def test_preview_contine_banner_declarant(client):
    """Preview contine bannerul declarant (D12) cu text despre ireversibil."""
    import_id = _setup_preview(client)
    r = client.get(f"/_import/{import_id}/preview")
    assert r.status_code == 200
    assert "declarantul" in r.text
    assert "ireversibil" in r.text
    assert "banner" in r.text


def test_preview_contine_checkboxuri_needs_review(client):
    """Randurile needs_review au checkbox 'verificat' (D11)."""
    # Cream un rand cu VIN numeric → needs_review
    rows_with_review = [
        {
            "VIN": "1234567890",  # VIN numeric → coercion flag → needs_review
            "Nr inmatriculare": "B001TST",
            "Data prestatie": "15.06.2026",
            "Odometru final": "123456",
            "Operatie": "OE-1",
        }
    ]
    import_id = _upload_and_get_import_id(client, rows=rows_with_review)
    client.post(
        f"/_import/{import_id}/mapare-coloane",
        data={
            "colname":     ["VIN", "Nr inmatriculare", "Data prestatie", "Odometru final", "Operatie"],
            "canon":       ["vin", "nr_inmatriculare", "data_prestatie", "odometru_final", "operatie"],
            "format_data": "DD.MM.YYYY",
        },
    )
    r = client.get(f"/_import/{import_id}/preview")
    assert r.status_code == 200
    # Checkbox reviewed_rows prezent pentru randul needs_review
    assert "reviewed_rows" in r.text
    assert "needs_review" in r.text


def test_preview_duplicate_in_file_are_text(client):
    """Randurile duplicate_in_file arata text 'dubla cu randul N' (D10 — nu doar culoare)."""
    _seed_op_mapping(client, "Revizie", "OE-1")
    # Doua randuri identice → duplicate_in_file
    dup_rows = [
        {"VIN": "WVWZZZ1KZAW000123", "Nr inmatriculare": "B001TST",
         "Data prestatie": "15.06.2026", "Odometru final": "123456", "Operatie": "Revizie"},
        {"VIN": "WVWZZZ1KZAW000123", "Nr inmatriculare": "B001TST",
         "Data prestatie": "15.06.2026", "Odometru final": "123456", "Operatie": "Revizie"},
    ]
    import_id = _upload_and_get_import_id(client, rows=dup_rows)
    client.post(
        f"/_import/{import_id}/mapare-coloane",
        data={
            "colname":     ["VIN", "Nr inmatriculare", "Data prestatie", "Odometru final", "Operatie"],
            "canon":       ["vin", "nr_inmatriculare", "data_prestatie", "odometru_final", "operatie"],
            "format_data": "DD.MM.YYYY",
        },
    )
    r = client.get(f"/_import/{import_id}/preview")
    assert r.status_code == 200
    # Text explicit pentru duplicate_in_file (nu doar culoare — cerinta daltonism D10)
    assert "dubla cu randul" in r.text
    assert "duplicate_in_file" in r.text
