"""Unit tests for LocationService."""

from datetime import timedelta
from pathlib import Path

import pytest

from teams_phone.exceptions import NotFoundError
from teams_phone.infrastructure import CacheManager
from teams_phone.models import EmergencyLocation
from teams_phone.services.location_service import LocationService

# Sample CSV content for tests (from test_cache_manager.py)
LOCATIONS_CSV = """locationId,civicAddressId,description,companyName,address,city,stateOrProvince,postalCode,countryOrRegion,isDefault
93cb8a70-b4af-41df-9928-d07607e21776,a1b2c3d4-0000-0000-0000-000000000000,Main Office - Floor 3,Contoso Ltd,123 Main St,Seattle,WA,98101,US,True
f47ac10b-58cc-4372-a567-0e02b2c3d479,a1b2c3d4-0000-0000-0000-000000000000,Branch Office,Contoso Ltd,456 Oak Ave,Portland,OR,97201,US,False"""


class TestLocationServiceInit:
    """Tests for LocationService initialization."""

    @pytest.mark.unit
    def test_init_stores_cache_manager(self, tmp_path: Path) -> None:
        """Constructor stores the cache_manager instance."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        service = LocationService(cache_manager)

        assert service.cache_manager is cache_manager


class TestLocationServiceListLocations:
    """Tests for list_locations method."""

    @pytest.mark.unit
    def test_list_locations_returns_empty_list_when_no_csv(
        self, tmp_path: Path
    ) -> None:
        """list_locations returns empty list when CSV doesn't exist."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        service = LocationService(cache_manager)

        result = service.list_locations()

        assert result == []

    @pytest.mark.unit
    def test_list_locations_returns_emergency_location_objects(
        self, tmp_path: Path
    ) -> None:
        """list_locations returns list of EmergencyLocation objects."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        (tmp_path / "locations.csv").write_text(LOCATIONS_CSV, encoding="utf-8")
        service = LocationService(cache_manager)

        result = service.list_locations()

        assert len(result) == 2
        assert all(isinstance(loc, EmergencyLocation) for loc in result)

    @pytest.mark.unit
    def test_list_locations_parses_fields_correctly(self, tmp_path: Path) -> None:
        """list_locations correctly parses all fields from CSV."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        (tmp_path / "locations.csv").write_text(LOCATIONS_CSV, encoding="utf-8")
        service = LocationService(cache_manager)

        result = service.list_locations()

        first = result[0]
        assert first.location_id == "93cb8a70-b4af-41df-9928-d07607e21776"
        assert first.civic_address_id == "a1b2c3d4-0000-0000-0000-000000000000"
        assert first.description == "Main Office - Floor 3"
        assert first.company_name == "Contoso Ltd"
        assert first.address == "123 Main St"
        assert first.city == "Seattle"
        assert first.state_or_province == "WA"
        assert first.postal_code == "98101"
        assert first.country_or_region == "US"
        assert first.is_default is True

    @pytest.mark.unit
    def test_list_locations_converts_boolean_correctly(self, tmp_path: Path) -> None:
        """list_locations converts isDefault string to boolean."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        (tmp_path / "locations.csv").write_text(LOCATIONS_CSV, encoding="utf-8")
        service = LocationService(cache_manager)

        result = service.list_locations()

        assert result[0].is_default is True
        assert result[1].is_default is False


class TestLocationServiceGetLocation:
    """Tests for get_location method."""

    @pytest.mark.unit
    def test_get_location_returns_location_by_id(self, tmp_path: Path) -> None:
        """get_location returns location when ID matches."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        (tmp_path / "locations.csv").write_text(LOCATIONS_CSV, encoding="utf-8")
        service = LocationService(cache_manager)

        result = service.get_location("93cb8a70-b4af-41df-9928-d07607e21776")

        assert result is not None
        assert result.location_id == "93cb8a70-b4af-41df-9928-d07607e21776"
        assert result.description == "Main Office - Floor 3"

    @pytest.mark.unit
    def test_get_location_returns_none_for_unknown_id(self, tmp_path: Path) -> None:
        """get_location returns None when ID not found."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        (tmp_path / "locations.csv").write_text(LOCATIONS_CSV, encoding="utf-8")
        service = LocationService(cache_manager)

        result = service.get_location("unknown-id")

        assert result is None

    @pytest.mark.unit
    def test_get_location_returns_none_when_no_csv(self, tmp_path: Path) -> None:
        """get_location returns None when CSV doesn't exist."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        service = LocationService(cache_manager)

        result = service.get_location("93cb8a70-b4af-41df-9928-d07607e21776")

        assert result is None


