#!/usr/bin/env bash

set -Eeuo pipefail

REPO_BASE_URL='https://distro.advance2000.com'
BOOTSTRAP_CA_URL='http://distro.advance2000.com/advance2000.com.crt'

APT_KEY_URL="${REPO_BASE_URL}/keys/archive-keyring.gpg"
RPM_KEY_URL="${REPO_BASE_URL}/keys/RPM-GPG-KEY"
APT_REPO_URL="${REPO_BASE_URL}/apt"
RPM_REPO_URL="${REPO_BASE_URL}/rpm"

REPO_DISPLAY_NAME='Advance2000'
REPO_ID='advance2000'

APT_KEYRING="/usr/share/keyrings/${REPO_ID}-archive-keyring.gpg"
APT_SOURCE_FILE="/etc/apt/sources.list.d/${REPO_ID}.list"
RPM_REPO_FILE="/etc/yum.repos.d/${REPO_ID}.repo"
CA_NAME="${REPO_ID}-root-ca.crt"

log() {
    printf '[%s-init] %s\n' "${REPO_ID}" "$*"
}

die() {
    log "ERROR: $*"
    exit 1
}

on_error() {
    local exit_code=$?
    local line_number="${1:-unknown}"

    log "ERROR: bootstrap failed at line ${line_number}, exit code ${exit_code}"
    exit "${exit_code}"
}

trap 'on_error "${LINENO}"' ERR

require_root() {
    [[ "${EUID}" -eq 0 ]] ||
        die "Run this script as root or through sudo"
}

download() {
    local url="$1"
    local destination="$2"

    log "Downloading ${url}"

    if command -v curl >/dev/null 2>&1; then
        curl --fail --silent --show-error --location             --output "${destination}" "${url}"
    elif command -v wget >/dev/null 2>&1; then
        wget --quiet --output-document="${destination}" "${url}"
    else
        die "Neither curl nor wget is installed"
    fi

    [[ -s "${destination}" ]] ||
        die "Downloaded file is empty: ${url}"
}

load_os_release() {
    [[ -r /etc/os-release ]] ||
        die "/etc/os-release is unavailable"

    # shellcheck source=/dev/null
    source /etc/os-release

    OS_ID="${ID:-unknown}"
    OS_ID_LIKE="${ID_LIKE:-}"
    OS_VERSION_ID="${VERSION_ID:-}"
    OS_CODENAME="${VERSION_CODENAME:-}"
    OS_MAJOR="${OS_VERSION_ID%%.*}"

    case "${OS_ID}" in
        ubuntu)
            case "${OS_VERSION_ID}" in
                20.04) OS_CODENAME="focal" ;;
                22.04) OS_CODENAME="jammy" ;;
                24.04) OS_CODENAME="noble" ;;
                26.04) OS_CODENAME="resolute" ;;
            esac
            ;;
        debian)
            if [[ -z "${OS_CODENAME}" && "${OS_MAJOR}" == "13" ]]; then
                OS_CODENAME="trixie"
            fi
            ;;
    esac
}

detect_family() {
    case "${OS_ID}" in
        ubuntu|debian)
            OS_FAMILY="apt"
            ;;
        rhel|rocky|almalinux|centos|ol)
            OS_FAMILY="rpm"
            ;;
        *)
            if [[ " ${OS_ID_LIKE} " == *" debian "* ]]; then
                OS_FAMILY="apt"
            elif [[ " ${OS_ID_LIKE} " == *" rhel "* ||
                    " ${OS_ID_LIKE} " == *" fedora "* ]]; then
                OS_FAMILY="rpm"
            else
                die "Unsupported operating system: ${OS_ID}"
            fi
            ;;
    esac
}

normalize_architecture() {
    case "$(uname -m)" in
        x86_64|amd64)
            RPM_ARCH="x86_64"
            APT_ARCH="amd64"
            ;;
        aarch64|arm64)
            RPM_ARCH="aarch64"
            APT_ARCH="arm64"
            ;;
        *)
            die "Unsupported architecture: $(uname -m)"
            ;;
    esac
}

install_ca_debian() {
    local destination="/usr/local/share/ca-certificates/${CA_NAME}"

    command -v update-ca-certificates >/dev/null 2>&1 ||
        die "update-ca-certificates is unavailable"

    install -d -m 0755 /usr/local/share/ca-certificates
    download "${BOOTSTRAP_CA_URL}" "${destination}"
    chmod 0644 "${destination}"

    log "Updating Debian/Ubuntu CA trust"
    update-ca-certificates
}

