"""iTunes Search API client with rate limiting."""

import asyncio
import time
from typing import Optional
from dataclasses import dataclass, field

import httpx

ITUNES_SEARCH_URL = "https://itunes.apple.com/search"
ITUNES_LOOKUP_URL = "https://itunes.apple.com/lookup"

# Rate limit: ~20 req/min to be safe
MIN_REQUEST_INTERVAL = 3.0

@dataclass
class AppResult:
    """Parsed app result from iTunes Search API."""
    track_id: int
    name: str
    bundle_id: str
    developer: str
    price: float
    currency: str
    primary_genre: str
    genres: list[str]
    rating: float
    rating_count: int
    current_version_rating: float
    current_version_rating_count: int
    description: str
    release_date: str
    updated_date: str
    version: str
    content_rating: str
    file_size_bytes: Optional[int]
    icon_url: str
    store_url: str
    minimum_os: str

    @classmethod
    def from_api(cls, data: dict) -> "AppResult":
        return cls(
            track_id=data.get("trackId", 0),
            name=data.get("trackName", ""),
            bundle_id=data.get("bundleId", ""),
            developer=data.get("artistName", ""),
            price=data.get("price", 0.0),
            currency=data.get("currency", "USD"),
            primary_genre=data.get("primaryGenreName", ""),
            genres=data.get("genres", []),
            rating=data.get("averageUserRating", 0.0),
            rating_count=data.get("userRatingCount", 0),
            current_version_rating=data.get("averageUserRatingForCurrentVersion", 0.0),
            current_version_rating_count=data.get("userRatingCountForCurrentVersion", 0),
            description=data.get("description", ""),
            release_date=data.get("releaseDate", ""),
            updated_date=data.get("currentVersionReleaseDate", ""),
            version=data.get("version", ""),
            content_rating=data.get("contentAdvisoryRating", ""),
            file_size_bytes=int(data["fileSizeBytes"]) if data.get("fileSizeBytes") else None,
            icon_url=data.get("artworkUrl512", data.get("artworkUrl100", "")),
            store_url=data.get("trackViewUrl", ""),
            minimum_os=data.get("minimumOsVersion", ""),
        )

    def to_dict(self) -> dict:
        return {
            "track_id": self.track_id,
            "name": self.name,
            "bundle_id": self.bundle_id,
            "developer": self.developer,
            "price": self.price,
            "primary_genre": self.primary_genre,
            "rating": round(self.rating, 2),
            "rating_count": self.rating_count,
            "release_date": self.release_date,
            "store_url": self.store_url,
        }


@dataclass
class SearchResult:
    """Full search result for a keyword."""
    keyword: str
    country: str
    result_count: int
    apps: list[AppResult]
    searched_at: float = field(default_factory=time.time)

    def to_dict(self) -> dict:
        return {
            "keyword": self.keyword,
            "country": self.country,
            "result_count": self.result_count,
            "apps": [a.to_dict() for a in self.apps],
        }


class ITunesClient:
    """Async iTunes Search API client with built-in rate limiting."""

    def __init__(self):
        self._last_request_time: float = 0.0
        self._client: Optional[httpx.AsyncClient] = None

    async def _get_client(self) -> httpx.AsyncClient:
        if self._client is None or self._client.is_closed:
            self._client = httpx.AsyncClient(
                timeout=15.0,
                headers={"User-Agent": "ASO-MCP/0.1"},
                follow_redirects=True,
            )
        return self._client

    async def _rate_limit(self):
        """Enforce minimum interval between requests."""
        now = time.time()
        elapsed = now - self._last_request_time
        if elapsed < MIN_REQUEST_INTERVAL:
            await asyncio.sleep(MIN_REQUEST_INTERVAL - elapsed)
        self._last_request_time = time.time()

    async def search(
        self,
        keyword: str,
        country: str = "US",
        limit: int = 200,
    ) -> SearchResult:
        """Search iTunes for apps matching a keyword."""
        await self._rate_limit()
        client = await self._get_client()

        params = {
            "term": keyword,
            "country": country,
            "media": "software",
            "limit": min(limit, 200),
        }

        try:
            resp = await client.get(ITUNES_SEARCH_URL, params=params)
            resp.raise_for_status()
            data = resp.json()
        except httpx.HTTPStatusError as e:
            raise RuntimeError(f"iTunes API error: HTTP {e.response.status_code}") from e
        except Exception as e:
            raise RuntimeError(f"iTunes API request failed: {e}") from e

        apps = [AppResult.from_api(r) for r in data.get("results", [])]

        return SearchResult(
            keyword=keyword,
            country=country,
            result_count=data.get("resultCount", len(apps)),
            apps=apps,
        )

    async def lookup(self, app_id: int, country: str = "US") -> Optional[AppResult]:
        """Look up a specific app by track ID."""
        await self._rate_limit()
        client = await self._get_client()

        params = {"id": app_id, "country": country}

        try:
            resp = await client.get(ITUNES_LOOKUP_URL, params=params)
            resp.raise_for_status()
            data = resp.json()
        except Exception as e:
            raise RuntimeError(f"iTunes lookup failed: {e}") from e

        results = data.get("results", [])
        if not results:
            return None
        return AppResult.from_api(results[0])

    async def close(self):
        if self._client and not self._client.is_closed:
            await self._client.aclose()
