"""#1718：微信回调路由可观测性日志分支覆盖（UA/state/错误透传）。

直接驱动 wechat_callback 路由函数，mock OAuth service 与用户仓储：
- 成功路径：日志记录 UA、state 校验通过（MicroMessenger 内置浏览器）
- 失败路径：OAuth 返回错误时记 warning 并抛 400
"""

from __future__ import annotations

import asyncio
import os
import sys
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import MagicMock, patch

import pytest

os.environ.setdefault("JWT_SECRET_KEY", "unit-test-secret-key-for-testing")
os.environ.setdefault("DATABASE_URL", "sqlite:///test.db")

sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "apps" / "api"))

from app.api.routes import auth as auth_route  # noqa: E402
from fastapi import HTTPException  # noqa: E402


class _FakeRequest:
    def __init__(self, ua: str):
        self.headers = {"User-Agent": ua}


def _wechat_user():
    return SimpleNamespace(
        openid="openid-callback-1",
        unionid="union-callback-1",
        nickname="微信用户",
        avatar_url="http://x/a.png",
    )


def _fake_oauth_factory(success: bool):
    service = MagicMock()
    if success:
        service.handle_callback.return_value = (_wechat_user(), None)
    else:
        service.handle_callback.return_value = (None, "无效的 state 参数，请求可能已过期或被篡改")
    return service


def test_wechat_callback_success_logs_ua_and_state(caplog):
    fake_repo = MagicMock()
    sync_response = SimpleNamespace(
        access_token="at",
        refresh_token="rt",
        user_id="u-1",
        nickname="微信用户",
        avatar_url="",
        is_new_user=False,
        expires_in=1800,
    )
    fake_use_case = MagicMock()
    fake_use_case.execute.return_value = (sync_response, None)

    user = SimpleNamespace(
        id="u-1",
        phone_verified=True,
        email_verified=True,
        email="u@example.com",
    )
    fake_repo.find_by_id.return_value = user

    request_obj = SimpleNamespace(code="code-1", state="state-1")
    fake_http = _FakeRequest("Mozilla/5.0 (Linux; Android 13) MicroMessenger/8.0.40 WeChat/8.0.40")

    import packages.application.auth.wechat_oauth_service as oauth_mod
    import packages.application.auth.wechat_sync_use_case as sync_mod

    orig_oauth = oauth_mod.get_wechat_oauth_service
    orig_sync = sync_mod.WechatSyncUseCase
    oauth_mod.get_wechat_oauth_service = MagicMock(return_value=_fake_oauth_factory(success=True))
    sync_mod.WechatSyncUseCase = MagicMock(return_value=fake_use_case)
    try:
        with caplog.at_level("INFO", logger="app.api.routes.auth"):
            resp = asyncio.run(auth_route.wechat_callback(request_obj, fake_http, user_repository=fake_repo))
    finally:
        oauth_mod.get_wechat_oauth_service = orig_oauth
        sync_mod.WechatSyncUseCase = orig_sync

    assert resp.user_id == "u-1"
    assert resp.binding_complete is True
    log_text = " ".join(rec.getMessage() for rec in caplog.records)
    assert "微信回调" in log_text
    assert "MicroMessenger" in log_text or "微信内置浏览器=True" in log_text


def test_wechat_callback_failure_raises_400_with_detail(caplog):
    request_obj = SimpleNamespace(code="code-bad", state="state-bad")
    fake_http = _FakeRequest("Mozilla/5.0 Chrome/127")
    fake_service = _fake_oauth_factory(success=False)

    import packages.application.auth.wechat_oauth_service as oauth_mod

    orig = oauth_mod.get_wechat_oauth_service
    oauth_mod.get_wechat_oauth_service = MagicMock(return_value=fake_service)
    try:
        with caplog.at_level("WARNING", logger="app.api.routes.auth"):
            with pytest.raises(HTTPException) as exc_info:
                asyncio.run(auth_route.wechat_callback(request_obj, fake_http, user_repository=MagicMock()))
    finally:
        oauth_mod.get_wechat_oauth_service = orig

    assert exc_info.value.status_code == 400
    assert "state" in exc_info.value.detail
    assert any("微信回调" in rec.getMessage() for rec in caplog.records)
