"""Pytest configuration for v2 schema migration tests.

Provides shared fixtures and configuration for testing the v2 schema migration
components including database setup, test data, and cleanup procedures.
"""

import pytest
import os
import tempfile
import shutil
from datetime import datetime, timezone
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker
from typing import Generator

from src.database.models import Base, register_model
from src.database.connection import get_database_url


@pytest.fixture(scope="session")
def test_db_url() -> str:
    """Get test database URL."""
    # Use a separate test database to avoid affecting production data
    return "postgresql://localhost/trax_test"


@pytest.fixture(scope="session")
def test_db_engine(test_db_url: str):
    """Create test database engine with proper cleanup."""
    engine = create_engine(test_db_url)
    
    # Create all tables for testing
    Base.metadata.create_all(engine)
    
    yield engine
    
    # Cleanup: drop all tables
    Base.metadata.drop_all(engine)
    engine.dispose()


@pytest.fixture
def db_session(test_db_engine) -> Generator:
    """Create database session for individual tests."""
    Session = sessionmaker(bind=test_db_engine)
    session = Session()
    
    yield session
    
    # Rollback any uncommitted changes
    session.rollback()
    session.close()


@pytest.fixture
def sample_v1_transcripts(db_session):
    """Create sample v1 transcripts for testing."""
    from src.database.models import TranscriptionResult
    
    transcripts = []
    
    # Create sample v1 transcripts
    for i in range(3):
        transcript = TranscriptionResult(
            content={"text": f"Sample v1 transcript {i}"},
            accuracy=0.85 + (i * 0.05),
            processing_time=10.0 + (i * 2.0)
        )
        db_session.add(transcript)
        transcripts.append(transcript)
    
    db_session.commit()
    
    yield transcripts
    
    # Cleanup is handled by db_session fixture


@pytest.fixture
def sample_media_files(db_session):
    """Create sample media files for testing."""
    from src.database.models import MediaFile
    
    media_files = []
    
    # Create sample media files
    for i in range(2):
        media_file = MediaFile(
            filename=f"test_audio_{i}.wav",
            file_size=1024 * 1024 * (i + 1),  # 1MB, 2MB
            duration=60.0 + (i * 30.0),  # 60s, 90s
            mime_type="audio/wav",
            source_path=f"/path/to/source_{i}.wav",
            local_path=f"/path/to/local_{i}.wav",
            file_hash=f"hash_{i}",
            status="ready"
        )
        db_session.add(media_file)
        media_files.append(media_file)
    
    db_session.commit()
    
    yield media_files
    
    # Cleanup is handled by db_session fixture


@pytest.fixture
def sample_youtube_videos(db_session):
    """Create sample YouTube videos for testing."""
    from src.database.models import YouTubeVideo
    
    videos = []
    
    # Create sample YouTube videos
    for i in range(2):
        video = YouTubeVideo(
            youtube_id=f"test_id_{i}",
            title=f"Test Video {i}",
            channel=f"Test Channel {i}",
            description=f"Test description {i}",
            duration_seconds=300 + (i * 60),  # 5min, 6min
            url=f"https://youtube.com/watch?v=test_id_{i}"
        )
        db_session.add(video)
        videos.append(video)
    
    db_session.commit()
    
    yield videos
    
    # Cleanup is handled by db_session fixture


@pytest.fixture
def temp_migration_dir():
    """Create temporary directory for migration testing."""
    temp_dir = tempfile.mkdtemp()
    
    yield temp_dir
    
    # Cleanup
    shutil.rmtree(temp_dir, ignore_errors=True)


@pytest.fixture
def mock_alembic_config(temp_migration_dir):
    """Create mock Alembic configuration for testing."""
    import configparser
    
    # Create alembic.ini
    config = configparser.ConfigParser()
    config.add_section('alembic')
    config.set('alembic', 'script_location', os.path.join(temp_migration_dir, 'migrations'))
    config.set('alembic', 'sqlalchemy.url', get_database_url().replace("/trax", "/trax_test"))
    
    ini_path = os.path.join(temp_migration_dir, 'alembic.ini')
    with open(ini_path, 'w') as f:
        config.write(f)
    
    # Create migrations directory structure
    migrations_dir = os.path.join(temp_migration_dir, 'migrations')
    os.makedirs(migrations_dir, exist_ok=True)
    
    versions_dir = os.path.join(migrations_dir, 'versions')
    os.makedirs(versions_dir, exist_ok=True)
    
    # Create env.py
    env_py_content = '''
from logging.config import fileConfig
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
from src.database.models import Base

config = context.config
if config.config_file_name is not None:
    fileConfig(config.config_file_name)

target_metadata = Base.metadata

def run_migrations_offline() -> None:
    url = config.get_main_option("sqlalchemy.url")
    context.configure(
        url=url,
        target_metadata=target_metadata,
        literal_binds=True,
        dialect_opts={"paramstyle": "named"},
    )

    with context.begin_transaction():
        context.run_migrations()

def run_migrations_online() -> None:
    connectable = engine_from_config(
        config.get_section(config.config_ini_section, {}),
        prefix="sqlalchemy.",
        poolclass=pool.NullPool,
    )

    with connectable.connect() as connection:
        context.configure(
            connection=connection, target_metadata=target_metadata
        )

        with context.begin_transaction():
            context.run_migrations()

if context.is_offline_mode():
    run_migrations_offline()
else:
    run_migrations_online()
'''
    
    with open(os.path.join(migrations_dir, 'env.py'), 'w') as f:
        f.write(env_py_content)
    
    # Create script.py.mako
    script_mako_content = '''"""${message}

Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}

"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}

# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}


def upgrade() -> None:
    ${upgrades if upgrades else "pass"}


def downgrade() -> None:
    ${downgrades if downgrades else "pass"}
'''
    
    with open(os.path.join(migrations_dir, 'script.py.mako'), 'w') as f:
        f.write(script_mako_content)
    
    return ini_path


@pytest.fixture
def test_data_cleanup(db_session):
    """Clean up test data after each test."""
    yield
    
    # Clean up any remaining test data
    try:
        # Delete test data from all tables
        tables = ['speaker_profiles', 'processing_jobs', 'transcription_results', 
                 'media_files', 'youtube_videos']
        
        for table in tables:
            try:
                db_session.execute(text(f"DELETE FROM {table}"))
            except Exception:
                # Table might not exist yet, which is fine
                pass
        
        db_session.commit()
    except Exception:
        # Ignore cleanup errors
        pass


# Pytest configuration
def pytest_configure(config):
    """Configure pytest for v2 schema migration tests."""
    # Add custom markers
    config.addinivalue_line(
        "markers", "slow: marks tests as slow (deselect with '-m \"not slow\"')"
    )
    config.addinivalue_line(
        "markers", "integration: marks tests as integration tests"
    )
    config.addinivalue_line(
        "markers", "migration: marks tests as migration tests"
    )


def pytest_collection_modifyitems(config, items):
    """Modify test collection to add markers based on test names."""
    for item in items:
        # Mark migration tests
        if "migration" in item.nodeid.lower():
            item.add_marker(pytest.mark.migration)
        
        # Mark integration tests
        if "integration" in item.nodeid.lower() or "repository" in item.nodeid.lower():
            item.add_marker(pytest.mark.integration)
        
        # Mark slow tests
        if any(keyword in item.nodeid.lower() for keyword in ["performance", "migration"]):
            item.add_marker(pytest.mark.slow)
