"""Unit tests for provider_factory.py - Factory instantiation, dependency injection, provider registration."""

from unittest.mock import MagicMock, patch

import pytest

from src.core.providers.base_provider import Loader
from src.core.providers.provider_factory import Loaders


class TestLoadersInit:
    """Test Loaders factory initialization."""

    @patch("src.core.providers.provider_factory.AniworldLoader")
    def test_factory_initializes_with_default_providers(self, mock_aniworld):
        """Factory should register aniworld.to provider by default."""
        mock_aniworld.return_value = MagicMock(spec=Loader)
        factory = Loaders()
        assert "aniworld.to" in factory.dict

    @patch("src.core.providers.provider_factory.AniworldLoader")
    def test_factory_dict_contains_loader_instances(self, mock_aniworld):
        """Factory dict values should be Loader instances."""
        mock_instance = MagicMock(spec=Loader)
        mock_aniworld.return_value = mock_instance
        factory = Loaders()
        for key, value in factory.dict.items():
            assert isinstance(key, str)


class TestLoadersGetLoader:
    """Test GetLoader method."""

    @patch("src.core.providers.provider_factory.AniworldLoader")
    def test_get_loader_returns_registered_provider(self, mock_aniworld):
        """GetLoader should return provider for known key."""
        mock_instance = MagicMock(spec=Loader)
        mock_aniworld.return_value = mock_instance
        factory = Loaders()
        loader = factory.GetLoader("aniworld.to")
        assert loader is mock_instance

    @patch("src.core.providers.provider_factory.AniworldLoader")
    def test_get_loader_raises_key_error_for_unknown(self, mock_aniworld):
        """GetLoader should raise KeyError for unknown provider key."""
        mock_aniworld.return_value = MagicMock(spec=Loader)
        factory = Loaders()
        with pytest.raises(KeyError):
            factory.GetLoader("nonexistent.provider")

    @patch("src.core.providers.provider_factory.AniworldLoader")
    def test_get_loader_returns_same_instance(self, mock_aniworld):
        """GetLoader should return same instance on repeated calls."""
        mock_instance = MagicMock(spec=Loader)
        mock_aniworld.return_value = mock_instance
        factory = Loaders()
        first = factory.GetLoader("aniworld.to")
        second = factory.GetLoader("aniworld.to")
        assert first is second

    @patch("src.core.providers.provider_factory.AniworldLoader")
    def test_get_loader_empty_key(self, mock_aniworld):
        """GetLoader should raise KeyError for empty string key."""
        mock_aniworld.return_value = MagicMock(spec=Loader)
        factory = Loaders()
        with pytest.raises(KeyError):
            factory.GetLoader("")


class TestLoadersProviderRegistry:
    """Test the provider registry within the factory."""

    @patch("src.core.providers.provider_factory.AniworldLoader")
    def test_registry_size(self, mock_aniworld):
        """Factory should have exactly one default provider."""
        mock_aniworld.return_value = MagicMock(spec=Loader)
        factory = Loaders()
        assert len(factory.dict) == 1

    @patch("src.core.providers.provider_factory.AniworldLoader")
    def test_can_add_custom_provider(self, mock_aniworld):
        """Custom providers can be added to the factory registry."""
        mock_aniworld.return_value = MagicMock(spec=Loader)
        factory = Loaders()
        custom_provider = MagicMock(spec=Loader)
        factory.dict["custom.provider"] = custom_provider
        assert factory.GetLoader("custom.provider") is custom_provider

    @patch("src.core.providers.provider_factory.AniworldLoader")
    def test_can_override_existing_provider(self, mock_aniworld):
        """Existing providers can be overridden in the registry."""
        mock_aniworld.return_value = MagicMock(spec=Loader)
        factory = Loaders()
        new_provider = MagicMock(spec=Loader)
        factory.dict["aniworld.to"] = new_provider
        assert factory.GetLoader("aniworld.to") is new_provider

    @patch("src.core.providers.provider_factory.AniworldLoader")
    def test_multiple_factories_are_independent(self, mock_aniworld):
        """Multiple factory instances should have independent registries."""
        mock_aniworld.return_value = MagicMock(spec=Loader)
        factory1 = Loaders()
        factory2 = Loaders()
        factory1.dict["extra"] = MagicMock(spec=Loader)
        assert "extra" not in factory2.dict