install_ca_rpm() {
    local destination="/etc/pki/ca-trust/source/anchors/${CA_NAME}"

    command -v update-ca-trust >/dev/null 2>&1 ||
        die "update-ca-trust is unavailable"

    install -d -m 0755 /etc/pki/ca-trust/source/anchors
    download "${BOOTSTRAP_CA_URL}" "${destination}"
    chmod 0644 "${destination}"

    log "Updating RPM-family CA trust"
    update-ca-trust extract
}

configure_apt() {
    local temporary_key
    local source_line

    [[ -n "${OS_CODENAME}" ]] ||
        die "Unable to determine the APT distribution codename"

    case "${OS_CODENAME}" in
        focal|jammy|noble|resolute|trixie)
            ;;
        *)
            die "No ${REPO_DISPLAY_NAME} APT repository is configured for ${OS_CODENAME}"
            ;;
    esac

    command -v apt-get >/dev/null 2>&1 ||
        die "apt-get is unavailable"

    command -v gpg >/dev/null 2>&1 ||
        die "gpg is unavailable"

    temporary_key="$(mktemp)"
    trap 'rm -f "${temporary_key:-}"' RETURN

    download "${APT_KEY_URL}" "${temporary_key}"
    install -d -m 0755 "$(dirname "${APT_KEYRING}")"

    if ! gpg --batch --show-keys "${temporary_key}" >/dev/null 2>&1; then
        die "Downloaded APT signing key is invalid"
    fi

    if grep -q -- 'BEGIN PGP PUBLIC KEY BLOCK' "${temporary_key}"; then
        gpg --batch --yes --dearmor             --output "${APT_KEYRING}" "${temporary_key}"
    else
        install -m 0644 "${temporary_key}" "${APT_KEYRING}"
    fi

    chmod 0644 "${APT_KEYRING}"

    source_line="deb [arch=${APT_ARCH} signed-by=${APT_KEYRING}] ${APT_REPO_URL} ${OS_CODENAME} main"

    log "Writing ${APT_SOURCE_FILE}"
    printf '%s\n' "${source_line}" >"${APT_SOURCE_FILE}"
    chmod 0644 "${APT_SOURCE_FILE}"

    log "Refreshing APT metadata"
    apt-get update
}

configure_rpm() {
    local temporary_key

    [[ "${OS_MAJOR}" =~ ^[0-9]+$ ]] ||
        die "Unable to determine the RPM operating-system major version"

    case "${OS_MAJOR}" in
        9|10)
            ;;
        *)
            die "No ${REPO_DISPLAY_NAME} RPM repository is configured for major version ${OS_MAJOR}"
            ;;
    esac

    command -v rpm >/dev/null 2>&1 ||
        die "rpm is unavailable"

    temporary_key="$(mktemp)"
    trap 'rm -f "${temporary_key:-}"' RETURN

    download "${RPM_KEY_URL}" "${temporary_key}"
    rpm --import "${temporary_key}"

    log "Writing ${RPM_REPO_FILE}"

    cat >"${RPM_REPO_FILE}" <<REPOEOF
[${REPO_ID}]
name=${REPO_DISPLAY_NAME} Packages - EL ${OS_MAJOR} - ${RPM_ARCH}
baseurl=${RPM_REPO_URL}/rhel/${OS_MAJOR}/${RPM_ARCH}
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=${RPM_KEY_URL}
metadata_expire=1h
REPOEOF

    chmod 0644 "${RPM_REPO_FILE}"

    if command -v dnf >/dev/null 2>&1; then
        log "Refreshing DNF metadata"
        dnf -q clean metadata
        dnf -q makecache --refresh
    elif command -v yum >/dev/null 2>&1; then
        log "Refreshing YUM metadata"
        yum -q clean metadata
        yum -q makecache
    else
        die "Neither dnf nor yum is installed"
    fi
}

main() {
    require_root
    load_os_release
    detect_family
    normalize_architecture

    log "Detected ${OS_ID} ${OS_VERSION_ID:-unknown}"

    case "${OS_FAMILY}" in
        apt)
            install_ca_debian
            configure_apt
            ;;
        rpm)
            install_ca_rpm
            configure_rpm
            ;;
    esac

    log "${REPO_DISPLAY_NAME} trust and repositories are configured"
}

main "$@"
