"""Tests for brands API."""
import uuid

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.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 test_brand(async_session, test_user):
    """Create a test brand."""
    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):
    """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()


@pytest.fixture
def auth_headers(test_user):
    """Create authentication headers."""
    token = create_access_token(data={"sub": str(test_user.id)})
    return {"Authorization": f"Bearer {token}"}


class TestBrandsAPI:
    """Test cases for brands API."""

    @pytest.mark.asyncio
    async def test_get_brands_empty(self, async_client):
        """Test getting empty brand list."""
        response = await async_client.get("/api/v1/brands/")
        assert response.status_code == 200
        data = response.json()
        assert data["items"] == []
        assert data["total"] == 0

    @pytest.mark.asyncio
    async def test_create_brand(self, async_client, async_session, test_user):
        """Test creating a new brand."""
        brand_data = {
            "name": "New Brand",
            "aliases": ["NewBrand", "NB"],
            "website": "https://newbrand.com",
            "industry": "technology",
            "platforms": ["wenxin", "kimi"],
            "frequency": "weekly",
        }
        response = await async_client.post("/api/v1/brands/", json=brand_data)
        assert response.status_code == 201
        data = response.json()
        assert data["name"] == "New Brand"
        assert data["aliases"] == ["NewBrand", "NB"]
        assert data["website"] == "https://newbrand.com"
        assert data["industry"] == "technology"
        assert data["platforms"] == ["wenxin", "kimi"]
        assert data["frequency"] == "weekly"
        assert data["status"] == "active"
        assert data["user_id"] == str(test_user.id)

    @pytest.mark.asyncio
    async def test_get_brand_by_id(self, async_client, test_brand):
        """Test getting brand by ID."""
        response = await async_client.get(f"/api/v1/brands/{test_brand.id}/")
        assert response.status_code == 200
        data = response.json()
        assert data["id"] == str(test_brand.id)
        assert data["name"] == "Test Brand"
        assert data["aliases"] == ["TestBrand", "TB"]

    @pytest.mark.asyncio
    async def test_get_brand_not_found(self, async_client):
        """Test getting non-existent brand."""
        non_existent_id = uuid.uuid4()
        response = await async_client.get(f"/api/v1/brands/{non_existent_id}/")
        assert response.status_code == 404

    @pytest.mark.asyncio
    async def test_update_brand(self, async_client, test_brand):
        """Test updating a brand."""
        update_data = {
            "aliases": ["Updated", "Alias"],
            "frequency": "daily",
        }
        response = await async_client.put(
            f"/api/v1/brands/{test_brand.id}/", json=update_data
        )
        assert response.status_code == 200
        data = response.json()
        assert data["aliases"] == ["Updated", "Alias"]
        assert data["frequency"] == "daily"
        assert data["name"] == "Test Brand"  # Unchanged

    @pytest.mark.asyncio
    async def test_delete_brand(self, async_client, test_brand):
        """Test deleting a brand."""
        response = await async_client.delete(f"/api/v1/brands/{test_brand.id}/")
        assert response.status_code == 204

        # Verify brand is deleted
        response = await async_client.get(f"/api/v1/brands/{test_brand.id}/")
        assert response.status_code == 404

    @pytest.mark.asyncio
    async def test_list_brands(self, async_client, async_session, test_user):
        """Test listing multiple brands."""
        # Create multiple brands
        for i in range(3):
            brand = Brand(
                user_id=test_user.id,
                name=f"Brand {i}",
                platforms=["wenxin"],
            )
            async_session.add(brand)
        await async_session.commit()

        response = await async_client.get("/api/v1/brands/")
        assert response.status_code == 200
        data = response.json()
        assert len(data["items"]) == 3
        assert data["total"] == 3