#!/usr/bin/env bash

set -euo pipefail

PRODUCT_BASE_URL="https://software.3wcorner.com/pbx/tools/3wmp3"
PRODUCT_NAME="3wmp3"
SCRIPT_NAME="install.sh"
BOOTSTRAP_VERSION="0.1.0"
COPYRIGHT_YEAR="2026"

TARGET_DIR="/usr/local/sbin"
REQUESTED_RELEASE=""
USE_LATEST=0
PREPARE_SYSTEM_ONLY=0
ROLLBACK_LAST=0
REINSTALL_SAME_VERSION=0
ASSUME_YES=0
LIST_VERSIONS=0
HAS_JQ=0
WORK_DIR=""
header_printed=0

if [[ -t 1 ]]; then
    RESET=$'\033[0m'
    BRed=$'\033[1;31m'
    BGreen=$'\033[1;32m'
    BYellow=$'\033[1;33m'
    BBlue=$'\033[1;34m'
else
    RESET=""
    BRed=""
    BGreen=""
    BYellow=""
    BBlue=""
fi

usage() {
    cat <<EOF
Usage: ${SCRIPT_NAME} [--release VERSION] [--latest] [--prepare-system] [--rollback-last] [--reinstall] [--list-versions] [--target-dir PATH] [--yes] [--version]

Behavior:
  - default install path resolves the current recommended release online
  - \`--release VERSION\` installs a specific published release
  - \`--latest\` installs the newest published release
  - \`--prepare-system\` prepares dependencies only for the selected release
  - \`--rollback-last\` uses the current installer to restore the latest backup
  - \`--reinstall\` forces the selected release to be installed again even if the same version is already present
  - \`--list-versions\` prints published versions without installing anything
  - \`--yes\` auto-confirms supported prompts where safe
EOF
}

print_info() {
    printf '%sINFO%s %s\n' "${BBlue}" "${RESET}" "$1"
}

print_ok() {
    printf '%sOK%s %s\n' "${BGreen}" "${RESET}" "$1"
}

print_warn() {
    printf '%sWARN%s %s\n' "${BYellow}" "${RESET}" "$1"
}

print_error() {
    printf '%sERROR%s %s\n' "${BRed}" "${RESET}" "$1" >&2
}

fail() {
    print_error "$*"
    exit 1
}

cleanup() {
    if [[ -n "${WORK_DIR}" && -d "${WORK_DIR}" ]]; then
        rm -rf "${WORK_DIR}"
    fi
}

trap cleanup EXIT

print_header() {
    if [[ "${header_printed}" -eq 1 ]]; then
        return 0
    fi

    cat <<EOF
${BBlue}+------------------------------------------------------------------------------+${RESET}
${BBlue}|${RESET} ${PRODUCT_NAME} ${SCRIPT_NAME} ${BOOTSTRAP_VERSION}
${BBlue}|${RESET} Copyright (c) ${COPYRIGHT_YEAR} 3W Global Corp. All rights reserved.
${BBlue}|${RESET} ${BYellow}NOTICE:${RESET} This software is provided "as is", without warranties or
${BBlue}|${RESET} guarantees of any kind. Use it at your own risk. You are solely responsible
${BBlue}|${RESET} for backups, validation, and testing before production use. 3W Global Corp
${BBlue}|${RESET} shall not be liable for any loss, damage, data corruption, or service
${BBlue}|${RESET} interruption arising from its installation or use.
${BBlue}+------------------------------------------------------------------------------+${RESET}

EOF

    header_printed=1
}

print_version() {
    printf '%s %s\n' "${SCRIPT_NAME}" "${BOOTSTRAP_VERSION}"
}

check_bash_compatibility() {
    if [[ -z "${BASH_VERSION:-}" ]]; then
        fail "this installer must be run with bash"
    fi

    if [[ "${BASH_VERSINFO[0]-0}" -lt 3 ]]; then
        fail "this installer requires bash 3 or newer"
    fi
}

command_exists() {
    command -v "$1" >/dev/null 2>&1
}

prompt_yes_no() {
    local prompt="$1"
    local default_yes="${2:-0}"
    local reply=""

    if [[ "${ASSUME_YES}" -eq 1 && "${default_yes}" -eq 1 ]]; then
        return 0
    fi

    if [[ -r /dev/tty ]]; then
        printf '%s' "${prompt}" > /dev/tty
        IFS= read -r reply < /dev/tty || return 1
    elif [[ -t 0 ]]; then
        printf '%s' "${prompt}"
        IFS= read -r reply || return 1
    else
        return 1
    fi

    case "${reply}" in
        "")
            [[ "${default_yes}" -eq 1 ]]
            ;;
        y|Y|yes|YES)
            return 0
            ;;
        *)
            return 1
            ;;
    esac
}

confirm_terms() {
    if [[ "${THREEW_INSTALLER_ASSUME_TERMS:-0}" == "1" ]]; then
        return 0
    fi

    if [[ "${ASSUME_YES}" -eq 1 ]]; then
        print_info "Proceeding with non-interactive acceptance of the license notice and terms."
        return 0
    fi

    if prompt_yes_no "Proceed and confirm that you accept the license notice and terms above? [y/N] " 0; then
        print_ok "License notice and terms accepted."
        return 0
    fi

    print_warn "Cancelled. License notice and terms were not accepted."
    exit 1
}

detect_optional_tools() {
    if command_exists jq; then
        HAS_JQ=1
    fi
}

require_network_fetcher() {
    if command_exists curl || command_exists wget; then
        return 0
    fi

    fail "curl or wget is required to download release metadata"
}

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

    if command_exists curl; then
        curl -fsSL "${url}" -o "${destination}"
        return 0
    fi

    wget -qO "${destination}" "${url}"
}

fetch_url_text() {
    local url="$1"
    local destination=""

    destination="$(mktemp "${WORK_DIR}/fetch.XXXXXX")"
    fetch_url_to_file "${url}" "${destination}"
    cat "${destination}"
    rm -f "${destination}"
}

resolve_alias_version() {
    local alias_name="$1"
    local json_file=""
    local resolved_version=""
    local alias_json_url="${PRODUCT_BASE_URL%/}/${alias_name}.json"
    local alias_txt_url="${PRODUCT_BASE_URL%/}/${alias_name}.txt"

    if [[ "${HAS_JQ}" -eq 1 ]]; then
        json_file="$(mktemp "${WORK_DIR}/alias.XXXXXX.json")"
        if fetch_url_to_file "${alias_json_url}" "${json_file}" 2>/dev/null; then
            resolved_version="$(jq -r '.version // empty' "${json_file}" 2>/dev/null || true)"
        fi
        rm -f "${json_file}"
    fi

    if [[ -z "${resolved_version}" ]]; then
        resolved_version="$(fetch_url_text "${alias_txt_url}" | tr -d '[:space:]')"
    fi

    [[ -n "${resolved_version}" ]] || fail "failed to resolve ${alias_name} release version"
    printf '%s\n' "${resolved_version}"
}

print_versions() {
    local versions_text_url="${PRODUCT_BASE_URL%/}/versions.txt"
    local catalog_json_url="${PRODUCT_BASE_URL%/}/catalog.json"
    local catalog_file=""

    if [[ "${HAS_JQ}" -eq 1 ]]; then
        catalog_file="$(mktemp "${WORK_DIR}/catalog.XXXXXX.json")"
        if fetch_url_to_file "${catalog_json_url}" "${catalog_file}" 2>/dev/null; then
            jq -r '.versions[].version' "${catalog_file}"
            rm -f "${catalog_file}"
            return 0
        fi
        rm -f "${catalog_file}"
    fi

    fetch_url_text "${versions_text_url}"
}

release_exists() {
    local requested_version="$1"
    local listed_version=""

    while IFS= read -r listed_version; do
        [[ -n "${listed_version}" ]] || continue
        if [[ "${listed_version}" == "${requested_version}" ]]; then
            return 0
        fi
    done < <(print_versions)

    return 1
}

is_version_newer() {
    local candidate="$1"
    local baseline="$2"

    if ! command_exists sort; then
        return 1
    fi

    [[ "$(printf '%s\n%s\n' "${baseline}" "${candidate}" | sort -V | tail -n 1)" == "${candidate}" && "${candidate}" != "${baseline}" ]]
}

manifest_string_value() {
    local manifest_file="$1"
    local key="$2"
    local value=""

    if [[ "${HAS_JQ}" -eq 1 ]]; then
        value="$(jq -r ".install.${key} // empty" "${manifest_file}" 2>/dev/null || true)"
    fi

    if [[ -z "${value}" ]]; then
        value="$(sed -n "s/.*\"${key}\"[[:space:]]*:[[:space:]]*\"\\([^\"]*\\)\".*/\\1/p" "${manifest_file}" | head -n 1)"
    fi

    [[ -n "${value}" ]] || fail "failed to read '${key}' from manifest"
    printf '%s\n' "${value}"
}

manifest_boolean_value() {
    local manifest_file="$1"
    local key="$2"
    local value=""

    if [[ "${HAS_JQ}" -eq 1 ]]; then
        value="$(jq -r ".install.${key} // empty" "${manifest_file}" 2>/dev/null || true)"
    fi

    if [[ -z "${value}" ]]; then
        value="$(sed -n "s/.*\"${key}\"[[:space:]]*:[[:space:]]*\\(true\\|false\\).*/\\1/p" "${manifest_file}" | head -n 1)"
    fi

    case "${value}" in
        true|false)
            printf '%s\n' "${value}"
            ;;
        *)
            fail "failed to read boolean '${key}' from manifest"
            ;;
    esac
}

select_target_version() {
    local current_version=""
    local target_version=""

    current_version="$(resolve_alias_version "current")"

    if [[ "${ROLLBACK_LAST}" -eq 1 ]]; then
        if [[ -n "${REQUESTED_RELEASE}" || "${USE_LATEST}" -eq 1 ]]; then
            print_warn "Rollback uses the current recommended installer path. Explicit release selection is ignored."
        fi
        printf '%s\n' "${current_version}"
        return 0
    fi

    if [[ -n "${REQUESTED_RELEASE}" ]]; then
        release_exists "${REQUESTED_RELEASE}" || fail "requested release ${REQUESTED_RELEASE} is not published"
        target_version="${REQUESTED_RELEASE}"

        if is_version_newer "${current_version}" "${target_version}"; then
            print_warn "Requested release: ${target_version}"
            print_warn "Current recommended release: ${current_version}"
            if [[ "${ASSUME_YES}" -ne 1 ]] && prompt_yes_no "Install current recommended release ${current_version} instead? [y/N] " 0; then
                target_version="${current_version}"
            else
                print_info "Continuing with pinned release ${target_version}."
            fi
        fi

        printf '%s\n' "${target_version}"
        return 0
    fi

    if [[ "${USE_LATEST}" -eq 1 ]]; then
        printf '%s\n' "$(resolve_alias_version "latest")"
        return 0
    fi

    printf '%s\n' "${current_version}"
}

run_release_installer() {
    local target_version="$1"
    local manifest_file="${WORK_DIR}/manifest.json"
    local runtime_name=""
    local runtime_path=""
    local installer_name=""
    local installer_path=""
    local supports_yes=""
    local supports_rollback=""
    local installer_url=""
    local runtime_url=""
    local installer_file=""
    local runtime_file=""
    local -a installer_args=()

    fetch_url_to_file "${PRODUCT_BASE_URL%/}/versions/${target_version}/manifest.json" "${manifest_file}"

    runtime_name="$(manifest_string_value "${manifest_file}" "runtime_name")"
    runtime_path="$(manifest_string_value "${manifest_file}" "runtime_path")"
    installer_name="$(manifest_string_value "${manifest_file}" "installer_name")"
    installer_path="$(manifest_string_value "${manifest_file}" "installer_path")"
    supports_yes="$(manifest_boolean_value "${manifest_file}" "installer_supports_yes")"
    supports_rollback="$(manifest_boolean_value "${manifest_file}" "installer_supports_rollback")"

    installer_url="${PRODUCT_BASE_URL%/}/versions/${target_version}/${installer_path}"
    runtime_url="${PRODUCT_BASE_URL%/}/versions/${target_version}/${runtime_path}"
    installer_file="${WORK_DIR}/${installer_name}"
    runtime_file="${WORK_DIR}/${runtime_name}"

    fetch_url_to_file "${installer_url}" "${installer_file}"
    chmod 0755 "${installer_file}"

    if [[ "${ROLLBACK_LAST}" -eq 1 ]]; then
        if [[ "${supports_rollback}" != "true" ]]; then
            fail "release ${target_version} does not support rollback through the bootstrap installer"
        fi
        installer_args+=("--rollback-last")
    else
        if [[ "${PREPARE_SYSTEM_ONLY}" -ne 1 ]]; then
            fetch_url_to_file "${runtime_url}" "${runtime_file}"
            chmod 0755 "${runtime_file}"
        fi

        if [[ "${PREPARE_SYSTEM_ONLY}" -eq 1 ]]; then
            installer_args+=("--prepare-system")
        fi

        if [[ "${REINSTALL_SAME_VERSION}" -eq 1 ]]; then
            installer_args+=("--reinstall")
        fi
    fi

    installer_args+=("--target-dir" "${TARGET_DIR}")

    if [[ "${ASSUME_YES}" -eq 1 && "${supports_yes}" == "true" ]]; then
        installer_args+=("--yes")
    fi

    print_info "Selected release: ${target_version}"
    print_info "Using ${installer_name} for ${PRODUCT_BASE_URL%/}/versions/${target_version}/"
    THREEW_INSTALLER_SUPPRESS_HEADER=1 THREEW_INSTALLER_ASSUME_TERMS=1 "${installer_file}" "${installer_args[@]}"
}

check_bash_compatibility
detect_optional_tools
require_network_fetcher
WORK_DIR="$(mktemp -d)"

while [[ $# -gt 0 ]]; do
    case "$1" in
        --release)
            [[ $# -ge 2 ]] || fail "--release requires a value"
            REQUESTED_RELEASE="$2"
            shift 2
            ;;
        --latest)
            USE_LATEST=1
            shift
            ;;
        --prepare-system)
            PREPARE_SYSTEM_ONLY=1
            shift
            ;;
        --rollback-last)
            ROLLBACK_LAST=1
            shift
            ;;
        --reinstall|--force-install|--clean-install)
            REINSTALL_SAME_VERSION=1
            shift
            ;;
        --list-versions)
            LIST_VERSIONS=1
            shift
            ;;
        --target-dir)
            [[ $# -ge 2 ]] || fail "--target-dir requires a value"
            TARGET_DIR="$2"
            shift 2
            ;;
        --yes)
            ASSUME_YES=1
            shift
            ;;
        --version)
            print_version
            exit 0
            ;;
        -h|--help)
            usage
            exit 0
            ;;
        *)
            fail "unexpected argument: $1"
            ;;
    esac
done

print_header

if [[ "${HAS_JQ}" -eq 1 ]]; then
    print_ok "jq detected. JSON endpoints will be used when available."
else
    print_warn "jq not detected. Falling back to text aliases and compatibility manifest parsing."
fi

if [[ "${LIST_VERSIONS}" -eq 1 ]]; then
    print_versions
    exit 0
fi

confirm_terms

TARGET_VERSION="$(select_target_version)"
run_release_installer "${TARGET_VERSION}"