class TestLocationServiceSearchLocations:
    """Tests for search_locations method."""

    @pytest.mark.unit
    def test_search_locations_finds_by_description(self, tmp_path: Path) -> None:
        """search_locations finds locations matching description."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        (tmp_path / "locations.csv").write_text(LOCATIONS_CSV, encoding="utf-8")
        service = LocationService(cache_manager)

        result = service.search_locations("Main Office")

        assert len(result) == 1
        assert result[0].description == "Main Office - Floor 3"

    @pytest.mark.unit
    def test_search_locations_finds_by_city(self, tmp_path: Path) -> None:
        """search_locations finds locations matching city."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        (tmp_path / "locations.csv").write_text(LOCATIONS_CSV, encoding="utf-8")
        service = LocationService(cache_manager)

        result = service.search_locations("Seattle")

        assert len(result) == 1
        assert result[0].city == "Seattle"

    @pytest.mark.unit
    def test_search_locations_finds_by_address(self, tmp_path: Path) -> None:
        """search_locations finds locations matching address."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        (tmp_path / "locations.csv").write_text(LOCATIONS_CSV, encoding="utf-8")
        service = LocationService(cache_manager)

        result = service.search_locations("Oak Ave")

        assert len(result) == 1
        assert result[0].address == "456 Oak Ave"

    @pytest.mark.unit
    def test_search_locations_is_case_insensitive(self, tmp_path: Path) -> None:
        """search_locations performs case-insensitive matching."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        (tmp_path / "locations.csv").write_text(LOCATIONS_CSV, encoding="utf-8")
        service = LocationService(cache_manager)

        result = service.search_locations("seattle")

        assert len(result) == 1
        assert result[0].city == "Seattle"

    @pytest.mark.unit
    def test_search_locations_returns_empty_for_no_match(self, tmp_path: Path) -> None:
        """search_locations returns empty list when no match found."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        (tmp_path / "locations.csv").write_text(LOCATIONS_CSV, encoding="utf-8")
        service = LocationService(cache_manager)

        result = service.search_locations("Nonexistent City")

        assert result == []

    @pytest.mark.unit
    def test_search_locations_returns_empty_when_no_csv(self, tmp_path: Path) -> None:
        """search_locations returns empty list when CSV doesn't exist."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        service = LocationService(cache_manager)

        result = service.search_locations("Seattle")

        assert result == []


