"""Integration tests for WeChat OAuth login (dev mode mock flow)"""

import pytest
from httpx import AsyncClient, ASGITransport

from app.main import app
from app.services.wechat_oauth import is_dev_mode


@pytest.mark.asyncio
async def test_wechat_authorize(client: AsyncClient):
    """GET /auth/wechat/authorize returns authorization URL and state"""
    resp = await client.get("/api/v1/auth/wechat/authorize")
    assert resp.status_code == 200
    data = resp.json()
    assert "authorization_url" in data
    assert "state" in data
    assert len(data["state"]) == 32  # uuid4 hex


@pytest.mark.asyncio
async def test_wechat_callback_auto_register(client: AsyncClient):
    """Callback with valid state auto-registers a new user"""
    # 1. Get state
    auth_resp = await client.get("/api/v1/auth/wechat/authorize")
    state = auth_resp.json()["state"]

    # 2. Call callback (dev mode uses mock exchange)
    resp = await client.get(f"/api/v1/auth/wechat/callback?code=mock_code_123&state={state}",
                            follow_redirects=False)
    # Should redirect (302) with tokens in query params
    assert resp.status_code in (302, 307)
    location = resp.headers.get("location", "")
    assert "access_token" in location
    assert "refresh_token" in location


@pytest.mark.asyncio
async def test_wechat_callback_invalid_state(client: AsyncClient):
    """Callback with invalid/non-existent state returns 400"""
    resp = await client.get("/api/v1/auth/wechat/callback?code=abc&state=invalid_state_123")
    assert resp.status_code == 400


@pytest.mark.asyncio
async def test_wechat_callback_reuse_state_fails(client: AsyncClient):
    """Same state cannot be used twice (popped from cache)"""
    auth_resp = await client.get("/api/v1/auth/wechat/authorize")
    state = auth_resp.json()["state"]

    # First call succeeds
    resp1 = await client.get(f"/api/v1/auth/wechat/callback?code=first&state={state}",
                             follow_redirects=False)
    assert resp1.status_code in (302, 307)

    # Second call with same state fails
    resp2 = await client.get(f"/api/v1/auth/wechat/callback?code=second&state={state}",
                             follow_redirects=False)
    assert resp2.status_code == 400


@pytest.mark.asyncio
async def test_wechat_callback_existing_user_logs_in(client: AsyncClient):
    """Second callback with same openid logs in (does not create new user)"""
    # First login (auto-register) with deterministic code
    auth_resp1 = await client.get("/api/v1/auth/wechat/authorize")
    state1 = auth_resp1.json()["state"]
    resp1 = await client.get(f"/api/v1/auth/wechat/callback?code=test_user_001&state={state1}",
                             follow_redirects=False)
    assert resp1.status_code in (302, 307)
    location1 = resp1.headers.get("location", "")
    # Extract tokens from first login
    from urllib.parse import urlparse, parse_qs
    parsed1 = urlparse(location1)
    qs1 = parse_qs(parsed1.query)
    user_id1 = qs1.get("user_id", [""])[0]

    # Second login with same code (same openid via md5)
    auth_resp2 = await client.get("/api/v1/auth/wechat/authorize")
    state2 = auth_resp2.json()["state"]
    resp2 = await client.get(f"/api/v1/auth/wechat/callback?code=test_user_001&state={state2}",
                             follow_redirects=False)
    assert resp2.status_code in (302, 307)
    location2 = resp2.headers.get("location", "")
    parsed2 = urlparse(location2)
    qs2 = parse_qs(parsed2.query)
    user_id2 = qs2.get("user_id", [""])[0]

    # Same user (not duplicated)
    assert user_id1 == user_id2, "Same WeChat user should not be duplicated"


@pytest.mark.asyncio
async def test_wechat_user_endpoint(client: AsyncClient, auth_headers):
    """GET /auth/wechat/user returns current user's WeChat binding info"""
    resp = await client.get("/api/v1/auth/wechat/user", headers=auth_headers)
    assert resp.status_code == 200
    data = resp.json()
    assert "sso_provider" in data
