#!/usr/bin/env bash
# AFFiNE Canary ebuild updater for nbdy_overlay
#
# Version detection strategy:
#   GitHub releases API → latest canary pre-release (tag vYYYY.M.D-canary.BUILD)
#   Portage version: YYYY.M.D.BUILD (flattened for PMS compatibility)
#   SRC_URI: https://github.com/toeverything/AFFiNE/releases/download/v${CANARY_VER}/affine-${CANARY_VER}-canary-linux-x64.appimage

set -euo pipefail

# Cleanup on failure: remove any newly created ebuild
CLEANUP_FILES=()
cleanup_on_exit() {
    local exit_code=$?
    if (( exit_code != 0 )) && (( ${#CLEANUP_FILES[@]} > 0 )); then
        for f in "${CLEANUP_FILES[@]}"; do
            [[ -f "$f" ]] && rm -v "$f"
        done
    fi
}
trap cleanup_on_exit EXIT

OVERLAY_DIR="$(dirname "$(dirname "$(realpath "$0")")")"
EBUILD_DIR="${OVERLAY_DIR}/app-office/affine-canary-bin"
PKG_NAME="affine-canary-bin"
GITHUB_REPO="toeverything/AFFiNE"

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

log_info()    { echo -e "${BLUE}[INFO]${NC} $1" >&2; }
log_success() { echo -e "${GREEN}[OK]${NC} $1" >&2; }
log_warn()    { echo -e "${YELLOW}[WARN]${NC} $1" >&2; }
log_error()   { echo -e "${RED}[ERROR]${NC} $1" >&2; }

get_current_version() {
    local ebuild
    ebuild=$(ls "${EBUILD_DIR}"/*.ebuild 2>/dev/null | sort -V | tail -1)
    if [[ -z "$ebuild" ]]; then
        echo ""
        return
    fi
    basename "$ebuild" .ebuild | sed "s/${PKG_NAME}-//"
}

# Convert upstream canary tag to Portage PV
# v2026.3.20-canary.913 → 2026.3.20.913
canary_tag_to_pv() {
    local tag="$1"
    tag="${tag#v}"                     # strip leading v
    echo "$tag" | sed 's/-canary\././' # 2026.3.20-canary.913 → 2026.3.20.913
}

# Convert Portage PV back to upstream canary version string
# 2026.3.20.913 → 2026.3.20-canary.913
pv_to_canary_ver() {
    local pv="$1"
    local base="${pv%.*}"    # 2026.3.20
    local build="${pv##*.}"  # 913
    echo "${base}-canary.${build}"
}

get_latest_version() {
    log_info "Fetching latest canary release from GitHub..."

    local curl_opts=(-sfL --max-time 30)
    [[ -n "${GITHUB_TOKEN:-}" ]] && curl_opts+=(-H "Authorization: Bearer ${GITHUB_TOKEN}")

    local json
    json=$(curl "${curl_opts[@]}" \
        "https://api.github.com/repos/${GITHUB_REPO}/releases?per_page=30" 2>/dev/null) || {
        log_error "Failed to fetch releases from GitHub"
        return 1
    }

    # Find the latest canary release tag
    local canary_tags
    canary_tags=$(echo "$json" | grep -oP '"tag_name"\s*:\s*"\Kv[0-9]+\.[0-9]+\.[0-9]+-canary\.[0-9]+' | head -10)

    if [[ -z "$canary_tags" ]]; then
        log_error "No canary releases found"
        return 1
    fi

    # Check each canary tag for AppImage availability
    local tag
    while IFS= read -r tag; do
        [[ -z "$tag" ]] && continue
        local ver="${tag#v}"
        local asset_url="https://github.com/${GITHUB_REPO}/releases/download/${tag}/affine-${ver}-canary-linux-x64.appimage"
        local http_code
        http_code=$(curl -sfIL -o /dev/null -w '%{http_code}' "$asset_url" 2>/dev/null)

        if [[ "$http_code" == "200" || "$http_code" == "302" ]]; then
            local pv
            pv=$(canary_tag_to_pv "$tag")
            log_success "Latest canary: ${ver} (PV=${pv}, AppImage verified)"
            echo "$pv"
            return 0
        fi
        log_info "  ${tag}: no AppImage (HTTP ${http_code})"
    done <<< "$canary_tags"

    log_error "No canary release with AppImage found"
    return 1
}

create_ebuild() {
    local new_version="$1"
    local old_ebuild new_ebuild

    old_ebuild=$(ls "${EBUILD_DIR}"/*.ebuild 2>/dev/null | sort -V | tail -1)
    new_ebuild="${EBUILD_DIR}/${PKG_NAME}-${new_version}.ebuild"

    if [[ -z "$old_ebuild" ]]; then
        log_error "No existing ebuild found to copy"
        return 1
    fi

    if [[ -f "$new_ebuild" ]]; then
        log_warn "Ebuild already exists: $new_ebuild"
        return 0
    fi

    cp "$old_ebuild" "$new_ebuild"
    CLEANUP_FILES+=("$new_ebuild")
    log_success "Created: ${PKG_NAME}-${new_version}.ebuild"
}

generate_manifest() {
    log_info "Generating Manifest..."

    local ebuild
    ebuild=$(ls "${EBUILD_DIR}"/*.ebuild 2>/dev/null | sort -V | tail -1)

    if [[ -z "$ebuild" ]]; then
        log_error "No ebuild found"
        return 1
    fi

    local pv canary_ver distfile src_url
    pv=$(basename "$ebuild" .ebuild | sed "s/${PKG_NAME}-//")
    canary_ver=$(pv_to_canary_ver "$pv")
    distfile="affine-${canary_ver}-canary-linux-x64.appimage"
    src_url="https://github.com/${GITHUB_REPO}/releases/download/v${canary_ver}/${distfile}"

    log_info "Downloading ${distfile} for checksum (~180 MB)..."
    local tmpfile
    tmpfile=$(mktemp)

    if ! curl -sfL -o "$tmpfile" "$src_url"; then
        log_error "Failed to download ${src_url}"
        rm -f "$tmpfile"
        return 1
    fi

    local filesize blake2b sha512
    filesize=$(wc -c < "$tmpfile")
    blake2b=$(b2sum "$tmpfile" | awk '{print $1}')
    sha512=$(sha512sum "$tmpfile" | awk '{print $1}')
    rm -f "$tmpfile"

    echo "DIST ${distfile} ${filesize} BLAKE2B ${blake2b} SHA512 ${sha512}" > "${EBUILD_DIR}/Manifest"
    log_success "Manifest generated for ${distfile} (${filesize} bytes)"
}

cleanup_old_versions() {
    local keep="${1:-1}"
    local ebuilds

    mapfile -t ebuilds < <(ls "${EBUILD_DIR}"/*.ebuild 2>/dev/null | sort -V)
    local count=${#ebuilds[@]}

    if (( count <= keep )); then
        log_info "No cleanup needed (${count} versions, keeping ${keep})"
        return
    fi

    local to_remove=$((count - keep))
    log_info "Removing ${to_remove} old version(s)..."

    for ((i = 0; i < to_remove; i++)); do
        rm -v "${ebuilds[$i]}"
    done

    log_success "Cleanup complete"
}

git_commit() {
    local version="$1"
    local canary_ver
    canary_ver=$(pv_to_canary_ver "$version")

    cd "${OVERLAY_DIR}"
    git add "${EBUILD_DIR}/"

    if git diff --cached --quiet; then
        log_info "No changes to commit"
        return 0
    fi

    local msg="app-office/affine-canary-bin: bump to ${canary_ver}"
    git commit -m "$msg"
    log_success "Committed: $msg"
}

main() {
    local dry_run=false
    local force=false
    local no_commit=false
    local keep_versions=1

    while [[ $# -gt 0 ]]; do
        case $1 in
            -n|--dry-run)  dry_run=true;        shift ;;
            -f|--force)    force=true;           shift ;;
            --no-commit)   no_commit=true;       shift ;;
            --keep)        keep_versions="$2";   shift 2 ;;
            -h|--help)
                echo "Usage: $0 [OPTIONS]"
                echo "  -n, --dry-run    Preview changes without writing anything"
                echo "  -f, --force      Force update even if version appears current"
                echo "  --no-commit      Skip git commit step"
                echo "  --keep N         Keep N ebuild versions (default: 1)"
                exit 0
                ;;
            *) log_error "Unknown option: $1"; exit 1 ;;
        esac
    done

    echo "============================================"
    echo "  AFFiNE Canary Ebuild Updater"
    echo "============================================"
    echo ""

    local current_version latest_version
    current_version=$(get_current_version)
    latest_version=$(get_latest_version) || exit 1

    echo ""
    echo "Current: ${current_version:-<none>}"
    echo "Latest:  ${latest_version}"
    echo ""

    if [[ "$current_version" == "$latest_version" ]] && [[ "$force" != "true" ]]; then
        log_success "Already up to date!"
        exit 0
    fi

    if [[ "$dry_run" == "true" ]]; then
        log_info "[DRY-RUN] Would update to ${latest_version}"
        exit 0
    fi

    create_ebuild "$latest_version"
    generate_manifest
    cleanup_old_versions "$keep_versions"

    if [[ "$no_commit" != "true" ]]; then
        git_commit "$latest_version"
    fi

    log_success "Update complete: ${latest_version}"
}

main "$@"
