"""Baixa e gerencia o binário do gitleaks para a plataforma atual.

O gitleaks é distribuído como binário standalone por release no GitHub,
então cada SO/arquitetura tem um asset diferente. Baixamos uma vez e
guardamos em abyss_home() pra não repetir o download a cada scan.
"""

import stat
import tarfile
import zipfile
from pathlib import Path

import requests

from abyss.utils.platform import binary_name, get_arch, get_os, abyss_home

GITLEAKS_VERSION = "8.18.4"
GITLEAKS_REPO = "gitleaks/gitleaks"


def _asset_name() -> str:
    """Monta o nome do asset de release do gitleaks pra plataforma atual."""
    os_name = get_os()
    arch = get_arch()

    os_map = {"windows": "windows", "darwin": "darwin", "linux": "linux"}
    arch_map = {"x64": "x64", "arm64": "arm64", "x32": "x32"}

    ext = "zip" if os_name == "windows" else "tar.gz"
    return f"gitleaks_{GITLEAKS_VERSION}_{os_map[os_name]}_{arch_map.get(arch, 'x64')}.{ext}"


def gitleaks_path() -> Path:
    return abyss_home() / binary_name("gitleaks")


def is_installed() -> bool:
    return gitleaks_path().exists()


def install(progress_callback=None) -> Path:
    """Baixa e extrai o binário do gitleaks se ainda não estiver instalado."""
    target = gitleaks_path()
    if target.exists():
        return target

    asset = _asset_name()
    url = f"https://github.com/{GITLEAKS_REPO}/releases/download/v{GITLEAKS_VERSION}/{asset}"

    download_dir = abyss_home() / "downloads"
    download_dir.mkdir(exist_ok=True)
    archive_path = download_dir / asset

    if progress_callback:
        progress_callback(f"Baixando gitleaks v{GITLEAKS_VERSION} para {get_os()}/{get_arch()}...")

    response = requests.get(url, stream=True, timeout=60)
    response.raise_for_status()

    with open(archive_path, "wb") as f:
        for chunk in response.iter_content(chunk_size=8192):
            f.write(chunk)

    if progress_callback:
        progress_callback("Extraindo binário...")

    if asset.endswith(".zip"):
        with zipfile.ZipFile(archive_path, "r") as zf:
            zf.extractall(download_dir)
    else:
        with tarfile.open(archive_path, "r:gz") as tf:
            tf.extractall(download_dir)

    extracted_binary = download_dir / binary_name("gitleaks")
    extracted_binary.replace(target)

    if get_os() != "windows":
        target.chmod(target.stat().st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)

    archive_path.unlink(missing_ok=True)

    return target