"""Teste US-012 (PRD 3.3b): notificare email admin la signup (degradat) + bootstrap admin.

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

from __future__ import annotations

import os
import tempfile

import pytest
from starlette.testclient import TestClient


# ---------------------------------------------------------------------------
# Fixture client (pattern identic cu test_web_signup.py)
# ---------------------------------------------------------------------------

@pytest.fixture()
def client(monkeypatch):
    tmp = tempfile.mkdtemp()
    monkeypatch.setenv("AUTOPASS_DB_PATH", os.path.join(tmp, "t.db"))
    monkeypatch.setenv("AUTOPASS_SIGNUP_RATE_MAX", "100")
    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) as c:
        yield c
    get_settings.cache_clear()


def _csrf(c: TestClient) -> str:
    """Obtine un token CSRF proaspat de la GET /signup."""
    import re
    resp = c.get("/signup")
    assert resp.status_code == 200
    m = re.search(r'name="csrf_token"\s+value="([^"]+)"', resp.text)
    if not m:
        m = re.search(r'value="([^"]+)"\s+name="csrf_token"', resp.text)
    assert m, "csrf_token negasit in HTML"
    return m.group(1)


def _do_signup(c: TestClient, name: str, email: str, parola: str = "parolasecreta") -> object:
    from tests.conftest import make_test_cui
    token = _csrf(c)
    return c.post("/signup", data={
        "name": name,
        "cui": make_test_cui(email),
        "email": email,
        "parola": parola,
        "consent": "1",
        "csrf_token": token,
    })


# ---------------------------------------------------------------------------
# Teste notify_signup (unitare, fara TestClient)
# ---------------------------------------------------------------------------

def test_notify_noop_fara_smtp(monkeypatch):
    """smtp_host None -> notify_signup nu ridica si nu incearca sa trimita."""
    import smtplib

    # Daca smtplib.SMTP e apelat, testul pica
    def fake_smtp(*a, **kw):
        raise AssertionError("smtplib.SMTP nu trebuia apelat fara smtp_host configurat")

    monkeypatch.setattr(smtplib, "SMTP", fake_smtp)

    # Asigura smtp_host = None
    from app.config import get_settings
    get_settings.cache_clear()
    monkeypatch.setenv("AUTOPASS_SMTP_HOST", "")  # string gol -> None in Settings
    get_settings.cache_clear()

    from app.email import notify_signup
    # Nu trebuie sa ridice
    notify_signup(["admin@test.com"], account_id=1, email="nou@test.com")

    get_settings.cache_clear()


def test_notify_nu_blocheaza_la_eroare(monkeypatch):
    """smtp_host setat, SMTP ridica exceptie -> notify_signup returneaza normal (best-effort)."""
    import smtplib

    class FakeSMTP:
        def __init__(self, *a, **kw):
            raise ConnectionRefusedError("simulam eroare retea")

    monkeypatch.setattr(smtplib, "SMTP", FakeSMTP)

    monkeypatch.setenv("AUTOPASS_SMTP_HOST", "smtp.test.local")
    monkeypatch.setenv("AUTOPASS_SMTP_PORT", "587")
    monkeypatch.setenv("AUTOPASS_SMTP_FROM", "autopass@test.local")
    from app.config import get_settings
    get_settings.cache_clear()

    from app.email import notify_signup
    # Nu trebuie sa ridice, chiar daca SMTP esueaza
    notify_signup(["admin@test.com"], account_id=5, email="nou@test.com")

    get_settings.cache_clear()


# ---------------------------------------------------------------------------
# Teste bootstrap admin (prin TestClient)
# ---------------------------------------------------------------------------

def test_primul_signup_devine_admin(client):
    """Primul signup -> userul are is_admin=1 (count_admins==1).
    Al doilea signup cu alt email -> is_admin=0 (count_admins ramane 1)."""
    # Primul signup
    resp = _do_signup(client, "Primul Service", "primul@test.com")
    assert resp.status_code == 200
    assert "rfak_" in resp.text

    from app.db import get_connection
    from app.users import count_admins
    conn = get_connection()
    try:
        n_admins = count_admins(conn)
        assert n_admins == 1, f"Dupa primul signup, count_admins trebuie sa fie 1, nu {n_admins}"
        user = conn.execute(
            "SELECT is_admin FROM users WHERE email='primul@test.com'"
        ).fetchone()
        assert user is not None
        assert user["is_admin"] == 1, "Primul user trebuie sa fie admin"
    finally:
        conn.close()

    # Al doilea signup
    resp2 = _do_signup(client, "Al Doilea Service", "aldoilea@test.com")
    assert resp2.status_code == 200
    assert "rfak_" in resp2.text

    conn = get_connection()
    try:
        n_admins = count_admins(conn)
        assert n_admins == 1, f"Dupa al doilea signup, count_admins trebuie sa ramana 1, nu {n_admins}"
        user2 = conn.execute(
            "SELECT is_admin FROM users WHERE email='aldoilea@test.com'"
        ).fetchone()
        assert user2 is not None
        assert user2["is_admin"] == 0, "Al doilea user NU trebuie sa fie admin"
    finally:
        conn.close()


# ---------------------------------------------------------------------------
# Teste C16 (log SIGNUP pastrat) si best-effort E2E
# ---------------------------------------------------------------------------

def test_signup_logheaza_fara_pii_in_stdout(client, capsys):
    """Signup reusit -> NU se mai printeaza email-ul in clar in stdout (P2-7).

    C16 (jurnalizarea signup-ului) e pastrata, dar prin `log_event` (app_events +
    log text redactat), nu prin print() cu PII."""
    resp = _do_signup(client, "Service Log Test", "log@test.com")
    assert resp.status_code == 200
    assert "rfak_" in resp.text

    captured = capsys.readouterr()
    assert "log@test.com" not in captured.out, (
        f"Emailul nu trebuie sa apara in clar in stdout. Capturat: {captured.out!r}"
    )
    assert "SIGNUP cont=" not in captured.out, (
        "Print-ul vechi cu PII nu mai trebuie sa existe."
    )

    from app.db import get_connection
    conn = get_connection()
    try:
        row = conn.execute(
            "SELECT account_id, tip FROM app_events WHERE tip='signup' ORDER BY id DESC LIMIT 1"
        ).fetchone()
    finally:
        conn.close()
    assert row is not None, "Trebuie sa existe un eveniment 'signup' in app_events"
    assert row["tip"] == "signup"


def test_signup_neblocat_de_notify(monkeypatch, client):
    """notify_signup ridica -> signup returneaza totusi 200 cu cheia (best-effort E2E)."""
    # Monkeypatch notify_signup sa ridice
    def notify_always_raises(*a, **kw):
        raise RuntimeError("simulam eroare fatala in notify")

    # Importam modulul inainte de monkeypatch
    import app.email as email_mod
    monkeypatch.setattr(email_mod, "notify_signup", notify_always_raises)

    resp = _do_signup(client, "Service Robust", "robust@test.com")
    assert resp.status_code == 200, (
        f"Signup trebuia sa reuseasca indiferent de eroarea din notify. status={resp.status_code}"
    )
    assert "rfak_" in resp.text, "Cheia API trebuia afisata chiar daca notify a esuat"
