"""Integration tests for full GEO platform flows."""
import uuid
from datetime import datetime

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

from app.database import Base
from app.main import app
from app.models.user import User
from app.models.brand import Brand
from app.models.competitor import Competitor
from app.models.query import Query as QueryModel
from app.models.citation_record import CitationRecord
from app.api.deps import get_current_user, get_db
from app.services.auth import create_access_token


@pytest_asyncio.fixture
async def async_engine():
    """Create async engine for testing with SQLite."""
    from sqlalchemy.ext.asyncio import create_async_engine
    from sqlalchemy.pool import StaticPool

    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):
    """Create async session for testing."""
    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 test_user(async_session):
    """Create a test user."""
    user = User(
        id=uuid.uuid4(),
        email="test@example.com",
        password_hash="hashed_password",
        name="Test User",
        plan="free",
        max_queries=5,
        is_active=True,
        email_verified=True,
    )
    async_session.add(user)
    await async_session.commit()
    await async_session.refresh(user)
    return user


@pytest_asyncio.fixture
async def async_client(async_session, test_user):
    """Create async client for API testing."""

    async def override_get_db():
        yield async_session

    async def override_get_current_user():
        return test_user

    app.dependency_overrides[get_db] = override_get_db
    app.dependency_overrides[get_current_user] = override_get_current_user

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

    app.dependency_overrides.clear()


class TestFullBrandQueryFlow:
    """Integration test for complete brand query flow."""

    @pytest.mark.asyncio
    async def test_full_brand_query_flow(self, async_client, async_session, test_user):
        """
        Test complete flow:
        1. Create a brand
        2. Add a competitor
        3. Create a query for the brand
        4. Simulate citation records
        5. Get brand score
        6. Get brand score history
        7. Get citations stats
        """
        # Step 1: Create a brand
        brand_data = {
            "name": "TestBrand",
            "aliases": ["TestBrand", "TB"],
            "website": "https://testbrand.com",
            "industry": "technology",
            "platforms": ["wenxin", "kimi"],
            "frequency": "weekly",
        }
        response = await async_client.post("/api/v1/brands/", json=brand_data)
        assert response.status_code == 201
        brand = response.json()
        brand_id = brand["id"]
        assert brand["name"] == "TestBrand"

        # Step 2: Add a competitor
        competitor_data = {
            "name": "CompetitorA",
            "aliases": ["CompA"],
        }
        response = await async_client.post(
            f"/api/v1/brands/{brand_id}/competitors/",
            json=competitor_data
        )
        assert response.status_code == 201
        competitor = response.json()
        assert competitor["name"] == "CompetitorA"

        # Step 3: Create a query (using Query model directly)
        query = QueryModel(
            id=uuid.uuid4(),
            user_id=test_user.id,
            keyword="AI assistant",
            target_brand="TestBrand",
            brand_aliases=["TestBrand", "TB"],
            platforms=["wenxin", "kimi"],
            frequency="weekly",
            status="active",
        )
        async_session.add(query)
        await async_session.commit()

        # Step 4: Create citation records (simulating data collection)
        citations = [
            CitationRecord(
                id=uuid.uuid4(),
                query_id=query.id,
                platform="wenxin",
                cited=True,
                citation_position=1,
                citation_text="TestBrand is a leading AI company...",
                competitor_brands=["CompetitorA"],
                raw_response="{}",
                confidence=0.95,
                match_type="exact",
                queried_at=datetime.now(),
            ),
            CitationRecord(
                id=uuid.uuid4(),
                query_id=query.id,
                platform="kimi",
                cited=True,
                citation_position=2,
                citation_text="TestBrand offers great AI services...",
                competitor_brands=["CompetitorA"],
                raw_response="{}",
                confidence=0.88,
                match_type="alias",
                queried_at=datetime.now(),
            ),
            CitationRecord(
                id=uuid.uuid4(),
                query_id=query.id,
                platform="wenxin",
                cited=False,
                citation_position=None,
                citation_text=None,
                competitor_brands=[],
                raw_response="{}",
                confidence=0.3,
                match_type="none",
                queried_at=datetime.now(),
            ),
        ]
        for citation in citations:
            async_session.add(citation)
        await async_session.commit()

        # Step 5: Get brand score
        response = await async_client.get(f"/api/v1/brands/{brand_id}/score/")
        assert response.status_code == 200
        score_data = response.json()
        assert "mention_rate_score" in score_data
        assert "sov_score" in score_data
        assert "quality_score" in score_data
        assert "overall_score" in score_data
        # With 2 cited out of 3 queries, mention rate should be ~66.67
        assert score_data["mention_rate_score"] == pytest.approx(66.67, rel=0.1)

        # Step 6: Get brand score history
        response = await async_client.get(f"/api/v1/brands/{brand_id}/score/history/")
        assert response.status_code == 200
        history_data = response.json()
        assert "history" in history_data
        assert "total" in history_data

        # Step 7: Get citations stats
        response = await async_client.get(
            f"/api/v1/citations/stats?brand_id={brand_id}"
        )
        assert response.status_code == 200
        stats_data = response.json()
        assert "total_queries" in stats_data
        assert "total_citations" in stats_data
        assert "citation_rate" in stats_data
        assert stats_data["total_queries"] == 3
        assert stats_data["total_citations"] == 2


