"""
V2 API Test Configuration and Fixtures
Provides test fixtures for authentication, database, and API testing
"""

import pytest
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import StaticPool

# IMPORTANT: Monkey patch database module BEFORE importing app
# This prevents the app from connecting to production database
import app.core.database as db_module

# Create a test engine for the entire test session
_test_engine = create_engine(
    "sqlite:///:memory:",
    connect_args={"check_same_thread": False},
    poolclass=StaticPool,
)

# Replace the global engine and SessionLocal
db_module.engine = _test_engine
db_module.SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=_test_engine)

# Now safely import app (it will use our test database)
from app.main import app
from app.core.database import Base, get_db
from app.core.security import create_access_token
from app.models.user import User
from app.models.task import Task


@pytest.fixture(scope="function")
def engine():
    """Get test database engine and reset tables for each test"""
    Base.metadata.drop_all(bind=_test_engine)
    Base.metadata.create_all(bind=_test_engine)
    yield _test_engine
    # Tables will be dropped at the start of next test


@pytest.fixture(scope="function")
def db(engine):
    """Create test database session"""
    TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
    db = TestingSessionLocal()
    try:
        yield db
    finally:
        db.close()


@pytest.fixture(scope="function")
def client(db):
    """Create FastAPI test client with test database"""
    # Override get_db to use the same session as the test
    def override_get_db():
        try:
            yield db
        finally:
            # Don't close the session, it's managed by the db fixture
            pass

    app.dependency_overrides[get_db] = override_get_db
    with TestClient(app) as test_client:
        yield test_client
    app.dependency_overrides.clear()


@pytest.fixture
def test_user(db):
    """Create a test user"""
    # Ensure test_user is always created first by checking if it exists
    user = db.query(User).filter(User.email == "test@example.com").first()
    if not user:
        user = User(
            email="test@example.com",
            display_name="Test User",
            is_active=True
        )
        db.add(user)
        db.commit()
        db.refresh(user)
    return user


@pytest.fixture
def admin_user(db):
    """Create an admin user"""
    user = db.query(User).filter(User.email == "ymirliu@panjit.com.tw").first()
    if not user:
        user = User(
            email="ymirliu@panjit.com.tw",
            display_name="Admin User",
            is_active=True
        )
        db.add(user)
        db.commit()
        db.refresh(user)
    return user


@pytest.fixture
def auth_token(test_user):
    """Create authentication token for test user"""
    token_data = {
        "sub": str(test_user.id),
        "email": test_user.email
    }
    return create_access_token(token_data)


@pytest.fixture
def admin_token(admin_user):
    """Create authentication token for admin user"""
    token_data = {
        "sub": str(admin_user.id),
        "email": admin_user.email
    }
    return create_access_token(token_data)


@pytest.fixture
def test_task(test_user, db):
    """Create a test task (depends on test_user to ensure user exists first)"""
    task = Task(
        user_id=test_user.id,
        task_id="test-task-123",
        filename="test.pdf",
        file_type="application/pdf",
        status="pending"
    )
    db.add(task)
    db.commit()
    db.refresh(task)
    return task
