"""API tests for /api/auth/login, /api/auth/logout, /api/auth/me."""

from __future__ import annotations

import pytest
from fastapi.testclient import TestClient
from sqlalchemy import delete

from cyclone.api import app
from cyclone.auth import users
from cyclone.db import Session as DbSession
from cyclone.db import SessionLocal, User


@pytest.fixture(autouse=True)
def _clear(monkeypatch):
    # conftest sets AUTH_DISABLED=True so pre-auth tests keep passing
    # without a login. The auth-route tests need the real auth path
    # exercised, so flip it back off here.
    monkeypatch.setattr("cyclone.auth.deps.AUTH_DISABLED", False)
    with SessionLocal()() as db:
        db.execute(delete(DbSession))
        db.execute(delete(User))
        db.commit()
    yield
    with SessionLocal()() as db:
        db.execute(delete(DbSession))
        db.execute(delete(User))
        db.commit()


@pytest.fixture
def client():
    return TestClient(app)


@pytest.fixture
def seeded_admin(client):
    with SessionLocal()() as db:
        users.create(db, username="admin", password="adminpassword1", role="admin")
    return client


def test_login_success_returns_user_and_cookie(client):
    with SessionLocal()() as db:
        users.create(db, username="alice", password="hunter2hunter2", role="user")
    resp = client.post(
        "/api/auth/login",
        json={"username": "alice", "password": "hunter2hunter2"},
    )
    assert resp.status_code == 200
    body = resp.json()
    assert body["username"] == "alice"
    assert body["role"] == "user"
    assert "password_hash" not in body
    assert "cyclone_session" in resp.cookies


def test_login_bad_password_returns_401(client):
    with SessionLocal()() as db:
        users.create(db, username="bob", password="hunter2hunter2", role="user")
    resp = client.post(
        "/api/auth/login",
        json={"username": "bob", "password": "WRONG"},
    )
    assert resp.status_code == 401
    assert resp.json()["error"] == "invalid_credentials"


def test_login_unknown_user_returns_401(client):
    resp = client.post(
        "/api/auth/login",
        json={"username": "ghost", "password": "whatever"},
    )
    assert resp.status_code == 401
    assert resp.json()["error"] == "invalid_credentials"


def test_login_disabled_user_returns_403(client):
    with SessionLocal()() as db:
        u = users.create(db, username="carol", password="hunter2hunter2", role="user")
        users.disable(db, u.id)
    resp = client.post(
        "/api/auth/login",
        json={"username": "carol", "password": "hunter2hunter2"},
    )
    assert resp.status_code == 403
    assert resp.json()["error"] == "account_disabled"


def test_logout_clears_session_and_cookie(seeded_admin):
    login = seeded_admin.post(
        "/api/auth/login",
        json={"username": "admin", "password": "adminpassword1"},
    )
    cookie = login.cookies.get("cyclone_session")
    assert cookie
    resp = seeded_admin.post("/api/auth/logout", cookies={"cyclone_session": cookie})
    assert resp.status_code == 204


def test_me_returns_current_user(seeded_admin):
    login = seeded_admin.post(
        "/api/auth/login",
        json={"username": "admin", "password": "adminpassword1"},
    )
    cookie = login.cookies.get("cyclone_session")
    resp = seeded_admin.get("/api/auth/me", cookies={"cyclone_session": cookie})
    assert resp.status_code == 200
    assert resp.json()["username"] == "admin"


def test_me_without_cookie_returns_401(seeded_admin):
    resp = seeded_admin.get("/api/auth/me")
    assert resp.status_code == 401