class TestCSVExportFlow:
    """Integration test for CSV export flow."""

    @pytest.mark.asyncio
    async def test_csv_export_flow(self, async_client, async_session, test_user):
        """
        Test CSV export flow:
        1. Create a brand
        2. Create a query with citations
        3. Export CSV
        4. Verify CSV content
        """
        # Step 1: Create a brand
        brand_data = {
            "name": "ExportTestBrand",
            "aliases": ["ETB"],
            "website": "https://exporttest.com",
            "industry": "technology",
            "platforms": ["wenxin"],
            "frequency": "weekly",
        }
        response = await async_client.post("/api/v1/brands/", json=brand_data)
        assert response.status_code == 201
        brand = response.json()

        # Step 2: Create a query with citations
        query = QueryModel(
            id=uuid.uuid4(),
            user_id=test_user.id,
            keyword="export test keyword",
            target_brand="ExportTestBrand",
            brand_aliases=["ETB"],
            platforms=["wenxin"],
            frequency="weekly",
            status="active",
        )
        async_session.add(query)
        await async_session.commit()

        citation = CitationRecord(
            id=uuid.uuid4(),
            query_id=query.id,
            platform="wenxin",
            cited=True,
            citation_position=1,
            citation_text="ExportTestBrand is featured in this response...",
            competitor_brands=[],
            raw_response="{}",
            confidence=0.92,
            match_type="exact",
            queried_at=datetime.now(),
        )
        async_session.add(citation)
        await async_session.commit()

        # Step 3: Export CSV
        response = await async_client.get(
            f"/api/v1/reports/export/csv?query_id={query.id}"
        )
        assert response.status_code == 200
        assert response.headers["content-type"] == "text/csv; charset=utf-8"

        # Step 4: Verify CSV content
        content = response.text
        lines = content.split("\n")
        # Header row should contain column names
        assert "查询关键词" in lines[0]
        assert "目标品牌" in lines[0]
        assert "是否引用" in lines[0]
        # Data should contain our test data
        assert "export test keyword" in content
        assert "ExportTestBrand" in content
        assert "是" in content  # cited = True


class TestBrandNotFoundHandling:
    """Integration test for brand not found handling."""

    @pytest.mark.asyncio
    async def test_score_endpoint_brand_not_found(self, async_client):
        """Test that score endpoint returns 404 for non-existent brand."""
        fake_id = uuid.uuid4()
        response = await async_client.get(f"/api/v1/brands/{fake_id}/score/")
        assert response.status_code == 404

    @pytest.mark.asyncio
    async def test_history_endpoint_brand_not_found(self, async_client):
        """Test that history endpoint returns 404 for non-existent brand."""
        fake_id = uuid.uuid4()
        response = await async_client.get(f"/api/v1/brands/{fake_id}/score/history/")
        assert response.status_code == 404

    @pytest.mark.asyncio
    async def test_citations_stats_brand_not_found(self, async_client):
        """Test that citations stats returns 404 for non-existent brand."""
        fake_id = uuid.uuid4()
        response = await async_client.get(f"/api/v1/citations/stats?brand_id={fake_id}")
        assert response.status_code == 404