"""Resolves download/magnet links from tracker detail pages.

Some trackers (e.g. limetorrents) do not include direct download links
in search results. Instead, each result links to a details page where
the actual download/magnet URL can be found. This service fetches the
details page and extracts the link using CSS selectors from the YAML
definition's ``download`` section.
"""

import dataclasses
import logging

from bs4 import BeautifulSoup

from mariner.clients import http
from mariner.models import torrent, tracker
from mariner.services import templater

log = logging.getLogger(__name__)


class Service:
    """Fetches a torrent's detail page and extracts download/magnet links.

    Args:
        client: An async HTTP client for fetching detail pages.
        download_spec: The download section from the tracker YAML.
        config: The tracker's config dict for template rendering.

    """

    def __init__(
        self,
        client: http.AsyncClientProtocol,
        download_spec: tracker.DownloadSpec,
        config: dict[str, str],
    ) -> None:
        self._client = client
        self._spec = download_spec
        self._config = config

    async def resolve(self, t: torrent.Torrent) -> torrent.Torrent:
        """Fetch the detail page and return a Torrent with resolved links.

        If the detail page cannot be fetched or no selectors match,
        returns the original Torrent unchanged.

        Args:
            t: A torrent whose ``details_url`` points to the detail page.

        Returns:
            A new Torrent with ``download`` or ``magnet`` populated,
            or the original if resolution fails.

        """
        if not t.details_url:
            return t

        try:
            body = await self._client.get(t.details_url)
        except Exception:
            log.warning("Failed to fetch details page for %s", t.name)
            return t

        soup = BeautifulSoup(body, "lxml")
        ctx = {"Config": self._config}

        for sel in self._spec.selectors:
            rendered = templater.render(sel.selector, ctx)
            element = soup.select_one(rendered)
            if element is None:
                continue
            raw = element.get(sel.attribute)
            if not raw:
                continue
            link = raw[0] if isinstance(raw, list) else raw

            if link.startswith("magnet:"):
                return dataclasses.replace(t, magnet=t.magnet or link)
            return dataclasses.replace(t, download=t.download or link)

        log.warning("No download link found on details page for %s", t.name)
        return t
