"""
Pytest fixtures for testing
"""
import pytest
import pytest_asyncio
from httpx import AsyncClient
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
from datetime import datetime, timedelta
import jwt

from main import app
from config import settings
from models import Base, get_db
from models.user import User, UserRole
from utils.jwt_utils import create_access_token
import uuid


# Test database URL - use separate test database
TEST_DATABASE_URL = settings.DATABASE_URL.replace("/geutebruck_api", "/geutebruck_api_test")


@pytest.fixture(scope="session")
def event_loop():
    """Create an instance of the default event loop for the test session"""
    import asyncio
    loop = asyncio.get_event_loop_policy().new_event_loop()
    yield loop
    loop.close()


@pytest_asyncio.fixture(scope="function")
async def test_db_engine():
    """Create test database engine"""
    engine = create_async_engine(TEST_DATABASE_URL, echo=False)

    # Create all tables
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)

    yield engine

    # Drop all tables after test
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.drop_all)

    await engine.dispose()


@pytest_asyncio.fixture(scope="function")
async def test_db_session(test_db_engine):
    """Create test database session"""
    AsyncTestingSessionLocal = async_sessionmaker(
        test_db_engine,
        class_=AsyncSession,
        expire_on_commit=False
    )

    async with AsyncTestingSessionLocal() as session:
        yield session


@pytest_asyncio.fixture(scope="function")
async def async_client(test_db_session):
    """Create async HTTP client for testing"""

    # Override the get_db dependency to use test database
    async def override_get_db():
        yield test_db_session

    app.dependency_overrides[get_db] = override_get_db

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

    # Clear overrides
    app.dependency_overrides.clear()


@pytest_asyncio.fixture(scope="function")
async def test_admin_user(test_db_session):
    """Create test admin user"""
    from passlib.hash import bcrypt

    user = User(
        id=uuid.uuid4(),
        username="admin",
        password_hash=bcrypt.hash("admin123"),
        role=UserRole.ADMINISTRATOR,
        created_at=datetime.utcnow(),
        updated_at=datetime.utcnow()
    )

    test_db_session.add(user)
    await test_db_session.commit()
    await test_db_session.refresh(user)

    return user


@pytest_asyncio.fixture(scope="function")
async def test_operator_user(test_db_session):
    """Create test operator user"""
    from passlib.hash import bcrypt

    user = User(
        id=uuid.uuid4(),
        username="operator",
        password_hash=bcrypt.hash("operator123"),
        role=UserRole.OPERATOR,
        created_at=datetime.utcnow(),
        updated_at=datetime.utcnow()
    )

    test_db_session.add(user)
    await test_db_session.commit()
    await test_db_session.refresh(user)

    return user


@pytest_asyncio.fixture(scope="function")
async def test_viewer_user(test_db_session):
    """Create test viewer user"""
    from passlib.hash import bcrypt

    user = User(
        id=uuid.uuid4(),
        username="viewer",
        password_hash=bcrypt.hash("viewer123"),
        role=UserRole.VIEWER,
        created_at=datetime.utcnow(),
        updated_at=datetime.utcnow()
    )

    test_db_session.add(user)
    await test_db_session.commit()
    await test_db_session.refresh(user)

    return user


@pytest.fixture
def auth_token(test_admin_user):
    """Generate valid authentication token for admin user"""
    token_data = {
        "sub": str(test_admin_user.id),
        "username": test_admin_user.username,
        "role": test_admin_user.role.value
    }
    return create_access_token(token_data)


@pytest.fixture
def operator_token(test_operator_user):
    """Generate valid authentication token for operator user"""
    token_data = {
        "sub": str(test_operator_user.id),
        "username": test_operator_user.username,
        "role": test_operator_user.role.value
    }
    return create_access_token(token_data)


@pytest.fixture
def viewer_token(test_viewer_user):
    """Generate valid authentication token for viewer user"""
    token_data = {
        "sub": str(test_viewer_user.id),
        "username": test_viewer_user.username,
        "role": test_viewer_user.role.value
    }
    return create_access_token(token_data)


@pytest.fixture
def expired_token():
    """Generate expired authentication token"""
    token_data = {
        "sub": str(uuid.uuid4()),
        "username": "testuser",
        "role": "viewer",
        "exp": datetime.utcnow() - timedelta(hours=1),  # Expired 1 hour ago
        "iat": datetime.utcnow() - timedelta(hours=2),
        "type": "access"
    }
    return jwt.encode(token_data, settings.JWT_SECRET_KEY, algorithm=settings.JWT_ALGORITHM)
