"""Unit tests for NFO auto-create logic.

Tests the NFO service's auto-creation logic, file path resolution,
existence checks, and configuration-based behavior.
"""
from pathlib import Path
from unittest.mock import AsyncMock, Mock, patch

import pytest

from src.core.services.nfo_service import NFOService


class TestNFOFileExistenceCheck:
    """Test NFO file existence checking logic."""

    def test_has_nfo_returns_true_when_file_exists(self, tmp_path):
        """Test has_nfo returns True when tvshow.nfo exists."""
        # Setup
        anime_dir = tmp_path / "anime"
        anime_dir.mkdir()
        serie_folder = anime_dir / "Test Series"
        serie_folder.mkdir()
        nfo_file = serie_folder / "tvshow.nfo"
        nfo_file.write_text("<tvshow></tvshow>")
        
        # Create service
        service = NFOService(
            tmdb_api_key="test_key",
            anime_directory=str(anime_dir)
        )
        
        # Test
        assert service.has_nfo("Test Series") is True

    def test_has_nfo_returns_false_when_file_missing(self, tmp_path):
        """Test has_nfo returns False when tvshow.nfo is missing."""
        # Setup
        anime_dir = tmp_path / "anime"
        anime_dir.mkdir()
        serie_folder = anime_dir / "Test Series"
        serie_folder.mkdir()
        
        # Create service
        service = NFOService(
            tmdb_api_key="test_key",
            anime_directory=str(anime_dir)
        )
        
        # Test
        assert service.has_nfo("Test Series") is False

    def test_has_nfo_returns_false_when_folder_missing(self, tmp_path):
        """Test has_nfo returns False when series folder doesn't exist."""
        # Setup
        anime_dir = tmp_path / "anime"
        anime_dir.mkdir()
        
        # Create service
        service = NFOService(
            tmdb_api_key="test_key",
            anime_directory=str(anime_dir)
        )
        
        # Test - folder doesn't exist
        assert service.has_nfo("Nonexistent Series") is False

    @pytest.mark.asyncio
    async def test_check_nfo_exists_returns_true_when_file_exists(self, tmp_path):
        """Test async check_nfo_exists returns True when file exists."""
        # Setup
        anime_dir = tmp_path / "anime"
        anime_dir.mkdir()
        serie_folder = anime_dir / "Test Series"
        serie_folder.mkdir()
        nfo_file = serie_folder / "tvshow.nfo"
        nfo_file.write_text("<tvshow></tvshow>")
        
        # Create service
        service = NFOService(
            tmdb_api_key="test_key",
            anime_directory=str(anime_dir)
        )
        
        # Test
        result = await service.check_nfo_exists("Test Series")
        assert result is True

    @pytest.mark.asyncio
    async def test_check_nfo_exists_returns_false_when_file_missing(self, tmp_path):
        """Test async check_nfo_exists returns False when file missing."""
        # Setup
        anime_dir = tmp_path / "anime"
        anime_dir.mkdir()
        serie_folder = anime_dir / "Test Series"
        serie_folder.mkdir()
        
        # Create service
        service = NFOService(
            tmdb_api_key="test_key",
            anime_directory=str(anime_dir)
        )
        
        # Test
        result = await service.check_nfo_exists("Test Series")
        assert result is False


class TestNFOFilePathResolution:
    """Test NFO file path resolution logic."""

    def test_nfo_path_constructed_correctly(self, tmp_path):
        """Test NFO path is constructed correctly from anime dir and series folder."""
        anime_dir = tmp_path / "anime"
        anime_dir.mkdir()
        
        service = NFOService(
            tmdb_api_key="test_key",
            anime_directory=str(anime_dir)
        )
        
        # Check internal path construction
        expected_path = anime_dir / "My Series" / "tvshow.nfo"
        actual_path = service.anime_directory / "My Series" / "tvshow.nfo"
        
        assert actual_path == expected_path

    def test_nfo_path_handles_special_characters(self, tmp_path):
        """Test NFO path handles special characters in folder name."""
        anime_dir = tmp_path / "anime"
        anime_dir.mkdir()
        
        service = NFOService(
            tmdb_api_key="test_key",
            anime_directory=str(anime_dir)
        )
        
        # Test with special characters
        folder_name = "Series: The (2024) [HD]"
        expected_path = anime_dir / folder_name / "tvshow.nfo"
        actual_path = service.anime_directory / folder_name / "tvshow.nfo"
        
        assert actual_path == expected_path

    def test_nfo_path_uses_pathlib(self, tmp_path):
        """Test that NFO path uses pathlib.Path internally."""
        anime_dir = tmp_path / "anime"
        anime_dir.mkdir()
        
        service = NFOService(
            tmdb_api_key="test_key",
            anime_directory=str(anime_dir)
        )
        
        # Service should use Path internally
        assert isinstance(service.anime_directory, Path)


