"""
Unit Tests for Check Identity Endpoint (US-013)

Tests the dual login support: email + username verification
"""

import pytest
from unittest.mock import MagicMock, patch, AsyncMock


# ============================================================================
# TEST CHECK IDENTITY REQUEST MODEL
# ============================================================================

class TestCheckIdentityRequestModel:
    """Tests for CheckIdentityRequest model validation."""

    def test_valid_email_normalized_to_lowercase(self):
        """Email inputs should be normalized to lowercase."""
        from shared.auth.models import CheckIdentityRequest

        request = CheckIdentityRequest(identity="User@Example.COM")
        assert request.identity == "user@example.com"

    def test_valid_username_normalized_to_uppercase(self):
        """Username inputs (without @) should be normalized to uppercase."""
        from shared.auth.models import CheckIdentityRequest

        request = CheckIdentityRequest(identity="marius")
        assert request.identity == "MARIUS"

    def test_username_with_spaces_normalized(self):
        """Username with spaces should be preserved but uppercased."""
        from shared.auth.models import CheckIdentityRequest

        request = CheckIdentityRequest(identity="marius m")
        assert request.identity == "MARIUS M"

    def test_whitespace_trimmed(self):
        """Leading/trailing whitespace should be trimmed."""
        from shared.auth.models import CheckIdentityRequest

        request = CheckIdentityRequest(identity="  user@test.com  ")
        assert request.identity == "user@test.com"

    def test_empty_identity_raises_error(self):
        """Empty identity should raise validation error."""
        from pydantic import ValidationError
        from shared.auth.models import CheckIdentityRequest

        with pytest.raises(ValidationError):
            CheckIdentityRequest(identity="")

    def test_too_short_identity_raises_error(self):
        """Identity shorter than 2 chars should raise validation error."""
        from pydantic import ValidationError
        from shared.auth.models import CheckIdentityRequest

        with pytest.raises(ValidationError):
            CheckIdentityRequest(identity="a")


# ============================================================================
# TEST CHECK IDENTITY RESPONSE MODEL
# ============================================================================

class TestCheckIdentityResponseModel:
    """Tests for CheckIdentityResponse model."""

    def test_response_with_email_type(self):
        """Response should include identity_type field."""
        from shared.auth.models import CheckIdentityResponse, ServerInfo

        response = CheckIdentityResponse(
            exists=True,
            servers=[ServerInfo(id="server1", name="Server 1")],
            identity_type="email"
        )
        assert response.exists is True
        assert response.identity_type == "email"
        assert len(response.servers) == 1

    def test_response_with_username_type(self):
        """Response should support username identity type."""
        from shared.auth.models import CheckIdentityResponse

        response = CheckIdentityResponse(
            exists=True,
            servers=[],
            identity_type="username"
        )
        assert response.identity_type == "username"

    def test_response_default_identity_type(self):
        """Default identity_type should be 'unknown'."""
        from shared.auth.models import CheckIdentityResponse

        response = CheckIdentityResponse(exists=False, servers=[])
        assert response.identity_type == "unknown"


# ============================================================================
# TEST IDENTITY TYPE DETECTION
# ============================================================================

class TestIdentityTypeDetection:
    """Tests for email vs username detection logic."""

    def test_email_detected_by_at_sign(self):
        """Identity with @ should be treated as email."""
        # This is tested via the model validator
        from shared.auth.models import CheckIdentityRequest

        request = CheckIdentityRequest(identity="test@example.com")
        # Email should be lowercase
        assert request.identity == "test@example.com"
        assert "@" in request.identity

    def test_username_detected_without_at_sign(self):
        """Identity without @ should be treated as username."""
        from shared.auth.models import CheckIdentityRequest

        request = CheckIdentityRequest(identity="MARIUS")
        # Username should be uppercase
        assert request.identity == "MARIUS"
        assert "@" not in request.identity


# ============================================================================
# TEST EMAIL SERVER CACHE USERNAME LOOKUP
# ============================================================================

