"""Teste US-003 — tab "Integrare" (hub documentatie + exemple cod).

TDD: testele se scriu INAINTE de implementare; la inceput pica (RED),
dupa implementare trec (GREEN).

Rute testate:
- GET / -> tab-bar contine tab "Integrare"
- GET /?tab=integrare -> panou randat server-side
- GET /_fragments/integrare -> fragment HTMX cu require_login
"""

from __future__ import annotations

import os
import re
import tempfile

import pytest
from starlette.testclient import TestClient


# =========================================================================== #
# Helpers comune                                                               #
# =========================================================================== #

def _create_account_user(email: str, password: str = "parolasecreta10"):
    """Creeaza cont + user. Intoarce (acct_id, user_id)."""
    from app.accounts import create_account
    from app.users import create_user
    from app.db import get_connection

    conn = get_connection()
    try:
        acct_id = create_account(conn, "Service Test Integrare", active=True)
        user_id = create_user(conn, acct_id, email, password)
        return acct_id, user_id
    finally:
        conn.close()


def _login(client, email: str, password: str = "parolasecreta10") -> None:
    """Autentificare HTTP; seteaza cookie de sesiune pe client."""
    resp = client.get("/login")
    m = re.search(r'name="csrf_token"\s+value="([^"]+)"', resp.text) or \
        re.search(r'value="([^"]+)"\s+name="csrf_token"', resp.text)
    assert m, "csrf_token negasit pe /login"
    resp = client.post("/login", data={
        "email": email,
        "parola": password,
        "csrf_token": m.group(1),
    })
    assert resp.status_code == 303, f"Login esuat: {resp.status_code} {resp.text[:200]}"


def _add_creds(acct_id: int) -> None:
    """Adauga credentiale RAR criptate pe cont (pentru test are_creds=True)."""
    from app.db import get_connection
    from app.crypto import encrypt_creds

    conn = get_connection()
    try:
        creds_enc = encrypt_creds({"email": "test@rar.ro", "password": "secret"})
        conn.execute(
            "UPDATE accounts SET rar_creds_enc=? WHERE id=?",
            (creds_enc, acct_id),
        )
        conn.commit()
    finally:
        conn.close()


def _add_api_key(acct_id: int) -> str:
    """Adauga o cheie API activa pe cont. Intoarce cheia bruta."""
    from app.db import get_connection
    from app.auth import create_api_key

    conn = get_connection()
    try:
        key = create_api_key(conn, acct_id)
        return key
    finally:
        conn.close()


@pytest.fixture()
def client(monkeypatch):
    """Client cu BD izolata si autentificare web activata."""
    tmp = tempfile.mkdtemp()
    monkeypatch.setenv("AUTOPASS_DB_PATH", os.path.join(tmp, "integrare_test.db"))
    monkeypatch.setenv("AUTOPASS_WEB_AUTH_REQUIRED", "true")
    from app.config import get_settings
    get_settings.cache_clear()
    from app.web import ratelimit
    ratelimit._hits.clear()
    from app.main import app
    with TestClient(app, follow_redirects=False) as c:
        yield c
    ratelimit._hits.clear()
    get_settings.cache_clear()


# =========================================================================== #
# test_tab_integrare_in_nav                                                    #
# =========================================================================== #

def test_tab_integrare_in_nav(client):
    """Tab-bar-ul principal contine link-ul catre tab-ul Integrare."""
    _create_account_user("nav_integrare@test.com")
    _login(client, "nav_integrare@test.com")

    resp = client.get("/")
    assert resp.status_code == 200
    html = resp.text
    # Trebuie sa existe un link sau buton cu ?tab=integrare
    assert "tab=integrare" in html, "tab-ul 'integrare' lipseste din tab-bar"
    # Textul "Integrare" vizibil
    assert "Integrare" in html


# =========================================================================== #
# test_deeplink_tab_integrare_randeaza_panou_server_side                       #
# =========================================================================== #

def test_deeplink_tab_integrare_randeaza_panou_server_side(client):
    """GET /?tab=integrare randeaza panoul server-side (nu redirectioneaza)."""
    _create_account_user("deeplink_integrare@test.com")
    _login(client, "deeplink_integrare@test.com")

    resp = client.get("/?tab=integrare")
    assert resp.status_code == 200
    html = resp.text
    # Panoul trebuie sa contina continut specific integrare
    # (nu sa cada pe Acasa din cauza unui tab invalid)
    assert "integrare" in html.lower()
    # tab-ul activ trebuie sa fie "integrare"
    assert 'aria-selected="true"' in html or "tab-activ" in html


