"""Tests for personnel_number feature (agent-07)."""
import asyncio
import pytest
from httpx import AsyncClient

pytestmark = pytest.mark.asyncio

USERS_URL = "/api/v1/users"
INVITE_URL = "/api/v1/users/invite"
COMPANIES_URL = "/api/v1/companies"
NEXT_URL = "/api/v1/users/next-personnel-number"


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


# ── Format-Validierung ───────────────────────────────────────────────────────

async def test_invite_with_letters_in_personnel_number_rejected(client: AsyncClient, registered_user):
    resp = await client.post(INVITE_URL, headers=auth(registered_user["tokens"]), json={
        "email": "letter@test.de",
        "first_name": "L", "last_name": "L",
        "personnel_number": "ABC123",
    })
    assert resp.status_code == 422


async def test_invite_with_numeric_personnel_number_ok(client: AsyncClient, registered_user):
    resp = await client.post(INVITE_URL, headers=auth(registered_user["tokens"]), json={
        "email": "num1@test.de",
        "first_name": "N", "last_name": "N",
        "personnel_number": "1001",
    })
    assert resp.status_code == 201
    assert resp.json()["personnel_number"] == "1001"


# ── Eindeutigkeit + Reservierung ─────────────────────────────────────────────

async def test_duplicate_personnel_number_rejected(client: AsyncClient, registered_user):
    h = auth(registered_user["tokens"])
    r1 = await client.post(INVITE_URL, headers=h, json={
        "email": "dup1@test.de", "first_name": "D", "last_name": "1",
        "personnel_number": "2001",
    })
    assert r1.status_code == 201
    r2 = await client.post(INVITE_URL, headers=h, json={
        "email": "dup2@test.de", "first_name": "D", "last_name": "2",
        "personnel_number": "2001",
    })
    assert r2.status_code == 409


async def test_personnel_number_reserved_after_deactivation(client: AsyncClient, registered_user):
    h = auth(registered_user["tokens"])
    # User mit Nummer anlegen
    r = await client.post(INVITE_URL, headers=h, json={
        "email": "reserve@test.de", "first_name": "R", "last_name": "R",
        "personnel_number": "3001",
    })
    user_id = r.json()["id"]
    # Deaktivieren
    await client.patch(f"{USERS_URL}/{user_id}", headers=h, json={"is_active": False})
    # Andere User darf 3001 nicht bekommen
    r2 = await client.post(INVITE_URL, headers=h, json={
        "email": "other@test.de", "first_name": "O", "last_name": "O",
        "personnel_number": "3001",
    })
    assert r2.status_code == 409


# ── Auto-Vergabe & Counter ───────────────────────────────────────────────────

async def test_next_personnel_number_endpoint(client: AsyncClient, registered_user):
    r = await client.get(NEXT_URL, headers=auth(registered_user["tokens"]))
    assert r.status_code == 200
    assert r.json()["next"].isdigit()


async def test_auto_mode_assigns_personnel_number(client: AsyncClient, registered_user):
    h = auth(registered_user["tokens"])
    # Modus auf auto setzen
    upd = await client.patch(f"{COMPANIES_URL}/me", headers=h, json={
        "personnel_number_mode": "auto",
    })
    assert upd.status_code == 200
    # Invite ohne explizite Nr.
    r = await client.post(INVITE_URL, headers=h, json={
        "email": "auto@test.de", "first_name": "A", "last_name": "A",
    })
    assert r.status_code == 201
    nr = r.json()["personnel_number"]
    assert nr is not None and nr.isdigit()
    # zurück auf manual
    await client.patch(f"{COMPANIES_URL}/me", headers=h, json={
        "personnel_number_mode": "manual",
    })


async def test_required_flag_blocks_invite_without_number(client: AsyncClient, registered_user):
    h = auth(registered_user["tokens"])
    upd = await client.patch(f"{COMPANIES_URL}/me", headers=h, json={
        "personnel_number_required": True,
    })
    assert upd.status_code == 200
    try:
        r = await client.post(INVITE_URL, headers=h, json={
            "email": "noreq2@test.de", "first_name": "X", "last_name": "X",
        })
        assert r.status_code == 400
    finally:
        await client.patch(f"{COMPANIES_URL}/me", headers=h, json={
            "personnel_number_required": False,
        })


# ── Lookup ───────────────────────────────────────────────────────────────────

async def test_get_by_personnel_number(client: AsyncClient, registered_user):
    h = auth(registered_user["tokens"])
    r = await client.post(INVITE_URL, headers=h, json={
        "email": "lookup@test.de", "first_name": "L", "last_name": "U",
        "personnel_number": "4001",
    })
    assert r.status_code == 201
    g = await client.get(f"{USERS_URL}/by-personnel/4001", headers=h)
    assert g.status_code == 200
    assert g.json()["email"] == "lookup@test.de"
    nf = await client.get(f"{USERS_URL}/by-personnel/9999999", headers=h)
    assert nf.status_code == 404