class TestEmailServerCacheUsernameLookup:
    """Tests for username lookup in EmailServerCache."""

    @pytest.fixture
    def reset_cache(self):
        """Reset the cache singleton before each test."""
        from shared.auth.email_server_cache import EmailServerCache

        # Reset singleton
        EmailServerCache._instance = None
        yield
        EmailServerCache._instance = None

    def test_get_servers_for_username_method_exists(self, reset_cache):
        """EmailServerCache should have get_servers_for_username method."""
        from shared.auth.email_server_cache import EmailServerCache

        cache = EmailServerCache()
        assert hasattr(cache, 'get_servers_for_username')
        assert callable(cache.get_servers_for_username)

    def test_empty_username_returns_empty_list(self, reset_cache):
        """Empty username should return empty list."""
        import asyncio
        from shared.auth.email_server_cache import EmailServerCache

        cache = EmailServerCache()

        async def test():
            # Mock settings to return empty servers
            with patch('backend.config.settings') as mock_settings:
                mock_settings.get_oracle_servers.return_value = []
                result = await cache.get_servers_for_username("")
                return result

        result = asyncio.get_event_loop().run_until_complete(test())
        assert result == []


# ============================================================================
# TEST BACKWARD COMPATIBILITY
# ============================================================================

class TestBackwardCompatibility:
    """Tests for backward compatibility with check-email endpoint."""

    def test_check_email_request_still_works(self):
        """CheckEmailRequest should still work for backward compatibility."""
        from shared.auth.models import CheckEmailRequest

        request = CheckEmailRequest(email="user@example.com")
        assert request.email == "user@example.com"

    def test_check_email_response_still_works(self):
        """CheckEmailResponse should still work for backward compatibility."""
        from shared.auth.models import CheckEmailResponse, ServerInfo

        response = CheckEmailResponse(
            exists=True,
            servers=[ServerInfo(id="s1", name="Server 1")]
        )
        assert response.exists is True
        assert len(response.servers) == 1


# ============================================================================
# TEST ACCEPTANCE CRITERIA (US-013)
# ============================================================================

class TestAcceptanceCriteria:
    """Tests verifying US-013 acceptance criteria."""

    def test_ac1_check_identity_request_model_exists(self):
        """AC1: CheckIdentityRequest model exists."""
        from shared.auth.models import CheckIdentityRequest

        assert CheckIdentityRequest is not None

    def test_ac2_email_detection_with_at_sign(self):
        """AC2: Input with @ is treated as email."""
        from shared.auth.models import CheckIdentityRequest

        request = CheckIdentityRequest(identity="test@domain.com")
        # Email normalized to lowercase
        assert "@" in request.identity
        assert request.identity.islower()

    def test_ac3_username_detection_without_at_sign(self):
        """AC3: Input without @ is treated as username."""
        from shared.auth.models import CheckIdentityRequest

        request = CheckIdentityRequest(identity="admin")
        # Username normalized to uppercase
        assert "@" not in request.identity
        assert request.identity == "ADMIN"

    def test_ac4_check_email_backward_compatible(self):
        """AC4: Old check-email models still work."""
        from shared.auth.models import CheckEmailRequest, CheckEmailResponse

        # Both models should be importable and usable
        req = CheckEmailRequest(email="test@test.com")
        resp = CheckEmailResponse(exists=False, servers=[])

        assert req.email == "test@test.com"
        assert resp.exists is False

    def test_ac5_response_includes_identity_type(self):
        """AC5: Response includes identity_type field."""
        from shared.auth.models import CheckIdentityResponse

        response = CheckIdentityResponse(
            exists=True,
            servers=[],
            identity_type="email"
        )
        assert hasattr(response, 'identity_type')
        assert response.identity_type in ["email", "username", "unknown"]


# ============================================================================
# TEST UI REQUIREMENTS
# ============================================================================

class TestUIRequirements:
    """Tests verifying UI-related requirements."""

    def test_placeholder_label_correct(self):
        """UI should use 'Email sau utilizator' as label."""
        # This is a documentation test - the actual UI change is in Vue
        # We verify the backend accepts both formats

        from shared.auth.models import CheckIdentityRequest

        # Should accept email format
        email_req = CheckIdentityRequest(identity="user@example.com")
        assert email_req.identity == "user@example.com"

        # Should accept username format
        username_req = CheckIdentityRequest(identity="UTILIZATOR")
        assert username_req.identity == "UTILIZATOR"

    def test_username_with_romanian_chars_handled(self):
        """Username with spaces (like 'MARIUS M') should be handled."""
        from shared.auth.models import CheckIdentityRequest

        request = CheckIdentityRequest(identity="marius m")
        assert request.identity == "MARIUS M"
