"""
pytest 共用設定。

策略:
  - 用 SQLite in-memory 資料庫跑測試(不依賴 PostgreSQL,測試秒級完成)
  - 每個測試一個獨立的 in-memory DB,測試之間互不干擾
  - 用 httpx.AsyncClient + ASGI transport 直接打 FastAPI app,不用真的開 port

PostgreSQL 專屬語法(例如 PG_UUID)在 SQLite 會自動 fallback 到 CHAR(32),
測試覆蓋的是商業邏輯,不測試「PostgreSQL 特有行為」。
"""

import asyncio
import os
from typing import AsyncGenerator

# 在 import app.* 之前先把 DATABASE_URL 等環境變數塞成 SQLite 開發值,
# 否則 app.database 會嘗試載入 asyncpg(PostgreSQL driver,dev 沒裝)而 ImportError。
os.environ.setdefault("DATABASE_URL", "sqlite+aiosqlite:///:memory:")
os.environ.setdefault("JWT_SECRET_KEY", "test_secret_key_pytest")
os.environ.setdefault("ENVIRONMENT", "test")

import pytest  # noqa: E402
import pytest_asyncio  # noqa: E402
from httpx import ASGITransport, AsyncClient  # noqa: E402
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine  # noqa: E402

from app.database import Base, get_db  # noqa: E402
from app.main import app  # noqa: E402


# ---------------------------------------------------------------------------
# Event loop:整個 test session 共用一個,避免 async fixture 衝突
# ---------------------------------------------------------------------------
@pytest.fixture(scope="session")
def event_loop():
    """強制整個 session 用同一個 loop(否則 async fixture 在不同 loop 之間會炸)。"""
    loop = asyncio.new_event_loop()
    yield loop
    loop.close()


# ---------------------------------------------------------------------------
# 每個測試一個乾淨的 in-memory DB
# ---------------------------------------------------------------------------
@pytest_asyncio.fixture
async def db_session() -> AsyncGenerator[AsyncSession, None]:
    """提供一個 SQLite in-memory async session。"""
    # `aiosqlite` 是 SQLite 的 async driver,只在測試環境用
    test_engine = create_async_engine(
        "sqlite+aiosqlite:///:memory:",
        echo=False,
    )

    async with test_engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)

    TestSession = async_sessionmaker(test_engine, class_=AsyncSession, expire_on_commit=False)

    async with TestSession() as session:
        yield session

    await test_engine.dispose()


# ---------------------------------------------------------------------------
# HTTP client:把 FastAPI 的 get_db 替換成測試用 session,然後丟進 AsyncClient
# ---------------------------------------------------------------------------
@pytest_asyncio.fixture
async def client(db_session: AsyncSession) -> AsyncGenerator[AsyncClient, None]:
    """提供一個能呼叫 FastAPI 的 async HTTP client。"""

    async def _override_get_db() -> AsyncGenerator[AsyncSession, None]:
        yield db_session

    app.dependency_overrides[get_db] = _override_get_db

    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as ac:
        yield ac

    app.dependency_overrides.clear()
