"""内容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.user import User
from app.models.brand import Brand
from app.api.deps import get_current_user, get_db
from app.services.auth import hash_password, create_access_token


# ==================== Fixtures ====================

@pytest_asyncio.fixture
async def async_engine():
    """创建测试用SQLite异步引擎"""
    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 test_user(async_session):
    """创建测试用户"""
    user = User(
        id=uuid.uuid4(),
        email="test@example.com",
        password_hash=hash_password("Test@123456"),
        name="Test User",
        plan="free",
        max_queries=5,
        is_active=True,
        email_verified=True,
        organization_id=uuid.uuid4(),  # 需要organization_id用于内容API
    )
    async_session.add(user)
    await async_session.commit()
    await async_session.refresh(user)
    return user


@pytest_asyncio.fixture
async def test_brand(async_session, test_user):
    """创建测试品牌"""
    brand = Brand(
        id=uuid.uuid4(),
        user_id=test_user.id,
        name="Test Brand",
        aliases=["TestBrand", "TB"],
        website="https://testbrand.com",
        industry="technology",
        platforms=["wenxin", "kimi"],
        frequency="weekly",
        status="active",
    )
    async_session.add(brand)
    await async_session.commit()
    await async_session.refresh(brand)
    return brand


@pytest_asyncio.fixture
async def async_client(async_session, test_user):
    """创建异步HTTP客户端用于API测试"""

    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()


@pytest.fixture
def auth_headers(test_user):
    """创建认证请求头"""
    token = create_access_token(data={"sub": str(test_user.id)})
    return {"Authorization": f"Bearer {token}"}


# ==================== 测试类 ====================

class TestContentAPI:
    """内容管理API测试"""

    @pytest.mark.asyncio
    async def test_list_contents_empty(self, async_client):
        """测试获取空内容列表"""
        response = await async_client.get("/api/v1/contents/")

        assert response.status_code == 200
        data = response.json()
        assert isinstance(data, list)
        assert len(data) == 0

    @pytest.mark.asyncio
    async def test_create_content(self, async_client, test_user):
        """测试创建内容"""
        content_data = {
            "title": "测试文章标题",
            "body": "这是测试文章的内容",
            "content_type": "article",
            "tags": ["测试", "文章"],
        }
        response = await async_client.post("/api/v1/contents/", json=content_data)

        assert response.status_code == 201
        data = response.json()
        assert data["title"] == "测试文章标题"
        assert data["body"] == "这是测试文章的内容"
        assert data["content_type"] == "article"
        assert data["status"] == "draft"
        assert "id" in data

    @pytest.mark.asyncio
    async def test_get_content_by_id(self, async_client, test_user):
        """测试通过ID获取内容"""
        # 先创建内容
        create_response = await async_client.post(
            "/api/v1/contents/",
            json={
                "title": "测试内容",
                "body": "测试内容正文",
                "content_type": "article",
            }
        )
        content_id = create_response.json()["id"]

        # 获取内容
        response = await async_client.get(f"/api/v1/contents/{content_id}")

        assert response.status_code == 200
        data = response.json()
        assert data["id"] == content_id
        assert data["title"] == "测试内容"

    @pytest.mark.asyncio
    async def test_get_content_not_found(self, async_client):
        """测试获取不存在的内容"""
        non_existent_id = uuid.uuid4()
        response = await async_client.get(f"/api/v1/contents/{non_existent_id}")

        assert response.status_code == 404

    @pytest.mark.asyncio
    async def test_update_content(self, async_client, test_user):
        """测试更新内容"""
        # 先创建内容
        create_response = await async_client.post(
            "/api/v1/contents/",
            json={
                "title": "原始标题",
                "body": "原始内容",
                "content_type": "article",
            }
        )
        content_id = create_response.json()["id"]

        # 更新内容
        update_data = {
            "title": "更新后的标题",
            "body": "更新后的内容",
            "status": "published",
        }
        response = await async_client.put(
            f"/api/v1/contents/{content_id}", json=update_data
        )

        assert response.status_code == 200
        data = response.json()
        assert data["title"] == "更新后的标题"
        assert data["body"] == "更新后的内容"

    @pytest.mark.asyncio
    async def test_update_content_partial(self, async_client, test_user):
        """测试部分更新内容"""
        # 先创建内容
        create_response = await async_client.post(
            "/api/v1/contents/",
            json={
                "title": "原始标题",
                "body": "原始内容",
            }
        )
        content_id = create_response.json()["id"]

        # 只更新标题
        response = await async_client.put(
            f"/api/v1/contents/{content_id}",
            json={"title": "新标题"}
        )

        assert response.status_code == 200
        data = response.json()
        assert data["title"] == "新标题"
        assert data["body"] == "原始内容"  # 保持不变

    @pytest.mark.asyncio
    async def test_delete_content(self, async_client, test_user):
        """测试删除内容"""
        # 先创建内容
        create_response = await async_client.post(
            "/api/v1/contents/",
            json={
                "title": "待删除内容",
                "body": "内容正文",
            }
        )
        content_id = create_response.json()["id"]

        # 删除内容
        response = await async_client.delete(f"/api/v1/contents/{content_id}")
        assert response.status_code == 204

        # 验证已删除
        get_response = await async_client.get(f"/api/v1/contents/{content_id}")
        assert get_response.status_code == 404

    @pytest.mark.asyncio
    async def test_publish_content(self, async_client, test_user):
        """测试发布内容"""
        # 先创建内容
        create_response = await async_client.post(
            "/api/v1/contents/",
            json={
                "title": "待发布内容",
                "body": "内容正文",
            }
        )
        content_id = create_response.json()["id"]

        # 发布内容
        response = await async_client.post(f"/api/v1/contents/{content_id}/publish")

        assert response.status_code == 200
        data = response.json()
        assert data["status"] == "published"
        assert data["published_at"] is not None

    @pytest.mark.asyncio
    async def test_list_contents_with_filter(self, async_client, test_user):
        """测试内容列表过滤"""
        # 创建多个不同类型的内容
        for i, content_type in enumerate(["article", "post", "article"]):
            await async_client.post(
                "/api/v1/contents/",
                json={
                    "title": f"内容 {i}",
                    "body": "正文",
                    "content_type": content_type,
                }
            )

        # 按类型过滤
        response = await async_client.get("/api/v1/contents/?content_type=article")

        assert response.status_code == 200
        data = response.json()
        assert isinstance(data, list)
        for item in data:
            assert item["content_type"] == "article"

    @pytest.mark.asyncio
    async def test_list_contents_with_status_filter(self, async_client, test_user):
        """测试内容列表按状态过滤"""
        # 创建一个草稿和一个已发布
        draft_response = await async_client.post(
            "/api/v1/contents/",
            json={"title": "草稿", "body": "正文", "content_type": "article"}
        )

        published_response = await async_client.post(
            "/api/v1/contents/",
            json={"title": "已发布", "body": "正文", "content_type": "article"}
        )
        await async_client.post(f"/api/v1/contents/{published_response.json()['id']}/publish")

        # 只获取草稿
        response = await async_client.get("/api/v1/contents/?status=draft")

        assert response.status_code == 200
        data = response.json()
        assert isinstance(data, list)
        for item in data:
            assert item["status"] == "draft"


class TestContentGenerationAPI:
    """内容生成API测试"""

    @pytest.mark.asyncio
    async def test_list_topics(self, async_client):
        """测试获取母题库列表"""
        response = await async_client.get("/api/v1/content/topics")

        assert response.status_code == 200
        data = response.json()
        assert isinstance(data, list)
        # 应该有多个母题
        assert len(data) > 0

        # 验证母题结构
        for topic in data:
            assert "id" in topic
            assert "name" in topic
            assert "description" in topic

    @pytest.mark.asyncio
    async def test_get_topic_detail(self, async_client):
        """测试获取母题详情"""
        # 获取第一个可用的topic id
        topics_response = await async_client.get("/api/v1/content/topics")
        topics = topics_response.json()

        if len(topics) > 0:
            topic_id = topics[0]["id"]
            response = await async_client.get(f"/api/v1/content/topics/{topic_id}")

            assert response.status_code == 200
            data = response.json()
            assert data["id"] == topic_id
            assert "prompt_template" in data

    @pytest.mark.asyncio
    async def test_get_topic_not_found(self, async_client):
        """测试获取不存在的母题"""
        response = await async_client.get("/api/v1/content/topics/nonexistent_topic")

        assert response.status_code == 404


class TestBrandKnowledgeAPI:
    """品牌知识库API测试"""

    @pytest.mark.asyncio
    async def test_list_brand_knowledge_empty(self, async_client):
        """测试获取空品牌知识库"""
        response = await async_client.get("/api/v1/contents/knowledge/")

        assert response.status_code == 200
        data = response.json()
        assert isinstance(data, list)
        assert len(data) == 0

    @pytest.mark.asyncio
    async def test_create_brand_knowledge(self, async_client, test_user):
        """测试创建品牌知识条目"""
        knowledge_data = {
            "category": "product",
            "title": "产品介绍",
            "body": "这是产品的详细介绍",
            "source": "官网",
        }
        response = await async_client.post(
            "/api/v1/contents/knowledge/", json=knowledge_data
        )

        assert response.status_code == 201
        data = response.json()
        assert data["title"] == "产品介绍"
        assert data["category"] == "product"
        assert data["body"] == "这是产品的详细介绍"
        assert data["source"] == "官网"
        assert "id" in data

    @pytest.mark.asyncio
    async def test_list_brand_knowledge_with_category(self, async_client, test_user):
        """测试按分类获取品牌知识"""
        # 创建不同分类的知识
        categories = ["product", "technology", "product"]
        for i, cat in enumerate(categories):
            await async_client.post(
                "/api/v1/contents/knowledge/",
                json={"category": cat, "title": f"知识 {i}", "body": "正文"}
            )

        # 按product分类过滤
        response = await async_client.get("/api/v1/contents/knowledge/?category=product")

        assert response.status_code == 200
        data = response.json()
        assert isinstance(data, list)
        for item in data:
            assert item["category"] == "product"

    @pytest.mark.asyncio
    async def test_update_brand_knowledge(self, async_client, test_user):
        """测试更新品牌知识"""
        # 先创建知识
        create_response = await async_client.post(
            "/api/v1/contents/knowledge/",
            json={"category": "test", "title": "原始标题", "body": "原始内容"}
        )
        knowledge_id = create_response.json()["id"]

        # 更新
        response = await async_client.put(
            f"/api/v1/contents/knowledge/{knowledge_id}",
            json={"title": "新标题", "body": "新内容"}
        )

        assert response.status_code == 200
        data = response.json()
        assert data["title"] == "新标题"
        assert data["body"] == "新内容"

    @pytest.mark.asyncio
    async def test_delete_brand_knowledge(self, async_client, test_user):
        """测试删除品牌知识"""
        # 先创建知识
        create_response = await async_client.post(
            "/api/v1/contents/knowledge/",
            json={"category": "test", "title": "待删除", "body": "正文"}
        )
        knowledge_id = create_response.json()["id"]

        # 删除
        response = await async_client.delete(f"/api/v1/contents/knowledge/{knowledge_id}")

        assert response.status_code == 204

        # 验证删除 - 通过列出知识来确认
        list_response = await async_client.get("/api/v1/contents/knowledge/")
        knowledge_ids = [item["id"] for item in list_response.json()]
        assert knowledge_id not in knowledge_ids