# =========================================================================== #
# test_fragment_integrare_necesita_login                                       #
# =========================================================================== #

def test_fragment_integrare_necesita_login(client):
    """GET /_fragments/integrare fara sesiune redirectioneaza la /login (require_login)."""
    # Fara login -> trebuie 303 catre /login
    resp = client.get("/_fragments/integrare")
    assert resp.status_code == 303
    assert "/login" in resp.headers.get("location", "")


# =========================================================================== #
# test_pagina_contine_account_id_si_endpoint_real                              #
# =========================================================================== #

def test_pagina_contine_account_id_si_endpoint_real(client):
    """Panoul Integrare afiseaza account_id-ul contului si URL-ul real al endpoint-ului."""
    acct_id, _ = _create_account_user("endpoint_real@test.com")
    _login(client, "endpoint_real@test.com")

    resp = client.get("/_fragments/integrare")
    assert resp.status_code == 200
    html = resp.text
    # account_id trebuie sa apara in pagina
    assert str(acct_id) in html
    # endpoint-ul /v1/prezentari trebuie sa apara
    assert "/v1/prezentari" in html


# =========================================================================== #
# test_pagina_are_tab_limbaje_si_vfp_cu_dialecte                               #
# =========================================================================== #

def test_pagina_are_tab_limbaje_si_vfp_cu_dialecte(client):
    """Panoul Integrare are tab-uri pentru limbaje si VFP are sub-tab-uri (dialecte)."""
    _create_account_user("limbaje@test.com")
    _login(client, "limbaje@test.com")

    resp = client.get("/_fragments/integrare")
    assert resp.status_code == 200
    html = resp.text
    # Limbajele principale trebuie sa fie prezente
    for limbaj in ("curl", "Python", "PHP"):
        assert limbaj in html, f"Limbajul '{limbaj}' lipseste din panoul Integrare"
    # VFP (Visual FoxPro) trebuie sa fie prezent
    assert "VFP" in html or "FoxPro" in html or "Visual Fox" in html
    # Dialectele VFP
    assert "MSXML2" in html or "MSXML" in html
    assert "WinHttp" in html


# =========================================================================== #
# test_canal_secundar_prezentari_si_import                                     #
# =========================================================================== #

def test_canal_secundar_prezentari_si_import(client):
    """Fiecare limbaj are sectiuni pentru canalele Prezentari JSON si Import fisier."""
    _create_account_user("canal_sec@test.com")
    _login(client, "canal_sec@test.com")

    resp = client.get("/_fragments/integrare")
    assert resp.status_code == 200
    html = resp.text
    # Ambele canale trebuie sa fie vizibile in pagina
    assert "prezentari" in html.lower() or "/v1/prezentari" in html
    assert "import" in html.lower() or "/v1/import" in html


# =========================================================================== #
# test_export_card_openapi_postman_swagger                                     #
# =========================================================================== #

def test_export_card_openapi_postman_swagger(client):
    """Panoul Integrare are card cu linkuri: /docs, /openapi.json, postman.json."""
    _create_account_user("export_card@test.com")
    _login(client, "export_card@test.com")

    resp = client.get("/_fragments/integrare")
    assert resp.status_code == 200
    html = resp.text
    # Linkuri de referinta
    assert "/docs" in html
    assert "/openapi.json" in html
    assert "postman" in html.lower()


# =========================================================================== #
# test_buton_copiaza_citeste_din_pre_code                                      #
# =========================================================================== #

def test_buton_copiaza_citeste_din_pre_code(client):
    """Snippet-urile au buton 'Copiaza' care citeste din <pre><code> (nu din data-*)."""
    _create_account_user("copiaza@test.com")
    _login(client, "copiaza@test.com")

    resp = client.get("/_fragments/integrare")
    assert resp.status_code == 200
    html = resp.text
    # Trebuie sa existe un buton de copiere
    assert "Copiaza" in html or "copiaza" in html.lower()
    # Snippet-urile trebuie sa fie in <pre><code> (nu text ascuns in data-*)
    assert "<pre>" in html and "<code>" in html
    # Butonul NU trebuie sa aiba data-cod sau data-snippet cu continutul
    # (copiaza din DOM, nu din attribut)
    assert 'data-cod="' not in html
    assert 'data-snippet="' not in html


