import os
import pytest
import pytest_asyncio
from sqlalchemy.engine import URL
from sqlalchemy.pool import StaticPool
from unittest.mock import MagicMock, AsyncMock
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine

from src.core.database import Base

pytest_plugins = []


@pytest.fixture
async def async_db():
    """Create an in-memory SQLite database for testing."""
    engine = create_async_engine(
        "sqlite+aiosqlite:///:memory:",
        poolclass=StaticPool,
        echo=False,
    )
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)

    async with AsyncSession(engine, expire_on_commit=False) as session:
        yield session

    await engine.dispose()


@pytest.fixture
def mock_auth_token():
    """Mock authentication token payload."""
    return {
        "sub": "test-user-id",
        "type": "user",
        "empresa_id": "test-empresa-id",
        "exp": 9999999999,
    }


@pytest.fixture
def mock_enterprise_auth():
    """Mock enterprise authentication token payload."""
    return {
        "sub": "enterprise-id",
        "type": "enterprise",
        "empresa_id": "enterprise-id",
        "exp": 9999999999,
    }


@pytest.fixture
def mock_s3_client():
    """Mock AWS S3 client."""
    client = AsyncMock()
    client.put_object = AsyncMock()
    client.get_object = AsyncMock()
    client.delete_object = AsyncMock()
    return client


@pytest.fixture
def mock_logger():
    """Mock logger for testing."""
    return MagicMock()


@pytest_asyncio.fixture
async def mock_db():
    """Database session for tests.

    Uses MySQL when MOCK_* vars are provided; otherwise falls back to mocks.
    """
    host = os.getenv("MOCK_HOST")
    port = os.getenv("MOCK_PORT")
    user = os.getenv("MOCK_USER")
    password = os.getenv("MOCK_PASSWORD")
    database = os.getenv("MOCK_DATABASE")

    use_real_db = all([host, port, user, password, database])

    if use_real_db:
        async_database_url = URL.create(
            drivername="mysql+asyncmy",
            username=user,
            password=password,
            host=host,
            port=int(port),
            database=database,
        )
        engine = create_async_engine(
            async_database_url,
            pool_pre_ping=True,
            pool_recycle=1800,
            connect_args={"charset": "utf8mb4", "autocommit": False},
        )
        async with AsyncSession(engine, expire_on_commit=False) as session:
            yield session
        await engine.dispose()
    else:
        db = AsyncMock(spec=AsyncSession)
        db.execute = AsyncMock()
        db.add = MagicMock()
        db.commit = AsyncMock()
        db.rollback = AsyncMock()
        db.refresh = AsyncMock()
        yield db
