"""Tests for SerieList class - identifier standardization."""
# pylint: disable=redefined-outer-name

import os
import tempfile
import warnings

import pytest

from src.core.entities.SerieList import SerieList
from src.core.entities.series import Serie


@pytest.fixture
def temp_directory():
    """Create a temporary directory for testing."""
    with tempfile.TemporaryDirectory() as tmpdir:
        yield tmpdir


@pytest.fixture
def sample_serie():
    """Create a sample Serie for testing."""
    return Serie(
        key="attack-on-titan",
        name="Attack on Titan",
        site="https://aniworld.to/anime/stream/attack-on-titan",
        folder="Attack on Titan (2013)",
        episodeDict={1: [1, 2, 3]}
    )


class TestSerieListKeyBasedStorage:
    """Test SerieList uses key for internal storage."""

    def test_init_creates_empty_keydict(self, temp_directory):
        """Test initialization creates keyDict."""
        serie_list = SerieList(temp_directory)
        assert hasattr(serie_list, 'keyDict')
        assert isinstance(serie_list.keyDict, dict)

    def test_add_stores_by_key(self, temp_directory, sample_serie):
        """Test add() stores series by key."""
        serie_list = SerieList(temp_directory)
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            serie_list.add(sample_serie)
        
        # Verify stored by key, not folder
        assert sample_serie.key in serie_list.keyDict
        assert serie_list.keyDict[sample_serie.key] == sample_serie

    def test_contains_checks_by_key(self, temp_directory, sample_serie):
        """Test contains() checks by key."""
        serie_list = SerieList(temp_directory)
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            serie_list.add(sample_serie)
        
        assert serie_list.contains(sample_serie.key)
        assert not serie_list.contains("nonexistent-key")

    def test_add_prevents_duplicates_by_key(
        self, temp_directory, sample_serie
    ):
        """Test add() prevents duplicates based on key."""
        serie_list = SerieList(temp_directory)
        
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            # Add same serie twice
            serie_list.add(sample_serie)
            initial_count = len(serie_list.keyDict)
            
            serie_list.add(sample_serie)
        
        # Should still have only one entry
        assert len(serie_list.keyDict) == initial_count
        assert len(serie_list.keyDict) == 1

    def test_get_by_key_returns_correct_serie(
        self, temp_directory, sample_serie
    ):
        """Test get_by_key() retrieves series correctly."""
        serie_list = SerieList(temp_directory)
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            serie_list.add(sample_serie)
        
        result = serie_list.get_by_key(sample_serie.key)
        assert result is not None
        assert result.key == sample_serie.key
        assert result.name == sample_serie.name

    def test_get_by_key_returns_none_for_missing(self, temp_directory):
        """Test get_by_key() returns None for nonexistent key."""
        serie_list = SerieList(temp_directory)
        
        result = serie_list.get_by_key("nonexistent-key")
        assert result is None

    def test_get_by_folder_backward_compatibility(
        self, temp_directory, sample_serie
    ):
        """Test get_by_folder() provides backward compatibility."""
        serie_list = SerieList(temp_directory)
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            serie_list.add(sample_serie)
            result = serie_list.get_by_folder(sample_serie.folder)
        
        assert result is not None
        assert result.key == sample_serie.key
        assert result.folder == sample_serie.folder

    def test_get_by_folder_returns_none_for_missing(self, temp_directory):
        """Test get_by_folder() returns None for nonexistent folder."""
        serie_list = SerieList(temp_directory)
        
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            result = serie_list.get_by_folder("Nonexistent Folder")
        assert result is None

    def test_get_all_returns_all_series(self, temp_directory, sample_serie):
        """Test get_all() returns all series from keyDict."""
        serie_list = SerieList(temp_directory)
        
        serie2 = Serie(
            key="naruto",
            name="Naruto",
            site="https://aniworld.to/anime/stream/naruto",
            folder="Naruto (2002)",
            episodeDict={1: [1, 2]}
        )
        
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            serie_list.add(sample_serie)
            serie_list.add(serie2)
        
        all_series = serie_list.get_all()
        assert len(all_series) == 2
        assert sample_serie in all_series
        assert serie2 in all_series

    def test_get_missing_episodes_filters_by_episode_dict(
        self, temp_directory
    ):
        """Test get_missing_episodes() returns only series with episodes."""
        serie_list = SerieList(temp_directory)
        
        # Serie with missing episodes
        serie_with_episodes = Serie(
            key="serie-with-episodes",
            name="Serie With Episodes",
            site="https://aniworld.to/anime/stream/serie-with-episodes",
            folder="Serie With Episodes (2020)",
            episodeDict={1: [1, 2, 3]}
        )
        
        # Serie without missing episodes
        serie_without_episodes = Serie(
            key="serie-without-episodes",
            name="Serie Without Episodes",
            site="https://aniworld.to/anime/stream/serie-without-episodes",
            folder="Serie Without Episodes (2021)",
            episodeDict={}
        )
        
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            serie_list.add(serie_with_episodes)
            serie_list.add(serie_without_episodes)
        
        missing = serie_list.get_missing_episodes()
        assert len(missing) == 1
        assert serie_with_episodes in missing
        assert serie_without_episodes not in missing

    def test_load_series_stores_by_key(self, temp_directory, sample_serie):
        """Test load_series() stores series by key when loading from disk."""
        # Create directory structure and save serie
        folder_path = os.path.join(temp_directory, sample_serie.folder)
        os.makedirs(folder_path, exist_ok=True)
        data_path = os.path.join(folder_path, "data")
        sample_serie.save_to_file(data_path)
        
        # Create new SerieList (triggers load_series in __init__)
        serie_list = SerieList(temp_directory)
        
        # Verify loaded by key
        assert sample_serie.key in serie_list.keyDict
        loaded_serie = serie_list.keyDict[sample_serie.key]
        assert loaded_serie.key == sample_serie.key
        assert loaded_serie.name == sample_serie.name


