"""Unit tests for anime key rename logic and validation."""
import pytest
from pydantic import ValidationError

from src.server.models.anime import AnimeMetadataUpdate, KEY_PATTERN


class TestKeyValidation:
    """Tests for AnimeMetadataUpdate key validation."""

    def test_valid_key_simple(self):
        """Test simple valid key."""
        model = AnimeMetadataUpdate(key="attack-on-titan")
        assert model.key == "attack-on-titan"

    def test_valid_key_single_char(self):
        """Test single character key is valid."""
        model = AnimeMetadataUpdate(key="a")
        assert model.key == "a"

    def test_valid_key_numbers(self):
        """Test key with numbers."""
        model = AnimeMetadataUpdate(key="86-eighty-six")
        assert model.key == "86-eighty-six"

    def test_valid_key_allows_hyphens(self):
        """Test hyphens in key are allowed."""
        model = AnimeMetadataUpdate(key="my-anime-key")
        assert model.key == "my-anime-key"

    def test_valid_key_normalizes_to_lowercase(self):
        """Test key is normalized to lowercase."""
        model = AnimeMetadataUpdate(key="Attack-On-Titan")
        assert model.key == "attack-on-titan"

    def test_valid_key_strips_whitespace(self):
        """Test key strips leading/trailing whitespace."""
        model = AnimeMetadataUpdate(key="  my-key  ")
        assert model.key == "my-key"

    def test_invalid_key_spaces(self):
        """Test key with spaces is rejected."""
        with pytest.raises(ValidationError) as exc_info:
            AnimeMetadataUpdate(key="my anime key")
        assert "Key must contain only" in str(exc_info.value)

    def test_invalid_key_uppercase_special(self):
        """Test key with special characters is rejected."""
        with pytest.raises(ValidationError) as exc_info:
            AnimeMetadataUpdate(key="anime!@#key")
        assert "Key must contain only" in str(exc_info.value)

    def test_invalid_key_empty(self):
        """Test empty key is rejected."""
        with pytest.raises(ValidationError) as exc_info:
            AnimeMetadataUpdate(key="")
        assert "cannot be empty" in str(exc_info.value)

    def test_invalid_key_only_whitespace(self):
        """Test whitespace-only key is rejected."""
        with pytest.raises(ValidationError) as exc_info:
            AnimeMetadataUpdate(key="   ")
        assert "cannot be empty" in str(exc_info.value)

    def test_invalid_key_starts_with_hyphen(self):
        """Test key starting with hyphen is rejected."""
        with pytest.raises(ValidationError):
            AnimeMetadataUpdate(key="-my-key")

    def test_invalid_key_ends_with_hyphen(self):
        """Test key ending with hyphen is rejected."""
        with pytest.raises(ValidationError):
            AnimeMetadataUpdate(key="my-key-")

    def test_key_none_is_allowed(self):
        """Test None key (no change requested) is allowed."""
        model = AnimeMetadataUpdate(key=None)
        assert model.key is None

    def test_key_omitted_is_allowed(self):
        """Test omitting key entirely is allowed."""
        model = AnimeMetadataUpdate(tmdb_id=1234)
        assert model.key is None


class TestTmdbIdValidation:
    """Tests for tmdb_id validation."""

    def test_valid_tmdb_id(self):
        """Test valid positive TMDB ID."""
        model = AnimeMetadataUpdate(tmdb_id=1429)
        assert model.tmdb_id == 1429

    def test_tmdb_id_none(self):
        """Test None tmdb_id is allowed."""
        model = AnimeMetadataUpdate(tmdb_id=None)
        assert model.tmdb_id is None

    def test_tmdb_id_negative_rejected(self):
        """Test negative tmdb_id is rejected."""
        with pytest.raises(ValidationError):
            AnimeMetadataUpdate(tmdb_id=-1)

    def test_tmdb_id_zero_rejected(self):
        """Test zero tmdb_id is rejected."""
        with pytest.raises(ValidationError):
            AnimeMetadataUpdate(tmdb_id=0)


class TestTvdbIdValidation:
    """Tests for tvdb_id validation."""

    def test_valid_tvdb_id(self):
        """Test valid positive TVDB ID."""
        model = AnimeMetadataUpdate(tvdb_id=267440)
        assert model.tvdb_id == 267440

    def test_tvdb_id_none(self):
        """Test None tvdb_id is allowed."""
        model = AnimeMetadataUpdate(tvdb_id=None)
        assert model.tvdb_id is None

    def test_tvdb_id_negative_rejected(self):
        """Test negative tvdb_id is rejected."""
        with pytest.raises(ValidationError):
            AnimeMetadataUpdate(tvdb_id=-5)

    def test_tvdb_id_zero_rejected(self):
        """Test zero tvdb_id is rejected."""
        with pytest.raises(ValidationError):
            AnimeMetadataUpdate(tvdb_id=0)


class TestKeyPattern:
    """Tests for the KEY_PATTERN regex directly."""

    @pytest.mark.parametrize("key", [
        "a",
        "abc",
        "attack-on-titan",
        "86-eighty-six",
        "a1b2c3",
        "x",
        "1",
    ])
    def test_valid_patterns(self, key):
        """Test keys that should match the pattern."""
        assert KEY_PATTERN.match(key) is not None

    @pytest.mark.parametrize("key", [
        "-start",
        "end-",
        "has space",
        "UPPER",
        "special!char",
        "under_score",
        "",
    ])
    def test_invalid_patterns(self, key):
        """Test keys that should not match the pattern."""
        assert KEY_PATTERN.match(key) is None