class TestYearExtractionLogic:
    """Test year extraction from series names."""

    def test_extract_year_from_name_with_year(self):
        """Test extracting year from series name with (YYYY) format."""
        clean_name, year = NFOService._extract_year_from_name("Attack on Titan (2013)")
        
        assert clean_name == "Attack on Titan"
        assert year == 2013

    def test_extract_year_from_name_without_year(self):
        """Test extracting year when no year present."""
        clean_name, year = NFOService._extract_year_from_name("Attack on Titan")
        
        assert clean_name == "Attack on Titan"
        assert year is None

    def test_extract_year_handles_trailing_spaces(self):
        """Test year extraction handles trailing spaces."""
        clean_name, year = NFOService._extract_year_from_name("Cowboy Bebop (1998)  ")
        
        assert clean_name == "Cowboy Bebop"
        assert year == 1998

    def test_extract_year_handles_spaces_before_year(self):
        """Test year extraction handles spaces before parentheses."""
        clean_name, year = NFOService._extract_year_from_name("One Piece  (1999)")
        
        assert clean_name == "One Piece"
        assert year == 1999

    def test_extract_year_ignores_mid_name_years(self):
        """Test year extraction ignores years not at the end."""
        clean_name, year = NFOService._extract_year_from_name("Series (2020) Episode")
        
        # Should not extract since year is not at the end
        assert clean_name == "Series (2020) Episode"
        assert year is None

    def test_extract_year_with_various_formats(self):
        """Test year extraction with various common formats."""
        # Standard format
        name1, year1 = NFOService._extract_year_from_name("Series Name (2024)")
        assert name1 == "Series Name"
        assert year1 == 2024
        
        # With extra info before year
        name2, year2 = NFOService._extract_year_from_name("Long Series Name (2024)")
        assert name2 == "Long Series Name"
        assert year2 == 2024
        
        # Old year
        name3, year3 = NFOService._extract_year_from_name("Classic Show (1985)")
        assert name3 == "Classic Show"
        assert year3 == 1985


class TestConfigurationBasedBehavior:
    """Test configuration-based NFO creation behavior."""

    def test_auto_create_enabled_by_default(self):
        """Test auto_create is enabled by default."""
        service = NFOService(
            tmdb_api_key="test_key",
            anime_directory="/anime"
        )
        
        assert service.auto_create is True

    def test_auto_create_can_be_disabled(self):
        """Test auto_create can be explicitly disabled."""
        service = NFOService(
            tmdb_api_key="test_key",
            anime_directory="/anime",
            auto_create=False
        )
        
        assert service.auto_create is False

    def test_service_initializes_with_all_config_options(self):
        """Test service initializes with all configuration options."""
        service = NFOService(
            tmdb_api_key="test_key_123",
            anime_directory="/my/anime",
            image_size="w500",
            auto_create=True
        )
        
        assert service.tmdb_client is not None
        assert service.anime_directory == Path("/my/anime")
        assert service.image_size == "w500"
        assert service.auto_create is True

    def test_image_size_defaults_to_original(self):
        """Test image_size defaults to 'original'."""
        service = NFOService(
            tmdb_api_key="test_key",
            anime_directory="/anime"
        )
        
        assert service.image_size == "original"

    def test_image_size_can_be_customized(self):
        """Test image_size can be customized."""
        service = NFOService(
            tmdb_api_key="test_key",
            anime_directory="/anime",
            image_size="w780"
        )
        
        assert service.image_size == "w780"


