import pytest
from httpx import AsyncClient

pytestmark = pytest.mark.asyncio

USERS_URL = "/api/v1/users"
INVITE_URL = "/api/v1/users/invite"


def auth(tokens):
    return {"Authorization": f"Bearer {tokens['access_token']}"}


async def test_list_users_as_admin(client: AsyncClient, registered_user):
    resp = await client.get(USERS_URL + "/", headers=auth(registered_user["tokens"]))
    assert resp.status_code == 200
    body = resp.json()
    assert "total" in body
    assert "items" in body
    assert body["total"] >= 1


async def test_list_users_forbidden_for_employee(client: AsyncClient, registered_user):
    # Invite an employee first
    inv = await client.post(INVITE_URL, headers=auth(registered_user["tokens"]), json={
        "email": "employee@test.de",
        "first_name": "Anna",
        "last_name": "Arbeit",
        "role": "EMPLOYEE",
    })
    assert inv.status_code == 201

    # Employee tries to list users – should fail
    # (We can't log in as employee here without accepting invite;
    #  so we test the role check via schema validation only)
    assert inv.json()["role"] == "EMPLOYEE"


async def test_invite_user(client: AsyncClient, registered_user):
    resp = await client.post(INVITE_URL, headers=auth(registered_user["tokens"]), json={
        "email": "newcolleague@test.de",
        "first_name": "Birgit",
        "last_name": "Neu",
        "role": "MANAGER",
    })
    assert resp.status_code == 201
    body = resp.json()
    assert body["email"] == "newcolleague@test.de"
    assert body["role"] == "MANAGER"
    assert body["is_active"] is False  # not yet accepted


async def test_invite_duplicate_email(client: AsyncClient, registered_user):
    await client.post(INVITE_URL, headers=auth(registered_user["tokens"]), json={
        "email": "dup@test.de", "first_name": "D", "last_name": "U", "role": "EMPLOYEE",
    })
    resp = await client.post(INVITE_URL, headers=auth(registered_user["tokens"]), json={
        "email": "dup@test.de", "first_name": "D", "last_name": "U", "role": "EMPLOYEE",
    })
    assert resp.status_code == 400


async def test_get_me(client: AsyncClient, registered_user):
    resp = await client.get(USERS_URL + "/me", headers=auth(registered_user["tokens"]))
    assert resp.status_code == 200
    assert resp.json()["id"] == registered_user["user"]["id"]


async def test_update_user(client: AsyncClient, registered_user):
    user_id = registered_user["user"]["id"]
    resp = await client.patch(
        f"{USERS_URL}/{user_id}",
        headers=auth(registered_user["tokens"]),
        json={"first_name": "Maximilian"},
    )
    assert resp.status_code == 200
    assert resp.json()["first_name"] == "Maximilian"


async def test_deactivate_and_reactivate(client: AsyncClient, registered_user):
    # Invite a second user to deactivate
    inv = await client.post(INVITE_URL, headers=auth(registered_user["tokens"]), json={
        "email": "temp@test.de", "first_name": "T", "last_name": "Emp", "role": "EMPLOYEE",
    })
    user_id = inv.json()["id"]

    deact = await client.post(
        f"{USERS_URL}/{user_id}/deactivate",
        headers=auth(registered_user["tokens"]),
    )
    assert deact.status_code == 200
    assert deact.json()["is_active"] is False

    react = await client.post(
        f"{USERS_URL}/{user_id}/reactivate",
        headers=auth(registered_user["tokens"]),
    )
    assert react.status_code == 200
    assert react.json()["is_active"] is True


async def test_cannot_deactivate_self(client: AsyncClient, registered_user):
    user_id = registered_user["user"]["id"]
    resp = await client.post(
        f"{USERS_URL}/{user_id}/deactivate",
        headers=auth(registered_user["tokens"]),
    )
    assert resp.status_code == 400


async def test_set_kiosk_pin(client: AsyncClient, registered_user):
    user_id = registered_user["user"]["id"]
    resp = await client.post(
        f"{USERS_URL}/{user_id}/kiosk-pin",
        headers=auth(registered_user["tokens"]),
        json={"pin": "1234"},
    )
    assert resp.status_code == 200


async def test_kiosk_pin_must_be_numeric(client: AsyncClient, registered_user):
    user_id = registered_user["user"]["id"]
    resp = await client.post(
        f"{USERS_URL}/{user_id}/kiosk-pin",
        headers=auth(registered_user["tokens"]),
        json={"pin": "abcd"},
    )
    assert resp.status_code == 422


async def test_anonymize_user(client: AsyncClient, registered_user):
    """DSGVO Art. 17: Anonymisierung entfernt den Personenbezug, Konto wird inaktiv."""
    inv = await client.post(INVITE_URL, headers=auth(registered_user["tokens"]), json={
        "email": "gdpr@test.de", "first_name": "Max", "last_name": "Muster",
        "role": "EMPLOYEE", "initial_password": "Secret123",
    })
    user_id = inv.json()["id"]

    resp = await client.post(f"{USERS_URL}/{user_id}/anonymize", headers=auth(registered_user["tokens"]))
    assert resp.status_code == 200, resp.text
    body = resp.json()
    assert body["anonymized_at"] is not None
    assert body["first_name"] == "Anonymisiert"
    assert body["email"] == f"anon-{user_id}@deleted.local"
    assert body["is_active"] is False

    # Login mit alter E-Mail unmöglich
    login = await client.post("/api/v1/auth/login", json={"email": "gdpr@test.de", "password": "Secret123"})
    assert login.status_code == 401

    # Reaktivierung eines anonymisierten Kontos wird abgelehnt
    react = await client.post(f"{USERS_URL}/{user_id}/reactivate", headers=auth(registered_user["tokens"]))
    assert react.status_code == 409

    # Erneutes Anonymisieren wird abgelehnt
    again = await client.post(f"{USERS_URL}/{user_id}/anonymize", headers=auth(registered_user["tokens"]))
    assert again.status_code == 409


async def test_cannot_anonymize_self(client: AsyncClient, registered_user):
    user_id = registered_user["user"]["id"]
    resp = await client.post(f"{USERS_URL}/{user_id}/anonymize", headers=auth(registered_user["tokens"]))
    assert resp.status_code == 400
