"""平台规则历史版本API测试"""
import uuid

import pytest
import pytest_asyncio
from httpx import AsyncClient, ASGITransport
from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession, create_async_engine
from sqlalchemy.pool import StaticPool

from app.database import Base
from app.main import app
from app.models.platform_rule_version import PlatformRuleVersion
from app.api.deps import get_db


@pytest_asyncio.fixture
async def async_engine():
    engine = create_async_engine(
        "sqlite+aiosqlite:///:memory:",
        connect_args={"check_same_thread": False},
        poolclass=StaticPool,
    )
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)
    yield engine
    await engine.dispose()


@pytest_asyncio.fixture
async def async_session(async_engine):
    async_session_maker = async_sessionmaker(
        async_engine,
        class_=AsyncSession,
        expire_on_commit=False,
        autoflush=False,
        autocommit=False,
    )
    async with async_session_maker() as session:
        yield session


@pytest_asyncio.fixture
async def async_client(async_session):
    async def override_get_db():
        yield async_session

    app.dependency_overrides[get_db] = override_get_db

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

    app.dependency_overrides.clear()


@pytest_asyncio.fixture
async def seed_versions(async_session):
    v1 = PlatformRuleVersion(
        id=uuid.uuid4(),
        rule_id="zhihu",
        platform="zhihu",
        version=1,
        rule_data={
            "content_length": {"min": 800, "max": 3000, "recommended": 1500},
            "title_rules": {"min_length": 5, "max_length": 50},
        },
        change_summary="初始版本",
        created_by="admin",
    )
    v2 = PlatformRuleVersion(
        id=uuid.uuid4(),
        rule_id="zhihu",
        platform="zhihu",
        version=2,
        rule_data={
            "content_length": {"min": 1000, "max": 5000, "recommended": 2000},
            "title_rules": {"min_length": 5, "max_length": 50},
        },
        change_summary="调整内容长度规则",
        created_by="admin",
    )
    v3 = PlatformRuleVersion(
        id=uuid.uuid4(),
        rule_id="zhihu",
        platform="zhihu",
        version=3,
        rule_data={
            "content_length": {"min": 1000, "max": 5000, "recommended": 2000},
            "title_rules": {"min_length": 8, "max_length": 60},
        },
        change_summary="调整标题长度规则",
        created_by="editor",
    )
    async_session.add_all([v1, v2, v3])
    await async_session.commit()
    return [v1, v2, v3]


class TestRuleVersionDiff:
    """历史版本对比API测试"""

    @pytest.mark.asyncio
    async def test_diff_returns_differences_between_versions(
        self, async_client, seed_versions
    ):
        response = await async_client.get(
            "/api/v1/platforms/zhihu/rules/diff",
            params={"from_version": 1, "to_version": 2},
        )

        assert response.status_code == 200
        data = response.json()
        assert data["platform_id"] == "zhihu"
        assert isinstance(data["diffs"], list)
        assert len(data["diffs"]) > 0
        assert data["total_changes"] > 0

        diff_fields = {d["field"] for d in data["diffs"]}
        assert "content_length.min" in diff_fields
        assert "content_length.max" in diff_fields
        assert "content_length.recommended" in diff_fields

    @pytest.mark.asyncio
    async def test_diff_no_changes_returns_empty(self, async_client, seed_versions):
        response = await async_client.get(
            "/api/v1/platforms/zhihu/rules/diff",
            params={"from_version": 2, "to_version": 2},
        )

        assert response.status_code == 200
        data = response.json()
        assert data["diffs"] == []
        assert data["total_changes"] == 0

    @pytest.mark.asyncio
    async def test_diff_nonexistent_version_returns_404(
        self, async_client, seed_versions
    ):
        response = await async_client.get(
            "/api/v1/platforms/zhihu/rules/diff",
            params={"from_version": 1, "to_version": 99},
        )

        assert response.status_code == 404

    @pytest.mark.asyncio
    async def test_diff_nonexistent_platform_returns_404(self, async_client):
        response = await async_client.get(
            "/api/v1/platforms/nonexistent_platform/rules/diff",
            params={"from_version": 1, "to_version": 2},
        )

        assert response.status_code == 404

    @pytest.mark.asyncio
    async def test_diff_missing_params_returns_error(self, async_client, seed_versions):
        response = await async_client.get(
            "/api/v1/platforms/zhihu/rules/diff",
        )

        assert response.status_code == 422

    @pytest.mark.asyncio
    async def test_diff_nested_field_change(self, async_client, seed_versions):
        response = await async_client.get(
            "/api/v1/platforms/zhihu/rules/diff",
            params={"from_version": 2, "to_version": 3},
        )

        assert response.status_code == 200
        data = response.json()
        diff_fields = {d["field"] for d in data["diffs"]}
        assert "title_rules.min_length" in diff_fields
        assert "title_rules.max_length" in diff_fields


class TestRuleHistory:
    """历史记录查询API测试"""

    @pytest.mark.asyncio
    async def test_history_returns_versions(
        self, async_client, seed_versions
    ):
        response = await async_client.get(
            "/api/v1/platforms/zhihu/rules/history",
        )

        assert response.status_code == 200
        data = response.json()
        assert data["total"] == 3
        assert len(data["history"]) == 3

    @pytest.mark.asyncio
    async def test_history_ordered_by_version_desc(
        self, async_client, seed_versions
    ):
        response = await async_client.get(
            "/api/v1/platforms/zhihu/rules/history",
        )

        assert response.status_code == 200
        data = response.json()
        versions = [h["version"] for h in data["history"]]
        assert versions == sorted(versions, reverse=True)

    @pytest.mark.asyncio
    async def test_history_respects_limit(self, async_client, seed_versions):
        response = await async_client.get(
            "/api/v1/platforms/zhihu/rules/history",
            params={"limit": 2},
        )

        assert response.status_code == 200
        data = response.json()
        assert len(data["history"]) == 2
        assert data["total"] == 3

    @pytest.mark.asyncio
    async def test_history_empty_when_no_versions(self, async_client):
        response = await async_client.get(
            "/api/v1/platforms/zhihu/rules/history",
        )

        assert response.status_code == 200
        data = response.json()
        assert data["total"] == 0
        assert data["history"] == []

    @pytest.mark.asyncio
    async def test_history_nonexistent_platform_returns_404(self, async_client):
        response = await async_client.get(
            "/api/v1/platforms/nonexistent_platform/rules/history",
        )

        assert response.status_code == 404

    @pytest.mark.asyncio
    async def test_history_version_has_required_fields(
        self, async_client, seed_versions
    ):
        response = await async_client.get(
            "/api/v1/platforms/zhihu/rules/history",
        )

        assert response.status_code == 200
        data = response.json()
        first = data["history"][0]
        assert "version" in first
        assert "new_rules" in first
        assert "change_summary" in first
        assert "changed_by" in first
        assert "created_at" in first