# =========================================================================== #
# test_empty_state_cta_cont_cand_fara_cheie_sau_creds                          #
# =========================================================================== #

def test_empty_state_cta_cont_cand_fara_cheie_sau_creds(client):
    """Fara cheie API sau credentiale RAR, panoul afiseaza CTA catre tab Cont."""
    # Cont nou fara cheie si fara credentiale
    _create_account_user("empty_state@test.com")
    _login(client, "empty_state@test.com")

    resp = client.get("/_fragments/integrare")
    assert resp.status_code == 200
    html = resp.text
    # Trebuie sa existe un mesaj de empty-state cu link catre tab cont
    assert "/?tab=cont" in html or "tab=cont" in html
    # Mesajul trebuie sa atraga atentia ca lipsesc ceva
    # (cheie sau credentiale)
    lower = html.lower()
    assert "cheie" in lower or "credentiale" in lower or "cont" in lower


# =========================================================================== #
# test_fara_culori_hardcodate_doar_tokens                                      #
# =========================================================================== #

def test_fara_culori_hardcodate_doar_tokens(client):
    """Panoul Integrare nu contine culori hex hardcodate (#RRGGBB) — doar var(--...) tokens."""
    _create_account_user("tokens_css@test.com")
    _login(client, "tokens_css@test.com")

    resp = client.get("/_fragments/integrare")
    assert resp.status_code == 200
    html = resp.text
    # Cauta culori hex in stil inline (style="...#...") sau in tag style
    # Pattern: # urmat de 3 sau 6 hex digits, in context CSS
    import re as _re
    # Cautam doar in atributele style="" inline si in taguri <style>
    style_attrs = _re.findall(r'style="([^"]*)"', html)
    style_tags = _re.findall(r'<style[^>]*>(.*?)</style>', html, _re.DOTALL)
    all_css = " ".join(style_attrs) + " ".join(style_tags)
    # Culori hex in CSS: #rgb sau #rrggbb (precedate de spatiu, :, sau ;)
    hex_colors = _re.findall(r'(?<=[: ])#[0-9a-fA-F]{3,6}\b', all_css)
    assert not hex_colors, (
        f"Culori hex hardcodate gasite in _integrare.html: {hex_colors}. "
        "Foloseste var(--...) tokens CSS."
    )


# =========================================================================== #
# test_export_postman_are_atribut_download  [FIX-2]                            #
# =========================================================================== #

def test_export_postman_are_atribut_download(client):
    """Linkul Postman (.json) contine atributul download (PRD US-003)."""
    _create_account_user("postman_download@test.com")
    _login(client, "postman_download@test.com")

    resp = client.get("/_fragments/integrare")
    assert resp.status_code == 200
    html = resp.text
    # Trebuie sa existe linkul postman.json cu atribut download
    assert "postman.json" in html, "Linkul postman.json lipseste din pagina"
    import re as _re
    # Cautam <a cu href postman.json care contine si atribut download
    postman_links = _re.findall(r'<a[^>]*postman\.json[^>]*>', html)
    assert postman_links, "Tag-ul <a> cu postman.json nu a fost gasit"
    assert any("download" in lnk for lnk in postman_links), (
        f"Linkul Postman nu are atribut 'download'. Tag gasit: {postman_links}"
    )


# =========================================================================== #
# test_export_card_foloseste_cardlink  [FIX-1]                                 #
# =========================================================================== #

def test_export_card_foloseste_cardlink(client):
    """Cardul Export & referinta foloseste componenta .cardlink (PRD US-003)."""
    _create_account_user("export_cardlink@test.com")
    _login(client, "export_cardlink@test.com")

    resp = client.get("/_fragments/integrare")
    assert resp.status_code == 200
    html = resp.text
    # Cardul export trebuie sa contina clasa cardlink
    assert "cardlink" in html, (
        "Clasa 'cardlink' lipseste din panoul Integrare. "
        "Cardul Export & referinta trebuie sa foloseasca componenta .cardlink."
    )
    # Linkurile de export trebuie sa foloseasca clasa cardlink
    import re as _re
    cardlink_anchors = _re.findall(r'<a[^>]*cardlink[^>]*>', html)
    assert cardlink_anchors, "Nu exista niciun <a class=\"cardlink\"> in pagina"


