# tests/unit/middleware/test_frontend_type.py
"""
Unit tests for FrontendTypeMiddleware.

Tests cover:
- Middleware sets frontend_type in request state
- All frontend types are correctly detected
- get_frontend_type helper function
"""

from unittest.mock import AsyncMock, Mock

import pytest
from fastapi import Request

from app.modules.enums import FrontendType
from middleware.frontend_type import FrontendTypeMiddleware, get_frontend_type


@pytest.mark.unit
class TestFrontendTypeMiddleware:
    """Test suite for FrontendTypeMiddleware."""

    @pytest.mark.asyncio
    async def test_middleware_sets_admin_frontend_type(self):
        """Test middleware sets ADMIN frontend type."""
        middleware = FrontendTypeMiddleware(app=None)

        request = Mock(spec=Request)
        request.url = Mock(path="/admin/dashboard")
        request.headers = {"host": "localhost"}
        request.state = Mock(spec=[])
        request.state.platform_clean_path = "/admin/dashboard"
        request.state.store = None

        call_next = AsyncMock(return_value=Mock())

        await middleware.dispatch(request, call_next)

        assert hasattr(request.state, "frontend_type")
        assert request.state.frontend_type == FrontendType.ADMIN
        call_next.assert_called_once_with(request)

    @pytest.mark.asyncio
    async def test_middleware_sets_store_frontend_type(self):
        """Test middleware sets STORE frontend type."""
        middleware = FrontendTypeMiddleware(app=None)

        request = Mock(spec=Request)
        request.url = Mock(path="/store/settings")
        request.headers = {"host": "localhost"}
        request.state = Mock(spec=[])
        request.state.platform_clean_path = "/store/settings"
        request.state.store = None

        call_next = AsyncMock(return_value=Mock())

        await middleware.dispatch(request, call_next)

        assert request.state.frontend_type == FrontendType.STORE
        call_next.assert_called_once()

    @pytest.mark.asyncio
    async def test_middleware_sets_storefront_frontend_type(self):
        """Test middleware sets STOREFRONT frontend type."""
        middleware = FrontendTypeMiddleware(app=None)

        request = Mock(spec=Request)
        request.url = Mock(path="/storefront/products")
        request.headers = {"host": "localhost"}
        request.state = Mock(spec=[])
        request.state.platform_clean_path = "/storefront/products"
        request.state.store = None

        call_next = AsyncMock(return_value=Mock())

        await middleware.dispatch(request, call_next)

        assert request.state.frontend_type == FrontendType.STOREFRONT
        call_next.assert_called_once()

    @pytest.mark.asyncio
    async def test_middleware_sets_storefront_with_store_context(self):
        """Test middleware sets STOREFRONT when store exists in state."""
        middleware = FrontendTypeMiddleware(app=None)

        request = Mock(spec=Request)
        request.url = Mock(path="/products")
        request.headers = {"host": "orion.omsflow.lu"}
        mock_store = Mock()
        mock_store.name = "Test Store"
        request.state = Mock(spec=[])
        request.state.platform_clean_path = "/products"
        request.state.store = mock_store

        call_next = AsyncMock(return_value=Mock())

        await middleware.dispatch(request, call_next)

        assert request.state.frontend_type == FrontendType.STOREFRONT
        call_next.assert_called_once()

    @pytest.mark.asyncio
    async def test_middleware_sets_platform_frontend_type(self):
        """Test middleware sets PLATFORM frontend type."""
        middleware = FrontendTypeMiddleware(app=None)

        request = Mock(spec=Request)
        request.url = Mock(path="/pricing")
        request.headers = {"host": "localhost"}
        request.state = Mock(spec=[])
        request.state.platform_clean_path = "/pricing"
        request.state.store = None

        call_next = AsyncMock(return_value=Mock())

        await middleware.dispatch(request, call_next)

        assert request.state.frontend_type == FrontendType.PLATFORM
        call_next.assert_called_once()

    @pytest.mark.asyncio
    async def test_middleware_returns_response(self):
        """Test middleware returns response from call_next."""
        middleware = FrontendTypeMiddleware(app=None)

        request = Mock(spec=Request)
        request.url = Mock(path="/admin/test")
        request.headers = {"host": "localhost"}
        request.state = Mock(clean_path="/admin/test")

        expected_response = Mock()
        call_next = AsyncMock(return_value=expected_response)

        response = await middleware.dispatch(request, call_next)

        assert response is expected_response

    @pytest.mark.asyncio
    async def test_middleware_uses_platform_clean_path_when_available(self):
        """Test middleware uses platform_clean_path when available."""
        middleware = FrontendTypeMiddleware(app=None)

        request = Mock(spec=Request)
        request.url = Mock(path="/platforms/main/store/settings")
        request.headers = {"host": "localhost"}
        # platform_clean_path shows the path with platform prefix stripped
        request.state = Mock(spec=[])
        request.state.platform_clean_path = "/store/settings"
        request.state.store = None

        call_next = AsyncMock(return_value=Mock())

        await middleware.dispatch(request, call_next)

        # Should detect as STORE based on platform_clean_path
        assert request.state.frontend_type == FrontendType.STORE

    @pytest.mark.asyncio
    async def test_middleware_falls_back_to_url_path(self):
        """Test middleware falls back to url.path when clean_path not set."""
        middleware = FrontendTypeMiddleware(app=None)

        request = Mock(spec=Request)
        request.url = Mock(path="/admin/dashboard")
        request.headers = {"host": "localhost"}
        # No clean_path attribute
        request.state = Mock(spec=[])

        call_next = AsyncMock(return_value=Mock())

        await middleware.dispatch(request, call_next)

        assert request.state.frontend_type == FrontendType.ADMIN


@pytest.mark.unit
class TestGetFrontendTypeHelper:
    """Test suite for get_frontend_type helper function."""

    def test_get_frontend_type_exists(self):
        """Test getting frontend type when it exists."""
        request = Mock(spec=Request)
        request.state.frontend_type = FrontendType.ADMIN

        result = get_frontend_type(request)

        assert result == FrontendType.ADMIN

    def test_get_frontend_type_default(self):
        """Test getting frontend type returns None when not set (fail-aware)."""
        request = Mock(spec=Request)
        request.state = Mock(spec=[])  # No frontend_type attribute

        result = get_frontend_type(request)

        assert result is None

    def test_get_frontend_type_for_all_types(self):
        """Test getting all frontend types."""
        for expected_type in FrontendType:
            request = Mock(spec=Request)
            request.state.frontend_type = expected_type

            result = get_frontend_type(request)

            assert result == expected_type
