"""Teste T9: canonicalize_row + build_key partajat (idempotency).

Verify:
(a) cross-canal: build_key(API canal-None) == build_key(import canal-rezolvat) pentru
    acelasi rand logic.
(b) regresie: strategia cheilor vechi (dual-lookup legacy) acoperita de test.
(c) canonicalize taie ".0" din odometru inainte de validare.
"""

from __future__ import annotations

import os
import tempfile

import pytest

from app.idempotency import (
    build_key,
    build_key_legacy,
    canonicalize_row,
    idempotency_key,
)


# --- canonicalize_row ---

def test_canonicalize_vin_upper():
    raw = {"vin": "wvwzzz1kzaw000123", "nr_inmatriculare": "b999tst",
           "data_prestatie": "2026-06-15", "odometru_final": "123456"}
    c = canonicalize_row(raw)
    assert c["vin"] == "WVWZZZ1KZAW000123"
    assert c["nr_inmatriculare"] == "B999TST"


def test_canonicalize_odometru_strip_dot_zero():
    """123456.0 (Excel float) -> '123456'."""
    raw = {"vin": "X", "nr_inmatriculare": "Y", "data_prestatie": "2026-01-01",
           "odometru_final": "123456.0"}
    c = canonicalize_row(raw)
    assert c["odometru_final"] == "123456"


def test_canonicalize_odometru_numeric_float():
    """Numeric float 123456.0 -> '123456'."""
    raw = {"vin": "X", "nr_inmatriculare": "Y", "data_prestatie": "2026-01-01",
           "odometru_final": 123456.0}
    c = canonicalize_row(raw)
    assert c["odometru_final"] == "123456"


def test_canonicalize_odometru_int_unchanged():
    """Integer 123456 -> '123456' (nu e alterat)."""
    raw = {"vin": "X", "nr_inmatriculare": "Y", "data_prestatie": "2026-01-01",
           "odometru_final": 123456}
    c = canonicalize_row(raw)
    assert c["odometru_final"] == "123456"


def test_canonicalize_odometru_50_unchanged():
    """'123456.50' nu e coercion pur — nu se taie."""
    raw = {"vin": "X", "nr_inmatriculare": "Y", "data_prestatie": "2026-01-01",
           "odometru_final": "123456.50"}
    c = canonicalize_row(raw)
    assert c["odometru_final"] == "123456.50"


def test_canonicalize_odometru_none():
    raw = {"vin": "X", "nr_inmatriculare": "Y", "data_prestatie": "2026-01-01"}
    c = canonicalize_row(raw)
    assert c["odometru_final"] == ""


def test_canonicalize_data_strip():
    raw = {"vin": "X", "nr_inmatriculare": "Y", "data_prestatie": "  2026-06-15  ",
           "odometru_final": "1"}
    c = canonicalize_row(raw)
    assert c["data_prestatie"] == "2026-06-15"


# --- build_key cross-canal (a) ---

_RAND = {
    "vin": "WVWZZZ1KZAW000123",
    "nr_inmatriculare": "B999TST",
    "data_prestatie": "2026-06-15",
    "odometru_final": "123456",
    "prestatii": [{"cod_prestatie": "OE-1"}],
}


def test_cross_canal_none_equals_1():
    """(a) build_key cu account_id=None si account_id=1 dau aceeasi cheie."""
    canon = canonicalize_row(_RAND)
    k_none = build_key(None, canon)
    k_1 = build_key(1, canon)
    assert k_none == k_1, "cross-canal divergenta: None vs 1"


def test_cross_canal_odometru_float():
    """Odometru float din Excel: cheia e identica indiferent de canal."""
    rand_float = {**_RAND, "odometru_final": "123456.0"}
    rand_int = {**_RAND, "odometru_final": "123456"}
    k_float_api = build_key(None, canonicalize_row(rand_float))
    k_int_import = build_key(1, canonicalize_row(rand_int))
    assert k_float_api == k_int_import, "float vs int odometru -> chei diferite"


# --- idempotency_key wrapper ---

def test_idempotency_key_backward_compat():
    """idempotency_key(None, raw) produce aceeasi cheie ca build_key(None, canon)."""
    canon = canonicalize_row(_RAND)
    k_new = build_key(None, canon)
    k_old = idempotency_key(None, _RAND)
    assert k_new == k_old


# --- build_key_legacy (b) ---

def test_legacy_key_differs_from_new():
    """(b) Cheia legacy (account_id=None in hash) difera de cheia noua (account_id=1)."""
    canon = canonicalize_row(_RAND)
    k_new = build_key(None, canon)  # None -> 1 in hash
    k_legacy = build_key_legacy(None, _RAND)  # None AS-PASSED in hash
    assert k_new != k_legacy, "legacy si new trebuie sa difere (diferit account_id in hash)"


def test_legacy_dual_lookup_strategy():
    """Strategia dual-lookup: row-uri vechi (cheie-None) gasite via build_key_legacy."""
    # Simuleaza un rand cu cheie veche (account_id=None in hash)
    old_key = build_key_legacy(None, _RAND)
    # Noul build_key (None->1) NU gaseste randul direct
    new_key = build_key(None, canonicalize_row(_RAND))
    assert new_key != old_key
    # Dual-lookup: incearca noul, apoi legacy
    found = old_key in {old_key} or new_key in {old_key}
    assert found, "dual-lookup trebuie sa gaseasca randul vechi"


# --- Integrare: API route foloseste build_key (OV-2) ---

@pytest.fixture()
def client(monkeypatch):
    tmp = tempfile.mkdtemp()
    monkeypatch.setenv("AUTOPASS_DB_PATH", os.path.join(tmp, "t9.db"))
    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 _body(**over):
    prez = {
        "vin": "WVWZZZ1KZAW000123",
        "nr_inmatriculare": "B999TST",
        "data_prestatie": "2026-06-15",
        "odometru_final": "123456",
        "prestatii": [{"cod_prestatie": "OE-1"}],
    }
    prez.update(over)
    return {"rar_credentials": {"email": "x@y.ro", "password": "s"}, "prezentari": [prez]}


def test_api_dedup_dupa_t9(client):
    """Deduplicarea functioneaza dupa T9: acelasi rand -> acelasi submission."""
    r1 = client.post("/v1/prezentari", json=_body())
    r2 = client.post("/v1/prezentari", json=_body())
    assert r1.status_code == 200
    sid1 = r1.json()["results"][0]["submission_id"]
    res2 = r2.json()["results"][0]
    assert res2["submission_id"] == sid1
    assert res2["deduped"] is True


def test_api_odometru_float_dedup(client):
    """Odometru float '123456.0' si '123456' dedup corect dupa canonicalizare."""
    r1 = client.post("/v1/prezentari", json=_body(odometru_final="123456"))
    r2 = client.post("/v1/prezentari", json=_body(odometru_final="123456.0"))
    assert r1.status_code == 200
    sid1 = r1.json()["results"][0]["submission_id"]
    res2 = r2.json()["results"][0]
    assert res2["submission_id"] == sid1, "odometru float si int trebuie sa dea acelasi submission"
    assert res2["deduped"] is True
