# tests/integration/middleware/conftest.py
"""
Fixtures specific to middleware integration tests.

The middleware (StoreContextMiddleware, ThemeContextMiddleware) calls get_db()
directly rather than using FastAPI's dependency injection. Since the middleware
modules import get_db at module load time (before tests run), we need to patch
get_db directly in each middleware module.

Solution: We patch get_db in both middleware.store_context and middleware.theme_context
to use a generator that yields the test database session.
"""

import uuid
from unittest.mock import patch

import pytest
from fastapi.testclient import TestClient

from app.core.database import get_db
from app.modules.cms.models import StoreTheme
from app.modules.tenancy.models import Merchant, Store, StoreDomain
from main import app

# Register test routes for middleware tests
from tests.integration.middleware.middleware_test_routes import (
    admin_router,
    api_router,
    store_router,
    storefront_router,
)
from tests.integration.middleware.middleware_test_routes import (
    router as test_router,
)

# Include the test routers in the app (only once)
if not any(r.path.startswith("/middleware-test") for r in app.routes if hasattr(r, "path")):
    app.include_router(test_router)
    app.include_router(api_router)
    app.include_router(admin_router)
    app.include_router(store_router)
    app.include_router(storefront_router)


@pytest.fixture
def client(db):
    """
    Create a test client with database dependency override.

    This patches:
    1. get_db in both middleware modules to use the test database
    2. settings.main_domain in store_context to use 'platform.com' for testing

    This ensures middleware can see test fixtures and detect subdomains correctly.
    """
    # Override the dependency for FastAPI endpoints
    def override_get_db():
        try:
            yield db
        finally:
            pass

    app.dependency_overrides[get_db] = override_get_db

    # Patch get_db in middleware modules - they have their own imports
    # The middleware calls: db_gen = get_db(); db = next(db_gen)
    # Also patch settings.main_domain so subdomain detection works with test hosts
    # Also bypass StorefrontAccessMiddleware subscription check for test routes —
    # these tests verify store context detection, not subscription access.
    from middleware.storefront_access import SKIP_PATH_PREFIXES

    test_skip_prefixes = SKIP_PATH_PREFIXES + ("/middleware-test/",)

    with patch("middleware.platform_context.get_db", override_get_db):
        with patch("middleware.store_context.get_db", override_get_db):
            with patch("middleware.theme_context.get_db", override_get_db):
                with patch("middleware.store_context.settings") as mock_settings:
                    with patch("middleware.storefront_access.SKIP_PATH_PREFIXES", test_skip_prefixes):
                        mock_settings.main_domain = "platform.com"
                        client = TestClient(app)
                        yield client

    # Clean up
    if get_db in app.dependency_overrides:
        del app.dependency_overrides[get_db]


@pytest.fixture
def middleware_test_merchant(db, test_user):
    """Create a merchant for middleware test stores."""
    unique_id = str(uuid.uuid4())[:8]
    merchant = Merchant(
        name=f"Middleware Test Merchant {unique_id}",
        contact_email=f"middleware{unique_id}@test.com",
        owner_user_id=test_user.id,
        is_active=True,
        is_verified=True,
    )
    db.add(merchant)
    db.commit()
    db.refresh(merchant)
    return merchant


@pytest.fixture
def store_with_subdomain(db, middleware_test_merchant):
    """Create a store with subdomain for testing."""
    unique_id = str(uuid.uuid4())[:8]
    store = Store(
        merchant_id=middleware_test_merchant.id,
        name="Test Store",
        store_code=f"TESTSTORE_{unique_id.upper()}",
        subdomain="teststore",
        is_active=True,
        is_verified=True,
    )
    db.add(store)
    db.commit()
    db.refresh(store)
    return store


@pytest.fixture
def store_with_custom_domain(db, middleware_test_merchant):
    """Create a store with custom domain for testing."""
    unique_id = str(uuid.uuid4())[:8]
    store = Store(
        merchant_id=middleware_test_merchant.id,
        name="Custom Domain Store",
        store_code=f"CUSTOMSTORE_{unique_id.upper()}",
        subdomain="customstore",
        is_active=True,
        is_verified=True,
    )
    db.add(store)
    db.commit()
    db.refresh(store)

    # Add custom domain
    domain = StoreDomain(
        store_id=store.id, domain="customdomain.com", is_active=True, is_primary=True
    )
    db.add(domain)
    db.commit()

    return store


@pytest.fixture
def store_with_theme(db, middleware_test_merchant):
    """Create a store with custom theme for testing."""
    unique_id = str(uuid.uuid4())[:8]
    store = Store(
        merchant_id=middleware_test_merchant.id,
        name="Themed Store",
        store_code=f"THEMEDSTORE_{unique_id.upper()}",
        subdomain="themedstore",
        is_active=True,
        is_verified=True,
    )
    db.add(store)
    db.commit()
    db.refresh(store)

    # Add custom theme
    theme = StoreTheme(
        store_id=store.id,
        theme_name="custom",
        colors={
            "primary": "#FF5733",
            "secondary": "#33FF57",
            "accent": "#ec4899",
            "background": "#ffffff",
            "text": "#1f2937",
            "border": "#e5e7eb",
        },
        logo_url="/static/stores/themedstore/logo.png",
        favicon_url="/static/stores/themedstore/favicon.ico",
        custom_css="body { background: #FF5733; }",
    )
    db.add(theme)
    db.commit()

    return store


@pytest.fixture
def middleware_inactive_store(db, middleware_test_merchant):
    """Create an inactive store for testing."""
    unique_id = str(uuid.uuid4())[:8]
    store = Store(
        merchant_id=middleware_test_merchant.id,
        name="Inactive Store",
        store_code=f"INACTIVE_{unique_id.upper()}",
        subdomain="inactive",
        is_active=False,
        is_verified=False,
    )
    db.add(store)
    db.commit()
    db.refresh(store)
    return store
