#
# Erminig - Récupération de la dernière version d'un soft sur Github via son API
# Copyright (C) 2025 L0m1g
# Sous licence DOUARN - Voir le fichier LICENCE pour les détails
#
# Ce fichier fait partie du projet Erminig.
# Libre comme l’air, stable comme un menhir, et salé comme le beurre.
#

import re
import requests
from erminig.config import Config
from erminig.controllers.evezh.abstract import UpstreamSource
from erminig.system.retry import retry_on_failure


class GitHubSource(UpstreamSource):

    @retry_on_failure()
    def get_latest(self):
        repo = self.config["github"]
        file_template = self.config.get("file")

        latest = self._get_latest_release(repo)
        if not latest:
            latest = self._get_latest_tag(repo)
        if not latest:
            print(f"[{self.name}] Aucune version détectée.")
            return None

        version = self.normalize_version(latest["tag"])
        url = latest.get("url")

        if not url and file_template:
            filename = file_template.replace("${version}", version)
            url = f"https://github.com/{repo}/releases/download/{latest['tag']}/{filename}"
            print(f"[{self.name}] Fallback URL : {url}")

        print(url)
        return {"name": self.name, "version": version, "url": url or ""}

    def _github_headers(self):
        headers = {}
        if Config.GITHUB_TOKEN:
            headers["Authorization"] = f"token {Config.GITHUB_TOKEN}"
        return headers

    def _get_latest_release(self, repo):
        r = requests.get(
            f"https://api.github.com/repos/{repo}/releases",
            headers=self._github_headers(),
        )
        r.raise_for_status()
        data = r.json()
        if not data:
            return None

        release = data[0]
        for asset in release.get("assets", []):
            if asset["browser_download_url"].endswith(".tar.gz"):
                return {
                    "tag": release["tag_name"],
                    "url": asset["browser_download_url"],
                }
        return {"tag": release["tag_name"]}

    def _get_latest_tag(self, repo):
        r = requests.get(
            f"https://api.github.com/repos/{repo}/tags", headers=self._github_headers()
        )
        r.raise_for_status()
        tags = r.json()
        if not tags:
            return None
        url = f"https://github.com/{repo}/archive/refs/tags/{tags[0]["name"]}.tar.gz"
        return {"tag": tags[0]["name"], "url": url}

    def normalize_version(self, tag):
        # Exemples : v2.7.1 → 2.7.1, R_2_7_1 → 2.7.1, expat-2.7.1 → 2.7.1
        tag = tag.strip()
        if tag.lower().startswith(("v", "r_", "r")):
            tag = re.sub(r"^[vVrR_]+", "", tag)
        tag = tag.replace("_", ".")
        match = re.search(r"(\d+\.\d+(?:\.\d+)?)", tag)
        return match.group(1) if match else tag