class TestSerieListPublicAPI:
    """Test that public API still works correctly."""

    def test_public_methods_work(self, temp_directory, sample_serie):
        """Test that all public methods work correctly after refactoring."""
        serie_list = SerieList(temp_directory)
        
        # Test add (suppress deprecation warning for test)
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            serie_list.add(sample_serie)
        
        # Test contains
        assert serie_list.contains(sample_serie.key)
        
        # Test GetList/get_all
        assert len(serie_list.GetList()) == 1
        assert len(serie_list.get_all()) == 1
        
        # Test GetMissingEpisode/get_missing_episodes
        assert len(serie_list.GetMissingEpisode()) == 1
        assert len(serie_list.get_missing_episodes()) == 1
        
        # Test new helper methods
        assert serie_list.get_by_key(sample_serie.key) is not None
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            assert serie_list.get_by_folder(sample_serie.folder) is not None


class TestSerieListSkipLoad:
    """Test SerieList initialization options."""

    def test_init_with_skip_load(self, temp_directory):
        """Test initialization with skip_load=True skips loading."""
        serie_list = SerieList(temp_directory, skip_load=True)
        assert len(serie_list.keyDict) == 0


class TestSerieListDeprecationWarnings:
    """Test deprecation warnings are raised for file-based methods."""

    def test_get_by_folder_raises_deprecation_warning(
        self, temp_directory, sample_serie
    ):
        """Test get_by_folder() raises deprecation warning."""
        serie_list = SerieList(temp_directory, skip_load=True)
        serie_list.keyDict[sample_serie.key] = sample_serie
        
        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            serie_list.get_by_folder(sample_serie.folder)
            
            # Check deprecation warning was raised
            assert len(w) == 1
            assert issubclass(w[0].category, DeprecationWarning)
            assert "get_by_key()" in str(w[0].message)