# =========================================================================== #
# test_microcopy_anticonfuzie_la_test_cheie  [FIX-3]                           #
# =========================================================================== #

def test_microcopy_anticonfuzie_la_test_cheie(client):
    """Formularul 'Testeaza conexiunea' contine microcopy anti-confuzie (PRD US-004)."""
    _create_account_user("microcopy@test.com")
    _login(client, "microcopy@test.com")

    resp = client.get("/_fragments/integrare")
    assert resp.status_code == 200
    html = resp.text
    # Textul specific din PRD US-004
    assert "Nu o salvam" in html, (
        "Microcopy anti-confuzie lipseste din formularul 'Testeaza conexiunea'. "
        "Trebuie sa contina: 'Nu o salvam si nu o memoram'."
    )


# =========================================================================== #
# test_buton_copiaza_schimba_label_in_copiat  [FIX-4]                          #
# =========================================================================== #

def test_buton_copiaza_schimba_label_in_copiat(client):
    """Scriptul JS schimba label-ul butonului in 'Copiat' la copiere (PRD US-003)."""
    _create_account_user("copiat_label@test.com")
    _login(client, "copiat_label@test.com")

    resp = client.get("/_fragments/integrare")
    assert resp.status_code == 200
    html = resp.text
    # Scriptul trebuie sa contina logica de schimbare a textContent pe buton
    assert "textContent" in html, (
        "Scriptul JS nu contine 'textContent' — schimbarea label-ului butonului lipseste."
    )
    assert "Copiat" in html, (
        "Textul 'Copiat' lipseste din script — butonul nu isi schimba label-ul."
    )
    import re as _re
    script_blocks = _re.findall(r'<script[^>]*>(.*?)</script>', html, _re.DOTALL)
    script_text = " ".join(script_blocks)
    # Verificam ca butonul (btn) isi schimba textContent (nu doar feedback div)
    assert "btn.textContent" in script_text, (
        "Scriptul JS nu contine 'btn.textContent' — label-ul butonului nu se schimba."
    )
    # Verificam valoarea setata pe buton
    assert "'Copiat'" in script_text or '"Copiat"' in script_text, (
        "Scriptul JS nu seteaza valoarea 'Copiat' pe buton."
    )
    # Verificam revenirea la 'Copiaza' dupa setTimeout
    assert "setTimeout" in script_text, (
        "Scriptul JS nu contine setTimeout — revenirea la 'Copiaza' dupa 2s lipseste."
    )
    assert "'Copiaza'" in script_text or '"Copiaza"' in script_text, (
        "Scriptul JS nu seteaza revenirea la 'Copiaza' dupa timeout."
    )


# =========================================================================== #
# test_script_integrare_scoped_pe_container  [FIX-3]                           #
# =========================================================================== #

def test_script_integrare_scoped_pe_container(client):
    """Scriptul JS din _integrare.html este scoped pe #integrare-section.

    Un querySelectorAll global ar ataca si tablist-ul principal din dashboard.html,
    acumuland handlere si provocand dubla-legare pe fiecare swap HTMX.
    Verificam ca scriptul porneste de la getElementById('integrare-section')
    si NU face document.querySelectorAll('[role="tablist"]') global.
    """
    _create_account_user("scoped_script@test.com")
    _login(client, "scoped_script@test.com")

    resp = client.get("/_fragments/integrare")
    assert resp.status_code == 200
    html = resp.text

    import re as _re
    script_blocks = _re.findall(r'<script[^>]*>(.*?)</script>', html, _re.DOTALL)
    script_text = " ".join(script_blocks)

    # Trebuie sa existe getElementById('integrare-section') ca root
    assert "getElementById('integrare-section')" in script_text or \
           'getElementById("integrare-section")' in script_text, (
        "Scriptul JS nu contine getElementById('integrare-section') — "
        "scoping-ul pe container lipseste"
    )

    # NU trebuie sa existe document.querySelectorAll cu '[role="tablist"]' global
    # (adica fara a folosi root-ul)
    has_global_tablist = bool(
        _re.search(r'document\.querySelectorAll\([\'"][^"\']*\[role=["\']tablist["\'][^"\']*[\'"]\)', script_text)
    )
    assert not has_global_tablist, (
        "Scriptul JS contine document.querySelectorAll('[role=\"tablist\"]') global — "
        "trebuie sa foloseasca root.querySelectorAll dupa getElementById('integrare-section')"
    )
