# tests/integration/middleware/test_middleware_stack.py
"""
Integration tests for the complete middleware stack.

These tests verify that all middleware components work together correctly
through real HTTP requests, ensuring proper execution order and state injection.
"""

from unittest.mock import patch

import pytest


@pytest.mark.integration
@pytest.mark.middleware
class TestMiddlewareStackIntegration:
    """Test the full middleware stack with real HTTP requests."""

    # ========================================================================
    # Admin Context Tests
    # ========================================================================

    def test_admin_path_sets_admin_context(self, client):
        """Test that /admin/* paths set ADMIN context type."""
        # Create a simple endpoint to inspect request state
        from fastapi import Request

        from main import app

        @app.get("/admin/test-context")
        async def test_admin_context(request: Request):
            return {
                "context_type": (
                    request.state.context_type.value
                    if hasattr(request.state, "context_type")
                    else None
                ),
                "has_vendor": hasattr(request.state, "vendor")
                and request.state.vendor is not None,
                "has_theme": hasattr(request.state, "theme"),
            }

        response = client.get("/admin/test-context")

        assert response.status_code == 200
        data = response.json()
        assert data["context_type"] == "admin"
        # Admin context typically doesn't require vendor, but might have one
        # The key assertion is that context_type is correctly set to admin

    def test_admin_subdomain_sets_admin_context(self, client):
        """Test that admin.* subdomain sets ADMIN context type."""
        from fastapi import Request

        from main import app

        @app.get("/test-admin-subdomain")
        async def test_admin_subdomain(request: Request):
            return {
                "context_type": (
                    request.state.context_type.value
                    if hasattr(request.state, "context_type")
                    else None
                )
            }

        # Simulate request with admin subdomain
        with patch("app.core.config.settings") as mock_settings:
            mock_settings.platform_domain = "platform.com"
            response = client.get(
                "/test-admin-subdomain", headers={"host": "admin.platform.com"}
            )

        assert response.status_code == 200
        data = response.json()
        assert data["context_type"] == "admin"

    # ========================================================================
    # API Context Tests
    # ========================================================================

    def test_api_path_sets_api_context(self, client):
        """Test that /api/* paths set API context type."""
        from fastapi import Request

        from main import app

        @app.get("/api/test-context")
        async def test_api_context(request: Request):
            return {
                "context_type": (
                    request.state.context_type.value
                    if hasattr(request.state, "context_type")
                    else None
                )
            }

        response = client.get("/api/test-context")

        assert response.status_code == 200
        data = response.json()
        assert data["context_type"] == "api"

    # ========================================================================
    # Vendor Dashboard Context Tests
    # ========================================================================

    def test_vendor_dashboard_path_sets_vendor_context(
        self, client, vendor_with_subdomain
    ):
        """Test that /vendor/* paths with vendor set VENDOR_DASHBOARD context."""
        from fastapi import Request

        from main import app

        @app.get("/vendor/test-context")
        async def test_vendor_context(request: Request):
            return {
                "context_type": (
                    request.state.context_type.value
                    if hasattr(request.state, "context_type")
                    else None
                ),
                "vendor_id": (
                    request.state.vendor_id
                    if hasattr(request.state, "vendor_id")
                    else None
                ),
                "vendor_code": (
                    request.state.vendor.code
                    if hasattr(request.state, "vendor")
                    else None
                ),
            }

        # Request with vendor subdomain
        with patch("app.core.config.settings") as mock_settings:
            mock_settings.platform_domain = "platform.com"
            response = client.get(
                "/vendor/test-context",
                headers={"host": f"{vendor_with_subdomain.subdomain}.platform.com"},
            )

        assert response.status_code == 200
        data = response.json()
        assert data["context_type"] == "vendor_dashboard"
        assert data["vendor_id"] == vendor_with_subdomain.id
        assert data["vendor_code"] == vendor_with_subdomain.code

    # ========================================================================
    # Shop Context Tests
    # ========================================================================

    def test_shop_path_with_subdomain_sets_shop_context(
        self, client, vendor_with_subdomain
    ):
        """Test that /shop/* paths with vendor subdomain set SHOP context."""
        from fastapi import Request

        from main import app

        @app.get("/shop/test-context")
        async def test_shop_context(request: Request):
            return {
                "context_type": (
                    request.state.context_type.value
                    if hasattr(request.state, "context_type")
                    else None
                ),
                "vendor_id": (
                    request.state.vendor_id
                    if hasattr(request.state, "vendor_id")
                    else None
                ),
                "has_theme": hasattr(request.state, "theme"),
            }

        with patch("app.core.config.settings") as mock_settings:
            mock_settings.platform_domain = "platform.com"
            response = client.get(
                "/shop/test-context",
                headers={"host": f"{vendor_with_subdomain.subdomain}.platform.com"},
            )

        assert response.status_code == 200
        data = response.json()
        assert data["context_type"] == "shop"
        assert data["vendor_id"] == vendor_with_subdomain.id
        assert data["has_theme"] is True

    def test_shop_path_with_custom_domain_sets_shop_context(
        self, client, vendor_with_custom_domain
    ):
        """Test that /shop/* paths with custom domain set SHOP context."""
        from fastapi import Request

        from main import app

        @app.get("/shop/test-custom-domain")
        async def test_shop_custom_domain(request: Request):
            return {
                "context_type": (
                    request.state.context_type.value
                    if hasattr(request.state, "context_type")
                    else None
                ),
                "vendor_id": (
                    request.state.vendor_id
                    if hasattr(request.state, "vendor_id")
                    else None
                ),
            }

        with patch("app.core.config.settings") as mock_settings:
            mock_settings.platform_domain = "platform.com"
            response = client.get(
                "/shop/test-custom-domain", headers={"host": "customdomain.com"}
            )

        assert response.status_code == 200
        data = response.json()
        assert data["context_type"] == "shop"
        assert data["vendor_id"] == vendor_with_custom_domain.id

    # ========================================================================
    # Middleware Execution Order Tests
    # ========================================================================

    def test_vendor_context_runs_before_context_detection(
        self, client, vendor_with_subdomain
    ):
        """Test that VendorContextMiddleware runs before ContextDetectionMiddleware."""
        from fastapi import Request

        from main import app

        @app.get("/test-execution-order")
        async def test_execution_order(request: Request):
            # If vendor context runs first, clean_path should be available
            # before context detection uses it
            return {
                "has_vendor": hasattr(request.state, "vendor"),
                "has_clean_path": hasattr(request.state, "clean_path"),
                "has_context_type": hasattr(request.state, "context_type"),
            }

        with patch("app.core.config.settings") as mock_settings:
            mock_settings.platform_domain = "platform.com"
            response = client.get(
                "/test-execution-order",
                headers={"host": f"{vendor_with_subdomain.subdomain}.platform.com"},
            )

        assert response.status_code == 200
        data = response.json()
        # All middleware should have run and set their state
        assert data["has_vendor"] is True
        assert data["has_clean_path"] is True
        assert data["has_context_type"] is True

    def test_theme_context_runs_after_vendor_context(self, client, vendor_with_theme):
        """Test that ThemeContextMiddleware runs after VendorContextMiddleware."""
        from fastapi import Request

        from main import app

        @app.get("/test-theme-loading")
        async def test_theme_loading(request: Request):
            return {
                "has_vendor": hasattr(request.state, "vendor"),
                "has_theme": hasattr(request.state, "theme"),
                "theme_primary_color": (
                    request.state.theme.get("primary_color")
                    if hasattr(request.state, "theme")
                    else None
                ),
            }

        with patch("app.core.config.settings") as mock_settings:
            mock_settings.platform_domain = "platform.com"
            response = client.get(
                "/test-theme-loading",
                headers={"host": f"{vendor_with_theme.subdomain}.platform.com"},
            )

        assert response.status_code == 200
        data = response.json()
        assert data["has_vendor"] is True
        assert data["has_theme"] is True
        assert data["theme_primary_color"] == "#FF5733"

    # ========================================================================
    # Static File Handling Tests
    # ========================================================================

    def test_static_files_skip_vendor_detection(self, client):
        """Test that static file requests skip vendor detection."""
        # Static file requests should not trigger vendor detection
        response = client.get("/static/css/style.css")

        # We expect 404 (file doesn't exist) but middleware should have run
        # The important thing is it doesn't crash trying to detect vendor
        assert response.status_code in [404, 200]  # Depending on if file exists

    # ========================================================================
    # Error Handling Tests
    # ========================================================================

    def test_missing_vendor_graceful_handling(self, client):
        """Test that missing vendor is handled gracefully."""
        from fastapi import Request

        from main import app

        @app.get("/test-missing-vendor")
        async def test_missing_vendor(request: Request):
            return {
                "has_vendor": hasattr(request.state, "vendor"),
                "vendor": (
                    request.state.vendor if hasattr(request.state, "vendor") else None
                ),
                "context_type": (
                    request.state.context_type.value
                    if hasattr(request.state, "context_type")
                    else None
                ),
            }

        with patch("app.core.config.settings") as mock_settings:
            mock_settings.platform_domain = "platform.com"
            response = client.get(
                "/test-missing-vendor", headers={"host": "nonexistent.platform.com"}
            )

        assert response.status_code == 200
        data = response.json()
        # Should handle missing vendor gracefully
        assert data["has_vendor"] is False or data["vendor"] is None
        # Should still set a context type (fallback)
        assert data["context_type"] is not None

    def test_inactive_vendor_not_loaded(self, client, inactive_vendor):
        """Test that inactive vendors are not loaded."""
        from fastapi import Request

        from main import app

        @app.get("/test-inactive-vendor")
        async def test_inactive_vendor_endpoint(request: Request):
            return {
                "has_vendor": hasattr(request.state, "vendor"),
                "vendor": (
                    request.state.vendor if hasattr(request.state, "vendor") else None
                ),
            }

        with patch("app.core.config.settings") as mock_settings:
            mock_settings.platform_domain = "platform.com"
            response = client.get(
                "/test-inactive-vendor",
                headers={"host": f"{inactive_vendor.subdomain}.platform.com"},
            )

        assert response.status_code == 200
        data = response.json()
        # Inactive vendor should not be loaded
        assert data["has_vendor"] is False or data["vendor"] is None
