import pytest
from fastapi.testclient import TestClient

from app.core.database import Base, engine
from app.main import app
from tests._safety_guards import safe_drop_all, safe_rmtree


@pytest.fixture(autouse=True)
def _setup_db():
    Base.metadata.create_all(engine)
    with TestClient(app):
        pass
    yield
    safe_drop_all(engine, Base.metadata)


@pytest.fixture()
def client():
    # Codex W2 M3: context manager 패턴으로 lifespan startup/shutdown 확실히 실행.
    with TestClient(app, raise_server_exceptions=False) as c:
        yield c


def _admin_login(client: TestClient):
    client.post("/api/v1/auth/login", json={"username": "admin", "password": "admin123"})


def _creator_login(client: TestClient):
    client.post("/api/v1/auth/login", json={"username": "creator", "password": "creator123"})


def test_create_user(client: TestClient):
    _admin_login(client)
    resp = client.post("/api/v1/users/", json={
        "username": "newuser",
        "display_name": "New User",
        "password": "pass123",
        "role": "creator",
    })
    assert resp.status_code == 200
    assert resp.json()["username"] == "newuser"


def test_list_users(client: TestClient):
    _admin_login(client)
    resp = client.get("/api/v1/users/")
    assert resp.status_code == 200
    data = resp.json()
    assert data["total"] >= 2  # admin + creator


def test_get_user(client: TestClient):
    _admin_login(client)
    # Create a user first
    create_resp = client.post("/api/v1/users/", json={
        "username": "getme",
        "display_name": "Get Me",
        "password": "pass123",
        "role": "creator",
    })
    user_id = create_resp.json()["id"]
    resp = client.get(f"/api/v1/users/{user_id}")
    assert resp.status_code == 200
    assert resp.json()["username"] == "getme"


def test_update_user(client: TestClient):
    _admin_login(client)
    create_resp = client.post("/api/v1/users/", json={
        "username": "updateme",
        "display_name": "Old Name",
        "password": "pass123",
        "role": "creator",
    })
    user_id = create_resp.json()["id"]
    resp = client.patch(f"/api/v1/users/{user_id}", json={"display_name": "New Name"})
    assert resp.status_code == 200
    assert resp.json()["display_name"] == "New Name"


def test_deactivate_user(client: TestClient):
    _admin_login(client)
    create_resp = client.post("/api/v1/users/", json={
        "username": "deacme",
        "display_name": "Deac Me",
        "password": "pass123",
        "role": "creator",
    })
    user_id = create_resp.json()["id"]
    resp = client.delete(f"/api/v1/users/{user_id}")
    assert resp.status_code == 200
    assert resp.json()["is_active"] == 0


def test_duplicate_username(client: TestClient):
    _admin_login(client)
    client.post("/api/v1/users/", json={
        "username": "dupuser",
        "display_name": "Dup",
        "password": "pass123",
        "role": "creator",
    })
    resp = client.post("/api/v1/users/", json={
        "username": "dupuser",
        "display_name": "Dup2",
        "password": "pass123",
        "role": "creator",
    })
    assert resp.status_code == 400


def test_creator_cannot_access(client: TestClient):
    _creator_login(client)
    resp = client.get("/api/v1/users/")
    assert resp.status_code == 403


def test_cannot_deactivate_last_admin(client: TestClient):
    _admin_login(client)
    # Get admin user id
    list_resp = client.get("/api/v1/users/")
    admin_user = [u for u in list_resp.json()["items"] if u["role"] == "admin"][0]
    resp = client.delete(f"/api/v1/users/{admin_user['id']}")
    assert resp.status_code == 400
