# tests/integration/middleware/test_vendor_context_flow.py
"""
Integration tests for vendor context detection end-to-end flow.

These tests verify that vendor detection works correctly through real HTTP requests
for all routing modes: subdomain, custom domain, and path-based.
"""

from unittest.mock import patch

import pytest


@pytest.mark.integration
@pytest.mark.middleware
@pytest.mark.vendor
class TestVendorContextFlow:
    """Test vendor context detection through real HTTP requests."""

    # ========================================================================
    # Subdomain Detection Tests
    # ========================================================================

    def test_subdomain_vendor_detection(self, client, vendor_with_subdomain):
        """Test vendor detection via subdomain routing."""
        from fastapi import Request

        from main import app

        @app.get("/test-subdomain-detection")
        async def test_subdomain(request: Request):
            return {
                "vendor_detected": 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
                ),
                "vendor_code": (
                    request.state.vendor.code
                    if hasattr(request.state, "vendor") and request.state.vendor
                    else None
                ),
                "vendor_name": (
                    request.state.vendor.name
                    if hasattr(request.state, "vendor") and request.state.vendor
                    else None
                ),
                "detection_method": "subdomain",
            }

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

        assert response.status_code == 200
        data = response.json()
        assert data["vendor_detected"] is True
        assert data["vendor_id"] == vendor_with_subdomain.id
        assert data["vendor_code"] == vendor_with_subdomain.code
        assert data["vendor_name"] == vendor_with_subdomain.name

    def test_subdomain_with_port_detection(self, client, vendor_with_subdomain):
        """Test vendor detection via subdomain with port number."""
        from fastapi import Request

        from main import app

        @app.get("/test-subdomain-port")
        async def test_subdomain_port(request: Request):
            return {
                "vendor_detected": hasattr(request.state, "vendor")
                and request.state.vendor is not None,
                "vendor_code": (
                    request.state.vendor.code
                    if hasattr(request.state, "vendor") and request.state.vendor
                    else None
                ),
            }

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

        assert response.status_code == 200
        data = response.json()
        assert data["vendor_detected"] is True
        assert data["vendor_code"] == vendor_with_subdomain.code

    def test_nonexistent_subdomain_returns_no_vendor(self, client):
        """Test that nonexistent subdomain doesn't crash and returns no vendor."""
        from fastapi import Request

        from main import app

        @app.get("/test-nonexistent-subdomain")
        async def test_nonexistent(request: Request):
            return {
                "vendor_detected": hasattr(request.state, "vendor")
                and request.state.vendor is not None,
                "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-nonexistent-subdomain",
                headers={"host": "nonexistent.platform.com"},
            )

        assert response.status_code == 200
        data = response.json()
        assert data["vendor_detected"] is False

    # ========================================================================
    # Custom Domain Detection Tests
    # ========================================================================

    def test_custom_domain_vendor_detection(self, client, vendor_with_custom_domain):
        """Test vendor detection via custom domain."""
        from fastapi import Request

        from main import app

        @app.get("/test-custom-domain")
        async def test_custom_domain(request: Request):
            return {
                "vendor_detected": 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
                ),
                "vendor_code": (
                    request.state.vendor.code
                    if hasattr(request.state, "vendor") and request.state.vendor
                    else None
                ),
                "detection_method": "custom_domain",
            }

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

        assert response.status_code == 200
        data = response.json()
        assert data["vendor_detected"] is True
        assert data["vendor_id"] == vendor_with_custom_domain.id
        assert data["vendor_code"] == vendor_with_custom_domain.code

    def test_custom_domain_with_www_detection(self, client, vendor_with_custom_domain):
        """Test vendor detection via custom domain with www prefix."""
        from fastapi import Request

        from main import app

        @app.get("/test-custom-domain-www")
        async def test_custom_domain_www(request: Request):
            return {
                "vendor_detected": hasattr(request.state, "vendor")
                and request.state.vendor is not None,
                "vendor_code": (
                    request.state.vendor.code
                    if hasattr(request.state, "vendor") and request.state.vendor
                    else None
                ),
            }

        with patch("app.core.config.settings") as mock_settings:
            mock_settings.platform_domain = "platform.com"
            # Test with www prefix - should still detect vendor
            response = client.get(
                "/test-custom-domain-www", headers={"host": "www.customdomain.com"}
            )

        # This might fail if your implementation doesn't strip www
        # Adjust assertion based on your actual behavior
        assert response.status_code == 200

    # ========================================================================
    # Path-Based Detection Tests (Development Mode)
    # ========================================================================

    def test_path_based_vendor_detection_vendors_prefix(
        self, client, vendor_with_subdomain
    ):
        """Test vendor detection via path-based routing with /vendors/ prefix."""
        from fastapi import Request

        from main import app

        @app.get("/vendors/{vendor_code}/test-path")
        async def test_path_based(vendor_code: str, request: Request):
            return {
                "vendor_detected": hasattr(request.state, "vendor")
                and request.state.vendor is not None,
                "vendor_code_param": vendor_code,
                "vendor_code_state": (
                    request.state.vendor.code
                    if hasattr(request.state, "vendor") and request.state.vendor
                    else None
                ),
                "clean_path": (
                    request.state.clean_path
                    if hasattr(request.state, "clean_path")
                    else None
                ),
            }

        with patch("app.core.config.settings") as mock_settings:
            mock_settings.platform_domain = "platform.com"
            response = client.get(
                f"/vendors/{vendor_with_subdomain.code}/test-path",
                headers={"host": "localhost:8000"},
            )

        assert response.status_code == 200
        data = response.json()
        assert data["vendor_detected"] is True
        assert data["vendor_code_param"] == vendor_with_subdomain.code
        assert data["vendor_code_state"] == vendor_with_subdomain.code

    def test_path_based_vendor_detection_vendor_prefix(
        self, client, vendor_with_subdomain
    ):
        """Test vendor detection via path-based routing with /vendor/ prefix."""
        from fastapi import Request

        from main import app

        @app.get("/vendor/{vendor_code}/test")
        async def test_vendor_path(vendor_code: str, request: Request):
            return {
                "vendor_detected": hasattr(request.state, "vendor")
                and request.state.vendor is not None,
                "vendor_code": (
                    request.state.vendor.code
                    if hasattr(request.state, "vendor") and request.state.vendor
                    else None
                ),
            }

        with patch("app.core.config.settings") as mock_settings:
            mock_settings.platform_domain = "platform.com"
            response = client.get(
                f"/vendor/{vendor_with_subdomain.code}/test",
                headers={"host": "localhost:8000"},
            )

        assert response.status_code == 200
        data = response.json()
        assert data["vendor_detected"] is True
        assert data["vendor_code"] == vendor_with_subdomain.code

    # ========================================================================
    # Clean Path Extraction Tests
    # ========================================================================

    def test_clean_path_extracted_from_vendor_prefix(
        self, client, vendor_with_subdomain
    ):
        """Test that clean_path is correctly extracted from path-based routing."""
        from fastapi import Request

        from main import app

        @app.get("/vendors/{vendor_code}/shop/products")
        async def test_clean_path(vendor_code: str, request: Request):
            return {
                "clean_path": (
                    request.state.clean_path
                    if hasattr(request.state, "clean_path")
                    else None
                ),
                "original_path": request.url.path,
            }

        with patch("app.core.config.settings") as mock_settings:
            mock_settings.platform_domain = "platform.com"
            response = client.get(
                f"/vendors/{vendor_with_subdomain.code}/shop/products",
                headers={"host": "localhost:8000"},
            )

        assert response.status_code == 200
        data = response.json()
        # Clean path should have vendor prefix removed
        assert data["clean_path"] == "/shop/products"
        assert (
            f"/vendors/{vendor_with_subdomain.code}/shop/products"
            in data["original_path"]
        )

    def test_clean_path_unchanged_for_subdomain(self, client, vendor_with_subdomain):
        """Test that clean_path equals original path for subdomain routing."""
        from fastapi import Request

        from main import app

        @app.get("/shop/test-clean-path")
        async def test_subdomain_clean_path(request: Request):
            return {
                "clean_path": (
                    request.state.clean_path
                    if hasattr(request.state, "clean_path")
                    else None
                ),
                "original_path": request.url.path,
            }

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

        assert response.status_code == 200
        data = response.json()
        # For subdomain routing, clean path should equal original path
        assert data["clean_path"] == data["original_path"]
        assert data["clean_path"] == "/shop/test-clean-path"

    # ========================================================================
    # Vendor State Injection Tests
    # ========================================================================

    def test_vendor_id_injected_into_request_state(self, client, vendor_with_subdomain):
        """Test that vendor_id is correctly injected into request.state."""
        from fastapi import Request

        from main import app

        @app.get("/test-vendor-id-injection")
        async def test_vendor_id(request: Request):
            return {
                "has_vendor_id": hasattr(request.state, "vendor_id"),
                "vendor_id": (
                    request.state.vendor_id
                    if hasattr(request.state, "vendor_id")
                    else None
                ),
                "vendor_id_type": (
                    type(request.state.vendor_id).__name__
                    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(
                "/test-vendor-id-injection",
                headers={"host": f"{vendor_with_subdomain.subdomain}.platform.com"},
            )

        assert response.status_code == 200
        data = response.json()
        assert data["has_vendor_id"] is True
        assert data["vendor_id"] == vendor_with_subdomain.id
        assert data["vendor_id_type"] == "int"

    def test_vendor_object_injected_into_request_state(
        self, client, vendor_with_subdomain
    ):
        """Test that full vendor object is injected into request.state."""
        from fastapi import Request

        from main import app

        @app.get("/test-vendor-object-injection")
        async def test_vendor_object(request: Request):
            vendor = (
                request.state.vendor
                if hasattr(request.state, "vendor") and request.state.vendor
                else None
            )
            return {
                "has_vendor": vendor is not None,
                "vendor_attributes": (
                    {
                        "id": vendor.id if vendor else None,
                        "name": vendor.name if vendor else None,
                        "code": vendor.code if vendor else None,
                        "subdomain": vendor.subdomain if vendor else None,
                        "is_active": vendor.is_active if vendor else None,
                    }
                    if vendor
                    else None
                ),
            }

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

        assert response.status_code == 200
        data = response.json()
        assert data["has_vendor"] is True
        assert data["vendor_attributes"]["id"] == vendor_with_subdomain.id
        assert data["vendor_attributes"]["name"] == vendor_with_subdomain.name
        assert data["vendor_attributes"]["code"] == vendor_with_subdomain.code
        assert data["vendor_attributes"]["is_active"] is True

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

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

        from main import app

        @app.get("/test-inactive-vendor-detection")
        async def test_inactive(request: Request):
            return {
                "vendor_detected": 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-inactive-vendor-detection",
                headers={"host": f"{inactive_vendor.subdomain}.platform.com"},
            )

        assert response.status_code == 200
        data = response.json()
        assert data["vendor_detected"] is False

    def test_platform_domain_without_subdomain_no_vendor(self, client):
        """Test that platform domain without subdomain doesn't detect vendor."""
        from fastapi import Request

        from main import app

        @app.get("/test-platform-domain")
        async def test_platform(request: Request):
            return {
                "vendor_detected": 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-platform-domain", headers={"host": "platform.com"}
            )

        assert response.status_code == 200
        data = response.json()
        assert data["vendor_detected"] is False
