"""
認證 API 整合測試。

測試覆蓋:
  - 註冊新帳號(第一個自動成 owner、第二個是 member、重複 email 會擋)
  - 登入(成功 / 帳密錯 / 帳號停用)
  - refresh token 換新 token
  - 帶 token 取得 /api/users/me
  - 不帶 token 取 /api/users/me 會 401
"""

import pytest
from httpx import AsyncClient


# ============================================================================
# /api/auth/register
# ============================================================================
async def test_register_first_user_becomes_owner(client: AsyncClient):
    res = await client.post(
        "/api/auth/register",
        json={
            "email": "alice@example.com",
            "password": "supersecret",
            "display_name": "Alice",
        },
    )
    assert res.status_code == 201, res.text
    body = res.json()
    assert body["email"] == "alice@example.com"
    assert body["role"] == "owner"  # 第一個註冊 = owner
    assert body["is_active"] is True
    assert "password_hash" not in body  # 不能洩漏密碼欄位


async def test_register_second_user_becomes_member(client: AsyncClient):
    # 第一個 owner
    await client.post(
        "/api/auth/register",
        json={"email": "owner@x.com", "password": "supersecret", "display_name": "Owner"},
    )
    # 第二個應該是 member
    res = await client.post(
        "/api/auth/register",
        json={"email": "bob@x.com", "password": "supersecret", "display_name": "Bob"},
    )
    assert res.status_code == 201
    assert res.json()["role"] == "member"


async def test_register_duplicate_email_is_rejected(client: AsyncClient):
    payload = {"email": "dup@x.com", "password": "supersecret", "display_name": "X"}
    await client.post("/api/auth/register", json=payload)
    res = await client.post("/api/auth/register", json=payload)
    assert res.status_code == 409


async def test_register_email_is_case_insensitive(client: AsyncClient):
    """ALICE@x.com 跟 alice@x.com 應該被視為同一個帳號。"""
    await client.post(
        "/api/auth/register",
        json={"email": "alice@x.com", "password": "supersecret", "display_name": "A"},
    )
    res = await client.post(
        "/api/auth/register",
        json={"email": "ALICE@x.com", "password": "supersecret", "display_name": "A"},
    )
    assert res.status_code == 409


async def test_register_password_too_short(client: AsyncClient):
    res = await client.post(
        "/api/auth/register",
        json={"email": "x@x.com", "password": "short", "display_name": "X"},
    )
    assert res.status_code == 422  # Pydantic validation


# ============================================================================
# /api/auth/login
# ============================================================================
@pytest.fixture
async def registered_user(client: AsyncClient):
    """先註冊一個帳號,讓登入測試可以用。"""
    res = await client.post(
        "/api/auth/register",
        json={"email": "login@x.com", "password": "supersecret", "display_name": "Login"},
    )
    assert res.status_code == 201
    return {"email": "login@x.com", "password": "supersecret"}


async def test_login_success(client: AsyncClient, registered_user):
    res = await client.post("/api/auth/login", json=registered_user)
    assert res.status_code == 200
    body = res.json()
    assert "tokens" in body
    assert body["tokens"]["access_token"]
    assert body["tokens"]["refresh_token"]
    assert body["tokens"]["token_type"] == "bearer"
    assert body["user"]["email"] == "login@x.com"


async def test_login_wrong_password(client: AsyncClient, registered_user):
    res = await client.post(
        "/api/auth/login",
        json={"email": registered_user["email"], "password": "wrong-password"},
    )
    assert res.status_code == 401


async def test_login_unknown_email(client: AsyncClient):
    res = await client.post(
        "/api/auth/login",
        json={"email": "nobody@x.com", "password": "whatever1"},
    )
    assert res.status_code == 401


# ============================================================================
# /api/auth/refresh
# ============================================================================
async def test_refresh_returns_new_tokens(client: AsyncClient, registered_user):
    login_res = await client.post("/api/auth/login", json=registered_user)
    refresh_token = login_res.json()["tokens"]["refresh_token"]

    res = await client.post("/api/auth/refresh", json={"refresh_token": refresh_token})
    assert res.status_code == 200
    body = res.json()
    assert body["access_token"]
    assert body["refresh_token"]


async def test_refresh_with_access_token_is_rejected(client: AsyncClient, registered_user):
    """access token 不能拿來 refresh(避免 token 類型混用)。"""
    login_res = await client.post("/api/auth/login", json=registered_user)
    access_token = login_res.json()["tokens"]["access_token"]

    res = await client.post("/api/auth/refresh", json={"refresh_token": access_token})
    assert res.status_code == 401


async def test_refresh_with_garbage_token(client: AsyncClient):
    res = await client.post("/api/auth/refresh", json={"refresh_token": "not-a-jwt"})
    assert res.status_code == 401


# ============================================================================
# /api/users/me
# ============================================================================
async def test_get_me_requires_auth(client: AsyncClient):
    res = await client.get("/api/users/me")
    assert res.status_code == 401


async def test_get_me_with_token(client: AsyncClient, registered_user):
    login_res = await client.post("/api/auth/login", json=registered_user)
    access = login_res.json()["tokens"]["access_token"]

    res = await client.get(
        "/api/users/me",
        headers={"Authorization": f"Bearer {access}"},
    )
    assert res.status_code == 200
    assert res.json()["email"] == registered_user["email"]


async def test_update_me(client: AsyncClient, registered_user):
    login_res = await client.post("/api/auth/login", json=registered_user)
    access = login_res.json()["tokens"]["access_token"]

    res = await client.patch(
        "/api/users/me",
        headers={"Authorization": f"Bearer {access}"},
        json={"display_name": "新名字"},
    )
    assert res.status_code == 200
    assert res.json()["display_name"] == "新名字"


# ============================================================================
# /health
# ============================================================================
async def test_health_check(client: AsyncClient):
    res = await client.get("/health")
    assert res.status_code == 200
    assert res.json()["status"] == "ok"