class TestNFOCreationWithYearHandling:
    """Test NFO creation year handling logic."""

    def test_year_extraction_used_in_clean_name(self):
        """Test that year extraction produces clean name for search."""
        # This tests the _extract_year_from_name static method which is already tested above
        # Here we document that the clean name (without year) is used for searches
        clean_name, year = NFOService._extract_year_from_name("Attack on Titan (2013)")
        
        assert clean_name == "Attack on Titan"
        assert year == 2013

    def test_explicit_year_parameter_takes_precedence(self):
        """Test that explicit year parameter takes precedence over extracted year."""
        # When both explicit year and year in name are provided,
        # the explicit year parameter should be used
        # This is documented behavior, tested in integration tests
        clean_name, extracted_year = NFOService._extract_year_from_name("Test Series (2020)")
        
        # Extracted year is 2020
        assert extracted_year == 2020
        
        # But if explicit year=2019 is passed to create_tvshow_nfo,
        # it should use 2019 (tested in integration tests)
        assert clean_name == "Test Series"


class TestMediaFileDownloadConfiguration:
    """Test media file download configuration."""

    def test_download_flags_control_behavior(self):
        """Test that download flags (poster/logo/fanart) control download behavior."""
        # This tests the configuration options passed to create_tvshow_nfo
        # The actual download behavior is tested in integration tests
        
        # Document expected behavior:
        # - download_poster=True should download poster.jpg
        # - download_logo=True should download logo.png
        # - download_fanart=True should download fanart.jpg
        # - Setting any to False should skip that download
        
        # This behavior is enforced in NFOService.create_tvshow_nfo
        # and verified in integration tests
        pass

    def test_default_download_settings(self):
        """Test default media download settings."""
        # By default, create_tvshow_nfo has:
        # - download_poster=True
        # - download_logo=True
        # - download_fanart=True
        
        # This means all media is downloaded by default
        # Verified in integration tests
        pass


class TestNFOServiceEdgeCases:
    """Test edge cases in NFO service."""

    def test_service_requires_api_key(self):
        """Test service requires valid API key."""
        # TMDBClient validates API key on initialization
        with pytest.raises(ValueError, match="TMDB API key is required"):
            NFOService(
                tmdb_api_key="",
                anime_directory="/anime"
            )

    def test_has_nfo_handles_empty_folder_name(self, tmp_path):
        """Test has_nfo handles empty folder name."""
        anime_dir = tmp_path / "anime"
        anime_dir.mkdir()
        
        service = NFOService(
            tmdb_api_key="test_key",
            anime_directory=str(anime_dir)
        )
        
        # Should return False for empty folder
        assert service.has_nfo("") is False

    def test_extract_year_handles_invalid_year_format(self):
        """Test year extraction handles invalid year formats."""
        # Invalid year (not 4 digits)
        name1, year1 = NFOService._extract_year_from_name("Series (202)")
        assert name1 == "Series (202)"
        assert year1 is None
        
        # Year with letters
        name2, year2 = NFOService._extract_year_from_name("Series (202a)")
        assert name2 == "Series (202a)"
        assert year2 is None

    @pytest.mark.asyncio
    async def test_check_nfo_exists_handles_permission_error(self, tmp_path):
        """Test check_nfo_exists handles permission errors gracefully."""
        anime_dir = tmp_path / "anime"
        anime_dir.mkdir()
        serie_folder = anime_dir / "Test Series"
        serie_folder.mkdir()
        
        service = NFOService(
            tmdb_api_key="test_key",
            anime_directory=str(anime_dir)
        )
        
        # Mock path.exists to raise PermissionError
        with patch.object(Path, 'exists', side_effect=PermissionError("No access")):
            # Should handle error and return False
            # (In reality, exists() doesn't raise, but this tests robustness)
            with pytest.raises(PermissionError):
                await service.check_nfo_exists("Test Series")
