"""Location service for emergency location operations.

This module provides the LocationService class for listing, searching, and
validating emergency locations from the CSV cache.
"""

from __future__ import annotations

from datetime import timedelta
from typing import TYPE_CHECKING, Any

from teams_phone.constants import CSV_STALE_DAYS
from teams_phone.exceptions import NotFoundError
from teams_phone.models import EmergencyLocation

if TYPE_CHECKING:
    from teams_phone.infrastructure import CacheManager


class LocationService:
    """Service for emergency location operations.

    Provides methods for listing, searching, and validating emergency
    locations from the CSV cache.

    Attributes:
        cache_manager: CacheManager instance for CSV access.
    """

    def __init__(self, cache_manager: CacheManager) -> None:
        """Initialize the LocationService.

        Args:
            cache_manager: CacheManager instance for CSV reading.
        """
        self.cache_manager = cache_manager

    def list_locations(self) -> list[EmergencyLocation]:
        """List all emergency locations from the cache.

        Returns:
            List of EmergencyLocation objects. Empty list if CSV doesn't
            exist or is malformed.
        """
        raw_data = self.cache_manager.read_locations_csv()
        locations: list[EmergencyLocation] = []

        for row in raw_data:
            # Create a new dict with boolean conversion for isDefault field
            # CacheManager returns dict[str, str], but Pydantic needs bool for isDefault
            validated_row: dict[str, Any] = dict(row)
            validated_row["isDefault"] = row.get("isDefault", "").lower() == "true"
            locations.append(EmergencyLocation.model_validate(validated_row))

        return locations

    def get_location(self, location_id: str) -> EmergencyLocation | None:
        """Get a single location by ID.

        Args:
            location_id: The location's unique identifier (GUID).

        Returns:
            EmergencyLocation if found, None otherwise.
        """
        locations = self.list_locations()

        for location in locations:
            if location.location_id == location_id:
                return location

        return None

    def search_locations(self, query: str) -> list[EmergencyLocation]:
        """Search locations by description, city, or address.

        Performs case-insensitive search across description, city, and
        address fields.

        Args:
            query: Search query string.

        Returns:
            List of EmergencyLocation objects matching the query.
        """
        locations = self.list_locations()
        query_lower = query.lower()
        results: list[EmergencyLocation] = []

        for location in locations:
            # Search in description, city, and address fields
            if query_lower in (location.description or "").lower():
                results.append(location)
            elif query_lower in (location.city or "").lower():
                results.append(location)
            elif query_lower in (location.address or "").lower():
                results.append(location)

        return results

    def validate_location(self, identifier: str) -> EmergencyLocation:
        """Validate and retrieve a location by ID or description.

        Attempts to find a location matching the identifier. Searches by
        exact location ID first, then by exact description match.

        Args:
            identifier: Location ID (GUID) or description.

        Returns:
            EmergencyLocation for the matched location.

        Raises:
            NotFoundError: If no location matches the identifier.
        """
        location = self._find_location(identifier)

        if location is None:
            raise NotFoundError(
                f"Location '{identifier}' not found",
                remediation=(
                    "Verify the location ID or description is correct.\n"
                    "Use 'teams-phone locations list' to see available locations."
                ),
            )

        return location

    def _find_location(self, identifier: str) -> EmergencyLocation | None:
        """Find a location by ID or description.

        Args:
            identifier: Location ID (GUID) or description.

        Returns:
            EmergencyLocation if found, None otherwise.
        """
        locations = self.list_locations()

        # First, try exact ID match
        for location in locations:
            if location.location_id == identifier:
                return location

        # Then, try exact description match (case-insensitive)
        identifier_lower = identifier.lower()
        for location in locations:
            if (location.description or "").lower() == identifier_lower:
                return location

        return None

    def get_cache_age(self) -> timedelta | None:
        """Get the age of the location cache.

        Returns:
            timedelta representing the cache age, or None if no cache exists.
        """
        age_days = self.cache_manager.get_cache_age_days()

        if age_days is None:
            return None

        return timedelta(days=age_days)

    def is_cache_stale(self) -> bool:
        """Check if the location cache is stale.

        Returns:
            True if cache doesn't exist or is older than CSV_STALE_DAYS (30 days).
        """
        return self.cache_manager.is_cache_stale()

    def get_staleness_warning(self) -> str | None:
        """Get a warning message if the cache is stale.

        Returns:
            Warning message string if cache is stale, None otherwise.
        """
        if not self.is_cache_stale():
            return None

        age_days = self.cache_manager.get_cache_age_days()

        if age_days is None:
            return (
                "Location cache not found. "
                "Run the PowerShell export script to create the cache."
            )

        return (
            f"Location cache is {age_days} days old (threshold: {CSV_STALE_DAYS} days). "
            "Consider refreshing by running the PowerShell export script."
        )
