# tests/integration/middleware/test_theme_loading_flow.py
"""
Integration tests for theme loading end-to-end flow.

These tests verify that vendor themes are correctly loaded and injected
into request.state through real HTTP requests.
"""

from unittest.mock import patch

import pytest


@pytest.mark.integration
@pytest.mark.middleware
@pytest.mark.theme
class TestThemeLoadingFlow:
    """Test theme loading through real HTTP requests."""

    # ========================================================================
    # Basic Theme Loading Tests
    # ========================================================================

    def test_theme_loaded_for_vendor_with_custom_theme(self, client, vendor_with_theme):
        """Test that custom theme is loaded for vendor with theme."""
        from fastapi import Request

        from main import app

        @app.get("/test-theme-loading")
        async def test_theme(request: Request):
            theme = request.state.theme if hasattr(request.state, "theme") else None
            return {
                "has_theme": theme is not None,
                "theme_data": theme if 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_theme"] is True
        assert data["theme_data"] is not None
        assert data["theme_data"]["primary_color"] == "#FF5733"
        assert data["theme_data"]["secondary_color"] == "#33FF57"

    def test_default_theme_loaded_for_vendor_without_theme(
        self, client, vendor_with_subdomain
    ):
        """Test that default theme is loaded for vendor without custom theme."""
        from fastapi import Request

        from main import app

        @app.get("/test-default-theme")
        async def test_default_theme(request: Request):
            theme = request.state.theme if hasattr(request.state, "theme") else None
            return {
                "has_theme": theme is not None,
                "theme_data": theme if theme else None,
            }

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

        assert response.status_code == 200
        data = response.json()
        assert data["has_theme"] is True
        # Default theme should have basic structure
        assert "primary_color" in data["theme_data"]
        assert "secondary_color" in data["theme_data"]

    def test_no_theme_loaded_without_vendor(self, client):
        """Test that no theme is loaded when there's no vendor."""
        from fastapi import Request

        from main import app

        @app.get("/test-no-theme")
        async def test_no_theme(request: Request):
            return {
                "has_theme": hasattr(request.state, "theme"),
                "has_vendor": hasattr(request.state, "vendor")
                and request.state.vendor is not None,
            }

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

        assert response.status_code == 200
        data = response.json()
        assert data["has_vendor"] is False
        # No vendor means no theme should be loaded
        assert data["has_theme"] is False

    # ========================================================================
    # Theme Structure Tests
    # ========================================================================

    def test_custom_theme_contains_all_fields(self, client, vendor_with_theme):
        """Test that custom theme contains all expected fields."""
        from fastapi import Request

        from main import app

        @app.get("/test-theme-fields")
        async def test_theme_fields(request: Request):
            theme = request.state.theme if hasattr(request.state, "theme") else {}
            return {
                "primary_color": theme.get("primary_color"),
                "secondary_color": theme.get("secondary_color"),
                "logo_url": theme.get("logo_url"),
                "favicon_url": theme.get("favicon_url"),
                "custom_css": theme.get("custom_css"),
            }

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

        assert response.status_code == 200
        data = response.json()
        assert data["primary_color"] == "#FF5733"
        assert data["secondary_color"] == "#33FF57"
        assert data["logo_url"] == "/static/vendors/themedvendor/logo.png"
        assert data["favicon_url"] == "/static/vendors/themedvendor/favicon.ico"
        assert "background" in data["custom_css"]

    def test_default_theme_structure(self, client, vendor_with_subdomain):
        """Test that default theme has expected structure."""
        from fastapi import Request

        from main import app

        @app.get("/test-default-theme-structure")
        async def test_default_structure(request: Request):
            theme = request.state.theme if hasattr(request.state, "theme") else {}
            return {
                "has_primary_color": "primary_color" in theme,
                "has_secondary_color": "secondary_color" in theme,
                "has_logo_url": "logo_url" in theme,
                "has_favicon_url": "favicon_url" in theme,
                "has_custom_css": "custom_css" in theme,
            }

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

        assert response.status_code == 200
        data = response.json()
        # Default theme should have basic structure
        assert data["has_primary_color"] is True
        assert data["has_secondary_color"] is True

    # ========================================================================
    # Theme Loading for Different Contexts Tests
    # ========================================================================

    def test_theme_loaded_in_shop_context(self, client, vendor_with_theme):
        """Test that theme is loaded in SHOP context."""
        from fastapi import Request

        from main import app

        @app.get("/shop/test-shop-theme")
        async def test_shop_theme(request: Request):
            return {
                "context_type": (
                    request.state.context_type.value
                    if hasattr(request.state, "context_type")
                    else None
                ),
                "has_theme": hasattr(request.state, "theme"),
                "theme_primary": (
                    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(
                "/shop/test-shop-theme",
                headers={"host": f"{vendor_with_theme.subdomain}.platform.com"},
            )

        assert response.status_code == 200
        data = response.json()
        assert data["context_type"] == "shop"
        assert data["has_theme"] is True
        assert data["theme_primary"] == "#FF5733"

    def test_theme_loaded_in_vendor_dashboard_context(self, client, vendor_with_theme):
        """Test that theme is loaded in VENDOR_DASHBOARD context."""
        from fastapi import Request

        from main import app

        @app.get("/vendor/test-dashboard-theme")
        async def test_dashboard_theme(request: Request):
            return {
                "context_type": (
                    request.state.context_type.value
                    if hasattr(request.state, "context_type")
                    else None
                ),
                "has_theme": hasattr(request.state, "theme"),
                "theme_secondary": (
                    request.state.theme.get("secondary_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(
                "/vendor/test-dashboard-theme",
                headers={"host": f"{vendor_with_theme.subdomain}.platform.com"},
            )

        assert response.status_code == 200
        data = response.json()
        assert data["context_type"] == "vendor_dashboard"
        assert data["has_theme"] is True
        assert data["theme_secondary"] == "#33FF57"

    def test_theme_loaded_in_api_context_with_vendor(self, client, vendor_with_theme):
        """Test that theme is loaded in API context when vendor is present."""
        from fastapi import Request

        from main import app

        @app.get("/api/test-api-theme")
        async def test_api_theme(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"),
            }

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

        assert response.status_code == 200
        data = response.json()
        assert data["context_type"] == "api"
        assert data["has_vendor"] is True
        # Theme should be loaded even for API context if vendor present
        assert data["has_theme"] is True

    def test_no_theme_in_admin_context(self, client):
        """Test that theme is not loaded in ADMIN context (no vendor)."""
        from fastapi import Request

        from main import app

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

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

        assert response.status_code == 200
        data = response.json()
        assert data["context_type"] == "admin"
        # Admin context has no vendor, so no theme
        assert data["has_theme"] is False

    # ========================================================================
    # Theme Loading with Different Routing Modes Tests
    # ========================================================================

    def test_theme_loaded_with_subdomain_routing(self, client, vendor_with_theme):
        """Test theme loading with subdomain routing."""
        from fastapi import Request

        from main import app

        @app.get("/test-subdomain-theme")
        async def test_subdomain_theme(request: Request):
            return {
                "vendor_code": (
                    request.state.vendor.code
                    if hasattr(request.state, "vendor") and request.state.vendor
                    else None
                ),
                "theme_logo": (
                    request.state.theme.get("logo_url")
                    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-subdomain-theme",
                headers={"host": f"{vendor_with_theme.subdomain}.platform.com"},
            )

        assert response.status_code == 200
        data = response.json()
        assert data["vendor_code"] == vendor_with_theme.code
        assert data["theme_logo"] == "/static/vendors/themedvendor/logo.png"

    def test_theme_loaded_with_custom_domain_routing(
        self, client, vendor_with_custom_domain, db
    ):
        """Test theme loading with custom domain routing."""
        # Add theme to custom domain vendor
        from models.database.vendor_theme import VendorTheme

        theme = VendorTheme(
            vendor_id=vendor_with_custom_domain.id,
            primary_color="#123456",
            secondary_color="#654321",
        )
        db.add(theme)
        db.commit()

        from fastapi import Request

        from main import app

        @app.get("/test-custom-domain-theme")
        async def test_custom_domain_theme(request: Request):
            return {
                "has_theme": hasattr(request.state, "theme"),
                "theme_primary": (
                    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-custom-domain-theme", headers={"host": "customdomain.com"}
            )

        assert response.status_code == 200
        data = response.json()
        assert data["has_theme"] is True
        assert data["theme_primary"] == "#123456"

    # ========================================================================
    # Theme Dependency on Vendor Context Tests
    # ========================================================================

    def test_theme_middleware_depends_on_vendor_middleware(
        self, client, vendor_with_theme
    ):
        """Test that theme loading depends on vendor being detected first."""
        from fastapi import Request

        from main import app

        @app.get("/test-theme-vendor-dependency")
        async def test_dependency(request: Request):
            return {
                "has_vendor": hasattr(request.state, "vendor")
                and request.state.vendor is not None,
                "vendor_id": (
                    request.state.vendor_id
                    if hasattr(request.state, "vendor_id")
                    else None
                ),
                "has_theme": hasattr(request.state, "theme"),
                "vendor_matches_theme": (
                    request.state.vendor_id == vendor_with_theme.id
                    if hasattr(request.state, "vendor_id")
                    else False
                ),
            }

        with patch("app.core.config.settings") as mock_settings:
            mock_settings.platform_domain = "platform.com"
            response = client.get(
                "/test-theme-vendor-dependency",
                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["vendor_id"] == vendor_with_theme.id
        assert data["has_theme"] is True
        assert data["vendor_matches_theme"] is True

    # ========================================================================
    # Theme Caching and Performance Tests
    # ========================================================================

    def test_theme_loaded_consistently_across_requests(self, client, vendor_with_theme):
        """Test that theme is loaded consistently across multiple requests."""
        from fastapi import Request

        from main import app

        @app.get("/test-theme-consistency")
        async def test_consistency(request: Request):
            return {
                "theme_primary": (
                    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"

            # Make multiple requests
            responses = []
            for _ in range(3):
                response = client.get(
                    "/test-theme-consistency",
                    headers={"host": f"{vendor_with_theme.subdomain}.platform.com"},
                )
                responses.append(response.json())

        # All responses should have same theme
        assert all(r["theme_primary"] == "#FF5733" for r in responses)

    # ========================================================================
    # Edge Cases and Error Handling Tests
    # ========================================================================

    def test_theme_gracefully_handles_missing_theme_fields(
        self, client, vendor_with_subdomain
    ):
        """Test that missing theme fields are handled gracefully."""
        from fastapi import Request

        from main import app

        @app.get("/test-partial-theme")
        async def test_partial_theme(request: Request):
            theme = request.state.theme if hasattr(request.state, "theme") else {}
            return {
                "has_theme": bool(theme),
                "primary_color": theme.get("primary_color", "default"),
                "logo_url": theme.get("logo_url", "default"),
            }

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

        assert response.status_code == 200
        data = response.json()
        assert data["has_theme"] is True
        # Should have defaults for missing fields
        assert data["primary_color"] is not None
        assert data["logo_url"] is not None

    def test_theme_dict_is_mutable(self, client, vendor_with_theme):
        """Test that theme dict can be accessed and read from."""
        from fastapi import Request

        from main import app

        @app.get("/test-theme-mutable")
        async def test_mutable(request: Request):
            theme = request.state.theme if hasattr(request.state, "theme") else {}
            # Try to access theme values
            primary = theme.get("primary_color")
            return {"can_read": primary is not None, "value": primary}

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

        assert response.status_code == 200
        data = response.json()
        assert data["can_read"] is True
        assert data["value"] == "#FF5733"
