"""Gitea release provider implementation."""

import json
import logging
import re
import urllib.error
import urllib.request
from typing import Optional

from .release_provider import ReleaseInfo, ReleaseProvider

logger = logging.getLogger(__name__)

# Default repository coordinates
_DEFAULT_BASE_URL = "https://git.dolgolyov-family.by"
_DEFAULT_OWNER = "alexei.dolgolyov"
_DEFAULT_REPO = "media-player-server"

# Restrictive tag whitelist — prevents a hostile Gitea response (or MITM) from
# injecting `..`, slashes, or URL-altering characters into the release URL we
# broadcast to clients. SemVer + pre-release suffix only.
_TAG_RE = re.compile(r"^v?\d+\.\d+\.\d+(?:[\w.\-+]{0,32})?$")


class GiteaReleaseProvider(ReleaseProvider):
    """Fetches the latest release from a Gitea repository."""

    def __init__(
        self,
        base_url: str = _DEFAULT_BASE_URL,
        owner: str = _DEFAULT_OWNER,
        repo: str = _DEFAULT_REPO,
        timeout: float = 10.0,
    ) -> None:
        self._api_url = f"{base_url}/api/v1/repos/{owner}/{repo}/releases"
        self._release_page_url = f"{base_url}/{owner}/{repo}/releases/tag"
        self._timeout = timeout

    async def get_latest_release(self) -> Optional[ReleaseInfo]:
        """Fetch the latest stable release from Gitea API.

        Returns:
            ReleaseInfo for the latest non-prerelease, or None on failure.
        """
        import asyncio

        try:
            data = await asyncio.to_thread(self._fetch_releases)
        except Exception as e:
            logger.warning("Failed to check for updates: %s", e)
            return None

        if not data:
            return None

        # Find the first non-prerelease, non-draft release
        for release in data:
            if release.get("draft") or release.get("prerelease"):
                continue

            tag = release.get("tag_name", "")
            if not isinstance(tag, str) or not _TAG_RE.match(tag):
                logger.warning("Rejecting malformed release tag from upstream: %r", tag)
                continue
            version = tag.lstrip("v")
            if not version:
                continue

            return ReleaseInfo(
                version=version,
                url=f"{self._release_page_url}/{tag}",
                prerelease=False,
            )

        logger.debug("No stable releases found")
        return None

    def _fetch_releases(self) -> list[dict]:
        """Synchronous HTTP fetch of releases (run in thread)."""
        url = f"{self._api_url}?limit=5"
        req = urllib.request.Request(url, headers={"Accept": "application/json"})
        try:
            with urllib.request.urlopen(req, timeout=self._timeout) as resp:
                return json.loads(resp.read().decode())
        except (urllib.error.URLError, urllib.error.HTTPError, json.JSONDecodeError, OSError) as e:
            raise RuntimeError(f"Gitea API request failed: {e}") from e