class TestSerieListBackwardCompatibility:
    """Test backward compatibility of file-based operations."""

    def test_file_based_mode_still_works(
        self, temp_directory, sample_serie
    ):
        """Test file-based mode still works without db_session."""
        serie_list = SerieList(temp_directory)
        
        # Add should still work (with deprecation warning)
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            serie_list.add(sample_serie)
        
        # File should be created
        data_path = os.path.join(
            temp_directory, sample_serie.folder, "data"
        )
        assert os.path.isfile(data_path)
        
        # Series should be in memory
        assert serie_list.contains(sample_serie.key)

    def test_load_from_file_still_works(
        self, temp_directory, sample_serie
    ):
        """Test loading from files still works."""
        # Create directory and save file
        folder_path = os.path.join(temp_directory, sample_serie.folder)
        os.makedirs(folder_path, exist_ok=True)
        data_path = os.path.join(folder_path, "data")
        sample_serie.save_to_file(data_path)
        
        # New SerieList should load it
        serie_list = SerieList(temp_directory)
        
        assert serie_list.contains(sample_serie.key)
        loaded = serie_list.get_by_key(sample_serie.key)
        assert loaded.name == sample_serie.name


class TestSerieListNFOFeatures:
    """Test SerieList NFO detection and logging."""

    def test_load_series_detects_nfo_file(self, temp_directory, caplog):
        """Test load_series detects and sets nfo_path for series with NFO."""
        import logging
        caplog.set_level(logging.INFO)
        
        # Create series folder with data file and NFO
        folder_name = "Test Series"
        folder_path = os.path.join(temp_directory, folder_name)
        os.makedirs(folder_path)
        
        serie = Serie(
            key="test-series",
            name="Test Series",
            site="https://example.com",
            folder=folder_name,
            episodeDict={1: [1, 2]}
        )
        
        data_path = os.path.join(folder_path, "data")
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            serie.save_to_file(data_path)
        
        # Create NFO file
        nfo_path = os.path.join(folder_path, "tvshow.nfo")
        with open(nfo_path, "w") as f:
            f.write("<tvshow></tvshow>")
        
        # Load series
        serie_list = SerieList(temp_directory)
        
        # Verify NFO was detected
        loaded = serie_list.get_by_key("test-series")
        assert loaded is not None
        assert loaded.nfo_path == nfo_path
        
        # Verify logging
        assert "1 with NFO" in caplog.text

    def test_load_series_detects_missing_nfo(self, temp_directory, caplog):
        """Test load_series logs when NFO is missing."""
        import logging
        caplog.set_level(logging.DEBUG)
        
        # Create series folder with data file but NO NFO
        folder_name = "Test Series"
        folder_path = os.path.join(temp_directory, folder_name)
        os.makedirs(folder_path)
        
        serie = Serie(
            key="test-series",
            name="Test Series",
            site="https://example.com",
            folder=folder_name,
            episodeDict={1: [1, 2]}
        )
        
        data_path = os.path.join(folder_path, "data")
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            serie.save_to_file(data_path)
        
        # Load series
        serie_list = SerieList(temp_directory)
        
        # Verify NFO not set
        loaded = serie_list.get_by_key("test-series")
        assert loaded is not None
        assert loaded.nfo_path is None
        
        # Verify logging
        assert "missing tvshow.nfo" in caplog.text

    def test_load_series_detects_media_files(self, temp_directory, caplog):
        """Test load_series detects poster, logo, and fanart files."""
        import logging
        caplog.set_level(logging.INFO)
        
        # Create series folder with all media files
        folder_name = "Test Series"
        folder_path = os.path.join(temp_directory, folder_name)
        os.makedirs(folder_path)
        
        serie = Serie(
            key="test-series",
            name="Test Series",
            site="https://example.com",
            folder=folder_name,
            episodeDict={1: [1, 2]}
        )
        
        data_path = os.path.join(folder_path, "data")
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            serie.save_to_file(data_path)
        
        # Create media files
        with open(os.path.join(folder_path, "poster.jpg"), "w") as f:
            f.write("poster data")
        with open(os.path.join(folder_path, "logo.png"), "w") as f:
            f.write("logo data")
        with open(os.path.join(folder_path, "fanart.jpg"), "w") as f:
            f.write("fanart data")
        
        # Load series
        serie_list = SerieList(temp_directory)
        
        # Verify logging shows all media found
        assert "Poster (1/1)" in caplog.text
        assert "Logo (1/1)" in caplog.text
        assert "Fanart (1/1)" in caplog.text

    def test_load_series_detects_missing_media_files(
        self, temp_directory, caplog
    ):
        """Test load_series logs when media files are missing."""
        import logging
        caplog.set_level(logging.DEBUG)
        
        # Create series folder with NO media files
        folder_name = "Test Series"
        folder_path = os.path.join(temp_directory, folder_name)
        os.makedirs(folder_path)
        
        serie = Serie(
            key="test-series",
            name="Test Series",
            site="https://example.com",
            folder=folder_name,
            episodeDict={1: [1, 2]}
        )
        
        data_path = os.path.join(folder_path, "data")
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", DeprecationWarning)
            serie.save_to_file(data_path)
        
        # Load series
        serie_list = SerieList(temp_directory)
        
        # Verify logging shows missing media
        assert "missing poster.jpg" in caplog.text
        assert "missing logo.png" in caplog.text
        assert "missing fanart.jpg" in caplog.text

    def test_load_series_summary_statistics(self, temp_directory, caplog):
        """Test load_series logs summary statistics for NFO and media."""
        import logging
        caplog.set_level(logging.INFO)
        
        # Create multiple series with varying NFO/media status
        for i in range(3):
            folder_name = f"Series {i}"
            folder_path = os.path.join(temp_directory, folder_name)
            os.makedirs(folder_path)
            
            serie = Serie(
                key=f"series-{i}",
                name=f"Series {i}",
                site="https://example.com",
                folder=folder_name,
                episodeDict={1: [1]}
            )
            
            data_path = os.path.join(folder_path, "data")
            with warnings.catch_warnings():
                warnings.simplefilter("ignore", DeprecationWarning)
                serie.save_to_file(data_path)
            
            # First series has everything
            if i == 0:
                with open(os.path.join(folder_path, "tvshow.nfo"), "w") as f:
                    f.write("<tvshow></tvshow>")
                with open(os.path.join(folder_path, "poster.jpg"), "w") as f:
                    f.write("poster")
                with open(os.path.join(folder_path, "logo.png"), "w") as f:
                    f.write("logo")
                with open(os.path.join(folder_path, "fanart.jpg"), "w") as f:
                    f.write("fanart")
            # Second series has NFO and poster only
            elif i == 1:
                with open(os.path.join(folder_path, "tvshow.nfo"), "w") as f:
                    f.write("<tvshow></tvshow>")
                with open(os.path.join(folder_path, "poster.jpg"), "w") as f:
                    f.write("poster")
            # Third series has nothing
        
        # Load series
        serie_list = SerieList(temp_directory)
        
        # Verify summary statistics
        assert "3 series total" in caplog.text
        assert "2 with NFO, 1 without NFO" in caplog.text
        assert "Poster (2/3)" in caplog.text
        assert "Logo (1/3)" in caplog.text
        assert "Fanart (1/3)" in caplog.text

    def test_load_series_handles_load_failure(self, temp_directory, caplog):
        """Test load_series handles series that fail to load gracefully."""
        import logging
        caplog.set_level(logging.ERROR)
        
        # Create folder with invalid data file
        folder_name = "Invalid Series"
        folder_path = os.path.join(temp_directory, folder_name)
        os.makedirs(folder_path)
        
        data_path = os.path.join(folder_path, "data")
        with open(data_path, "w") as f:
            f.write("invalid json {{{")
        
        # Load series - should not crash
        serie_list = SerieList(temp_directory)
        
        # Verify error logged
        assert "Failed to load metadata" in caplog.text
        
        # Should not be in keyDict
        assert len(serie_list.keyDict) == 0