class TestLocationServiceValidateLocation:
    """Tests for validate_location method."""

    @pytest.mark.unit
    def test_validate_location_returns_location_by_id(self, tmp_path: Path) -> None:
        """validate_location returns location when ID matches."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        (tmp_path / "locations.csv").write_text(LOCATIONS_CSV, encoding="utf-8")
        service = LocationService(cache_manager)

        result = service.validate_location("93cb8a70-b4af-41df-9928-d07607e21776")

        assert result.location_id == "93cb8a70-b4af-41df-9928-d07607e21776"

    @pytest.mark.unit
    def test_validate_location_returns_location_by_description(
        self, tmp_path: Path
    ) -> None:
        """validate_location returns location when description matches."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        (tmp_path / "locations.csv").write_text(LOCATIONS_CSV, encoding="utf-8")
        service = LocationService(cache_manager)

        result = service.validate_location("Main Office - Floor 3")

        assert result.description == "Main Office - Floor 3"

    @pytest.mark.unit
    def test_validate_location_description_case_insensitive(
        self, tmp_path: Path
    ) -> None:
        """validate_location matches description case-insensitively."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        (tmp_path / "locations.csv").write_text(LOCATIONS_CSV, encoding="utf-8")
        service = LocationService(cache_manager)

        result = service.validate_location("main office - floor 3")

        assert result.description == "Main Office - Floor 3"

    @pytest.mark.unit
    def test_validate_location_raises_not_found_error(self, tmp_path: Path) -> None:
        """validate_location raises NotFoundError for unknown identifier."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        (tmp_path / "locations.csv").write_text(LOCATIONS_CSV, encoding="utf-8")
        service = LocationService(cache_manager)

        with pytest.raises(NotFoundError) as exc_info:
            service.validate_location("unknown-location")

        assert "Location 'unknown-location' not found" in str(exc_info.value)
        assert exc_info.value.remediation is not None
        assert "teams-phone locations list" in exc_info.value.remediation

    @pytest.mark.unit
    def test_validate_location_raises_not_found_when_no_csv(
        self, tmp_path: Path
    ) -> None:
        """validate_location raises NotFoundError when CSV doesn't exist."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        service = LocationService(cache_manager)

        with pytest.raises(NotFoundError):
            service.validate_location("93cb8a70-b4af-41df-9928-d07607e21776")


class TestLocationServiceCacheAge:
    """Tests for get_cache_age method."""

    @pytest.mark.unit
    def test_get_cache_age_returns_none_when_no_cache(self, tmp_path: Path) -> None:
        """get_cache_age returns None when no cache exists."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        service = LocationService(cache_manager)

        result = service.get_cache_age()

        assert result is None

    @pytest.mark.unit
    def test_get_cache_age_returns_timedelta(self, tmp_path: Path) -> None:
        """get_cache_age returns timedelta when cache exists."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        (tmp_path / "locations.csv").write_text(LOCATIONS_CSV, encoding="utf-8")
        service = LocationService(cache_manager)

        result = service.get_cache_age()

        assert result is not None
        assert isinstance(result, timedelta)
        assert result.days == 0  # Just created, so 0 days old


class TestLocationServiceIsCacheStale:
    """Tests for is_cache_stale method."""

    @pytest.mark.unit
    def test_is_cache_stale_returns_true_when_no_cache(self, tmp_path: Path) -> None:
        """is_cache_stale returns True when no cache exists."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        service = LocationService(cache_manager)

        result = service.is_cache_stale()

        assert result is True

    @pytest.mark.unit
    def test_is_cache_stale_returns_false_for_fresh_cache(self, tmp_path: Path) -> None:
        """is_cache_stale returns False when cache is fresh."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        (tmp_path / "locations.csv").write_text(LOCATIONS_CSV, encoding="utf-8")
        service = LocationService(cache_manager)

        result = service.is_cache_stale()

        assert result is False


class TestLocationServiceStalenessWarning:
    """Tests for get_staleness_warning method."""

    @pytest.mark.unit
    def test_get_staleness_warning_returns_none_for_fresh_cache(
        self, tmp_path: Path
    ) -> None:
        """get_staleness_warning returns None when cache is fresh."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        (tmp_path / "locations.csv").write_text(LOCATIONS_CSV, encoding="utf-8")
        service = LocationService(cache_manager)

        result = service.get_staleness_warning()

        assert result is None

    @pytest.mark.unit
    def test_get_staleness_warning_returns_message_when_no_cache(
        self, tmp_path: Path
    ) -> None:
        """get_staleness_warning returns message when no cache exists."""
        cache_manager = CacheManager(cache_dir=str(tmp_path))
        service = LocationService(cache_manager)

        result = service.get_staleness_warning()

        assert result is not None
        assert "cache not found" in result.lower()
        assert "PowerShell" in result
