#!/usr/bin/env bash
set -euo pipefail

REPO_OWNER="xooooooooox"
REPO_NAME="radp-bash-framework"
tmp_dir=""

# Defaults (overridable by CLI args, then env vars)
OPT_MODE="${RADP_BF_INSTALL_MODE:-auto}"
OPT_REF="${RADP_BF_REF:-}"
OPT_VERSION="${RADP_BF_VERSION:-}"
OPT_INSTALL_DIR="${RADP_BF_INSTALL_DIR:-}"
OPT_BIN_DIR="${RADP_BF_BIN_DIR:-}"

# ============================================================================
# Logging
# ============================================================================

log() {
  printf "%s\n" "$*"
}

err() {
  printf "radp-bash-framework install: %s\n" "$*" >&2
}

die() {
  err "$@"
  exit 1
}

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

# ============================================================================
# Usage
# ============================================================================

usage() {
  cat <<'EOF'
radp-bash-framework installer

Usage:
  install.sh [OPTIONS]
  curl -fsSL .../install.sh | bash -s -- [OPTIONS]

Options:
  --ref <ref>           Install from a git ref (branch, tag, or SHA).
                        Implies manual installation. If a package-manager
                        version is already installed, it is removed first.
  --mode <mode>         Installation mode (default: auto)
                        auto     - use package manager if available, else manual
                        manual   - always download from GitHub
                        homebrew - force Homebrew
                        dnf      - force dnf
                        yum      - force yum
                        apt      - force apt
                        zypper   - force zypper
  --install-dir <dir>   Manual install location
                        (default: $HOME/.local/lib/radp-bash-framework)
  --bin-dir <dir>       Symlink location (default: $HOME/.local/bin)
  -h, --help            Show this help

Environment variables:
  RADP_BF_REF              Same as --ref
  RADP_BF_VERSION          Pin to a release version (e.g. v1.0.0)
  RADP_BF_INSTALL_MODE     Same as --mode
  RADP_BF_INSTALL_DIR      Same as --install-dir
  RADP_BF_BIN_DIR          Same as --bin-dir

Examples:
  # Default: auto-detect package manager
  bash install.sh

  # Install latest from main branch (removes pkm version if present)
  bash install.sh --ref main

  # Install a specific tag via manual download
  bash install.sh --ref v1.0.0-rc1

  # Force manual mode (latest release)
  bash install.sh --mode manual
EOF
}

# ============================================================================
# Argument Parsing
# ============================================================================

parse_args() {
  while [[ $# -gt 0 ]]; do
    case "$1" in
    --ref)
      [[ $# -lt 2 ]] && die "--ref requires a value"
      OPT_REF="$2"
      shift 2
      ;;
    --mode)
      [[ $# -lt 2 ]] && die "--mode requires a value"
      OPT_MODE="$2"
      shift 2
      ;;
    --install-dir)
      [[ $# -lt 2 ]] && die "--install-dir requires a value"
      OPT_INSTALL_DIR="$2"
      shift 2
      ;;
    --bin-dir)
      [[ $# -lt 2 ]] && die "--bin-dir requires a value"
      OPT_BIN_DIR="$2"
      shift 2
      ;;
    -h | --help)
      usage
      exit 0
      ;;
    *)
      die "Unknown option: $1 (use --help for usage)"
      ;;
    esac
  done
}

# ============================================================================
# Package Manager Detection and Installation
# ============================================================================

detect_os() {
  local os=""
  if [[ "${OSTYPE:-}" == darwin* ]]; then
    os="macos"
  elif [[ -f /etc/os-release ]]; then
    # shellcheck disable=SC1091
    source /etc/os-release
    case "${ID:-}" in
    fedora | centos | rhel | rocky | almalinux | ol)
      os="rhel"
      ;;
    debian | ubuntu | linuxmint | pop)
      os="debian"
      ;;
    opensuse* | sles)
      os="suse"
      ;;
    *)
      os="linux"
      ;;
    esac
  else
    os="unknown"
  fi
  echo "${os}"
}

# Detect available package manager
# Returns: homebrew, dnf, yum, apt, zypper, or empty string
detect_package_manager() {
  local os
  os="$(detect_os)"

  # Homebrew (macOS and Linux)
  if have brew; then
    echo "homebrew"
    return 0
  fi

  # Linux package managers
  case "${os}" in
  rhel)
    if have dnf; then
      echo "dnf"
      return 0
    elif have yum; then
      echo "yum"
      return 0
    fi
    ;;
  debian)
    if have apt-get; then
      echo "apt"
      return 0
    fi
    ;;
  suse)
    if have zypper; then
      echo "zypper"
      return 0
    fi
    ;;
  esac

  echo ""
}

# Detect if radp-bash-framework is installed via a package manager
# Returns: the pkm name (homebrew, dnf, apt, ...) or empty string
detect_pkm_installed() {
  # Homebrew
  if have brew && brew list --formula radp-bash-framework &>/dev/null; then
    echo "homebrew"
    return 0
  fi

  # RPM-based (dnf/yum)
  if have rpm && rpm -q radp-bash-framework &>/dev/null; then
    if have dnf; then
      echo "dnf"
    elif have yum; then
      echo "yum"
    else
      echo "rpm"
    fi
    return 0
  fi

  # Debian-based
  if have dpkg && dpkg -s radp-bash-framework &>/dev/null; then
    echo "apt"
    return 0
  fi

  # zypper
  if have zypper && zypper se -i radp-bash-framework &>/dev/null; then
    echo "zypper"
    return 0
  fi

  echo ""
}

# Uninstall package-manager-installed version
uninstall_pkm() {
  local pkm="$1"

  log "Removing package-manager version (${pkm}) to avoid conflicts..."

  case "${pkm}" in
  homebrew)
    brew uninstall radp-bash-framework || return 1
    ;;
  dnf)
    sudo dnf remove -y radp-bash-framework || return 1
    ;;
  yum)
    sudo yum remove -y radp-bash-framework || return 1
    ;;
  rpm)
    sudo rpm -e radp-bash-framework || return 1
    ;;
  apt)
    sudo apt-get remove -y radp-bash-framework || return 1
    ;;
  zypper)
    sudo zypper remove -y radp-bash-framework || return 1
    ;;
  *)
    err "Don't know how to uninstall via: ${pkm}"
    return 1
    ;;
  esac

  log "Package-manager version removed"
}

# Check if package manager repository is configured
check_repo_configured() {
  local pkm="$1"

  case "${pkm}" in
  homebrew)
    # Check if tap is configured
    if brew tap 2>/dev/null | grep -q "xooooooooox/radp"; then
      return 0
    fi
    return 1
    ;;
  dnf | yum)
    # Check if COPR repo is enabled
    if [[ -f /etc/yum.repos.d/_copr:copr.fedorainfracloud.org:xooooooooox:radp.repo ]] ||
      [[ -f /etc/yum.repos.d/radp.repo ]]; then
      return 0
    fi
    return 1
    ;;
  apt)
    # Check if OBS repo is configured
    if [[ -f /etc/apt/sources.list.d/home:xooooooooox:radp.list ]]; then
      return 0
    fi
    return 1
    ;;
  zypper)
    # Check if OBS repo is configured
    if zypper repos 2>/dev/null | grep -q "xooooooooox"; then
      return 0
    fi
    return 1
    ;;
  esac

  return 1
}

# Setup repository for package manager
setup_repo() {
  local pkm="$1"

  log "Setting up repository for ${pkm}..."

  case "${pkm}" in
  homebrew)
    log "Adding Homebrew tap..."
    brew tap xooooooooox/radp
    ;;
  dnf)
    log "Enabling COPR repository..."
    sudo dnf install -y dnf-plugins-core >/dev/null 2>&1 || true
    sudo dnf copr enable -y xooooooooox/radp
    ;;
  yum)
    log "Enabling COPR repository..."
    sudo yum install -y yum-plugin-copr >/dev/null 2>&1 || true
    sudo yum copr enable -y xooooooooox/radp
    ;;
  apt)
    log "Adding OBS repository..."
    # Detect distro for OBS
    local distro=""
    if [[ -f /etc/os-release ]]; then
      # shellcheck disable=SC1091
      source /etc/os-release
      case "${ID:-}" in
      ubuntu)
        distro="xUbuntu_${VERSION_ID}"
        ;;
      debian)
        distro="Debian_${VERSION_ID}"
        ;;
      *)
        err "Unsupported distribution for apt: ${ID:-unknown}"
        return 1
        ;;
      esac
    fi
    if [[ -z "${distro}" ]]; then
      err "Cannot detect distribution for OBS repository"
      return 1
    fi
    echo "deb http://download.opensuse.org/repositories/home:/xooooooooox:/radp/${distro}/ /" |
      sudo tee /etc/apt/sources.list.d/home:xooooooooox:radp.list >/dev/null
    curl -fsSL "https://download.opensuse.org/repositories/home:xooooooooox:radp/${distro}/Release.key" |
      gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/home_xooooooooox_radp.gpg >/dev/null
    sudo apt-get update >/dev/null
    ;;
  zypper)
    log "Adding OBS repository..."
    # Detect distro for OBS
    local distro=""
    if [[ -f /etc/os-release ]]; then
      # shellcheck disable=SC1091
      source /etc/os-release
      case "${ID:-}" in
      opensuse-tumbleweed)
        distro="openSUSE_Tumbleweed"
        ;;
      opensuse-leap)
        distro="openSUSE_Leap_${VERSION_ID}"
        ;;
      sles)
        distro="SLE_${VERSION_ID}"
        ;;
      *)
        err "Unsupported distribution for zypper: ${ID:-unknown}"
        return 1
        ;;
      esac
    fi
    if [[ -z "${distro}" ]]; then
      err "Cannot detect distribution for OBS repository"
      return 1
    fi
    sudo zypper addrepo -f "https://download.opensuse.org/repositories/home:/xooooooooox:/radp/${distro}/home:xooooooooox:radp.repo"
    ;;
  *)
    err "Unknown package manager: ${pkm}"
    return 1
    ;;
  esac
}

# Refresh package manager cache
refresh_cache() {
  local pkm="$1"

  log "Refreshing package cache..."

  case "${pkm}" in
  homebrew)
    brew update >/dev/null 2>&1 || true
    ;;
  dnf)
    sudo dnf clean all >/dev/null 2>&1 || true
    sudo dnf makecache >/dev/null 2>&1 || true
    ;;
  yum)
    sudo yum clean all >/dev/null 2>&1 || true
    sudo yum makecache >/dev/null 2>&1 || true
    ;;
  apt)
    sudo apt-get update >/dev/null 2>&1 || true
    ;;
  zypper)
    sudo zypper refresh >/dev/null 2>&1 || true
    ;;
  esac
}

# Install using package manager
install_via_pkm() {
  local pkm="$1"

  # Refresh cache to ensure we get the latest version
  refresh_cache "${pkm}"

  log "Installing ${REPO_NAME} via ${pkm}..."

  case "${pkm}" in
  homebrew)
    brew install radp-bash-framework
    ;;
  dnf)
    sudo dnf install -y radp-bash-framework
    ;;
  yum)
    sudo yum install -y radp-bash-framework
    ;;
  apt)
    sudo apt-get install -y radp-bash-framework
    ;;
  zypper)
    sudo zypper install -y radp-bash-framework
    ;;
  *)
    err "Unknown package manager: ${pkm}"
    return 1
    ;;
  esac
}

# ============================================================================
# Manual Installation
# ============================================================================

detect_fetcher() {
  if have curl; then
    echo "curl"
    return 0
  fi
  if have wget; then
    echo "wget"
    return 0
  fi
  if have fetch; then
    echo "fetch"
    return 0
  fi
  return 1
}

fetch_url() {
  local tool="$1"
  local url="$2"
  local out="$3"

  case "${tool}" in
  curl)
    curl -fsSL "${url}" -o "${out}"
    ;;
  wget)
    wget -qO "${out}" "${url}"
    ;;
  fetch)
    fetch -qo "${out}" "${url}"
    ;;
  *)
    return 1
    ;;
  esac
}

fetch_text() {
  local tool="$1"
  local url="$2"

  case "${tool}" in
  curl)
    curl -fsSL "${url}"
    ;;
  wget)
    wget -qO- "${url}"
    ;;
  fetch)
    fetch -qo- "${url}"
    ;;
  *)
    return 1
    ;;
  esac
}

resolve_ref() {
  if [[ -n "${OPT_REF}" ]]; then
    echo "${OPT_REF}"
    return 0
  fi

  if [[ -n "${OPT_VERSION}" ]]; then
    echo "${OPT_VERSION}"
    return 0
  fi

  local api_url="https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/releases/latest"
  local json
  json="$(fetch_text "${FETCH_TOOL}" "${api_url}" || true)"
  if [[ -z "${json}" ]]; then
    die "Failed to fetch latest release; use --ref <branch|tag> to specify."
  fi

  local tag
  tag="$(sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' <<<"${json}")"
  tag="${tag%%$'\n'*}"
  if [[ -z "${tag}" ]]; then
    die "Failed to parse latest tag; use --ref <branch|tag> to specify."
  fi
  echo "${tag}"
}

cleanup() {
  if [[ -n "${tmp_dir:-}" ]]; then
    rm -rf "${tmp_dir}"
  fi
}

install_manual() {
  FETCH_TOOL="$(detect_fetcher)" || die "Requires curl, wget, or fetch."

  local install_dir="${OPT_INSTALL_DIR:-$HOME/.local/lib/${REPO_NAME}}"
  local bin_dir="${OPT_BIN_DIR:-$HOME/.local/bin}"
  local ref
  ref="$(resolve_ref)"

  if [[ -z "${install_dir}" || "${install_dir}" == "/" ]]; then
    die "Unsafe install dir: ${install_dir}"
  fi
  if [[ "${RADP_BF_ALLOW_ANY_DIR:-0}" != "1" ]]; then
    if [[ "$(basename "${install_dir}")" != "${REPO_NAME}" ]]; then
      die "Install dir must end with ${REPO_NAME} (set RADP_BF_ALLOW_ANY_DIR=1 to override)."
    fi
  fi

  local tar_url="https://github.com/${REPO_OWNER}/${REPO_NAME}/archive/${ref}.tar.gz"
  tmp_dir="$(mktemp -d 2>/dev/null || mktemp -d -t "${REPO_NAME}")"
  local tarball="${tmp_dir}/${REPO_NAME}.tar.gz"
  trap cleanup EXIT

  log "Downloading ${tar_url}"
  if ! fetch_url "${FETCH_TOOL}" "${tar_url}" "${tarball}"; then
    die "Failed to download ${tar_url}"
  fi

  local tar_listing
  tar_listing="$(tar -tzf "${tarball}")"
  local root_dir="${tar_listing%%/*}"
  if [[ -z "${root_dir}" ]]; then
    die "Unable to read archive structure."
  fi

  tar -xzf "${tarball}" -C "${tmp_dir}"
  local src_root="${tmp_dir}/${root_dir}"
  if [[ ! -d "${src_root}/bin" || ! -d "${src_root}/src/main/shell/framework" ]]; then
    die "Archive layout unexpected; missing bin/ or src/main/shell/."
  fi

  rm -rf "${install_dir}"
  mkdir -p "${install_dir}/src/main/shell"
  cp -R "${src_root}/bin" "${install_dir}/"
  cp -R "${src_root}/src/main/shell/commands" "${install_dir}/src/main/shell/"
  cp -R "${src_root}/src/main/shell/config" "${install_dir}/src/main/shell/"
  cp -R "${src_root}/src/main/shell/framework" "${install_dir}/src/main/shell/"
  cp -R "${src_root}/completions" "${install_dir}/"

  chmod 0755 "${install_dir}/bin/radp-bf"
  find "${install_dir}/src/main/shell/framework" -type f -name "*.sh" -exec chmod 0755 {} \;

  # Write install metadata
  echo "${REPO_OWNER}/${REPO_NAME}" >"${install_dir}/.install-repo"
  echo "manual" >"${install_dir}/.install-method"
  echo "${ref}" >"${install_dir}/.install-ref"

  # Write actual installed version for banner display
  local installed_version
  if [[ "${ref}" =~ ^v[0-9]+\.[0-9]+ ]]; then
    # ref is a version tag, use it directly
    installed_version="${ref}"
  else
    # ref is branch/SHA, append to base version from source
    local base_version
    base_version=$(sed -n 's/^declare -gr gr_fw_version=//p' \
      "${install_dir}/src/main/shell/framework/bootstrap/context/vars/constants/constants.sh" 2>/dev/null \
      | head -n 1)
    [[ -z "$base_version" ]] && base_version="v0.0.0"
    installed_version="${base_version}+${ref}"
  fi
  echo "${installed_version}" >"${install_dir}/.install-version"

  mkdir -p "${bin_dir}"
  local target="${install_dir}/bin/radp-bf"
  local link_path
  for link_name in radp-bf radp-bash-framework; do
    link_path="${bin_dir}/${link_name}"
    if [[ -e "${link_path}" && ! -L "${link_path}" ]]; then
      die "Refusing to overwrite existing file: ${link_path}"
    fi
    ln -sf "${target}" "${link_path}"
  done

  # Install shell completions
  install_completions "${install_dir}"

  log ""
  log "Installed ${REPO_NAME} (ref: ${ref}) to ${install_dir}"
  log "Symlinked to ${bin_dir}/radp-bf and ${bin_dir}/radp-bash-framework"
  log "Ensure ${bin_dir} is in your PATH."
  log "Run: hash -r && source \"\$(radp-bf path init)\""
}

# ============================================================================
# Shell Completion Installation
# ============================================================================

install_completions() {
  local install_dir="$1"
  local completions_dir="${install_dir}/completions"

  if [[ ! -d "${completions_dir}" ]]; then
    log "Completions directory not found, skipping completion installation"
    return 0
  fi

  local bash_completion_installed=false
  local zsh_completion_installed=false

  # Determine bash completion directory
  local bash_comp_dir=""
  if [[ -d "${HOME}/.local/share/bash-completion/completions" ]]; then
    bash_comp_dir="${HOME}/.local/share/bash-completion/completions"
  elif [[ -d "${HOME}/.bash_completion.d" ]]; then
    bash_comp_dir="${HOME}/.bash_completion.d"
  else
    # Create user-local completion directory
    mkdir -p "${HOME}/.local/share/bash-completion/completions"
    bash_comp_dir="${HOME}/.local/share/bash-completion/completions"
  fi

  # Install bash completion
  if [[ -n "${bash_comp_dir}" && -f "${completions_dir}/radp-bf" ]]; then
    cp "${completions_dir}/radp-bf" "${bash_comp_dir}/radp-bf"
    bash_completion_installed=true
    log "Installed bash completion to ${bash_comp_dir}/radp-bf"
  fi

  # Determine zsh completion directory
  local zsh_comp_dir=""
  if [[ -d "${HOME}/.zfunc" ]]; then
    zsh_comp_dir="${HOME}/.zfunc"
  elif [[ -d "${HOME}/.local/share/zsh/site-functions" ]]; then
    zsh_comp_dir="${HOME}/.local/share/zsh/site-functions"
  else
    # Create user-local zsh completion directory
    mkdir -p "${HOME}/.zfunc"
    zsh_comp_dir="${HOME}/.zfunc"
  fi

  # Install zsh completion
  if [[ -n "${zsh_comp_dir}" && -f "${completions_dir}/_radp-bf" ]]; then
    cp "${completions_dir}/_radp-bf" "${zsh_comp_dir}/_radp-bf"
    zsh_completion_installed=true
    log "Installed zsh completion to ${zsh_comp_dir}/_radp-bf"
  fi

  # Provide instructions if zsh fpath might need updating
  if [[ "${zsh_completion_installed}" == "true" && "${zsh_comp_dir}" == "${HOME}/.zfunc" ]]; then
    if ! grep -q 'fpath=.*\.zfunc' "${HOME}/.zshrc" 2>/dev/null; then
      log ""
      log "Note: Add the following to your ~/.zshrc for zsh completion:"
      log "  fpath=(~/.zfunc \$fpath)"
      log "  autoload -Uz compinit && compinit"
    fi
  fi
}

# ============================================================================
# Main
# ============================================================================

main() {
  parse_args "$@"

  local mode="${OPT_MODE}"

  # --ref implies manual installation with pkm conflict resolution
  if [[ -n "${OPT_REF}" ]]; then
    log "Installing from ref: ${OPT_REF}"

    # Check for existing package-manager installation and remove it
    local existing_pkm
    existing_pkm="$(detect_pkm_installed)"
    if [[ -n "${existing_pkm}" ]]; then
      log "Detected existing package-manager installation (${existing_pkm})"
      uninstall_pkm "${existing_pkm}" || die "Failed to remove package-manager version"
    fi

    install_manual
    return 0
  fi

  local pkm=""

  # Determine installation method
  case "${mode}" in
  manual)
    log "Using manual installation (--mode manual)"
    install_manual
    return 0
    ;;
  homebrew | dnf | yum | apt | zypper)
    # Force specific package manager
    pkm="${mode}"
    if ! have "${pkm}" && [[ "${pkm}" != "homebrew" ]]; then
      die "Package manager '${pkm}' not found"
    fi
    if [[ "${pkm}" == "homebrew" ]] && ! have brew; then
      die "Homebrew not found"
    fi
    ;;
  auto | "")
    # Auto-detect package manager
    pkm="$(detect_package_manager)"
    if [[ -z "${pkm}" ]]; then
      log "No supported package manager detected, using manual installation"
      install_manual
      return 0
    fi
    log "Detected package manager: ${pkm}"
    ;;
  *)
    die "Unknown install mode: ${mode}. Use: auto, manual, homebrew, dnf, yum, apt, zypper"
    ;;
  esac

  # Check for existing manual installation and remove it
  local manual_install_dir="${OPT_INSTALL_DIR:-$HOME/.local/lib/${REPO_NAME}}"
  if [[ -f "${manual_install_dir}/.install-method" ]] &&
    [[ "$(cat "${manual_install_dir}/.install-method")" == "manual" ]]; then
    log "Detected existing manual installation at ${manual_install_dir}"
    log "Removing manual installation to avoid conflicts..."
    local manual_bin_dir="${OPT_BIN_DIR:-$HOME/.local/bin}"
    for link_name in radp-bf radp-bash-framework; do
      local manual_link="${manual_bin_dir}/${link_name}"
      if [[ -L "${manual_link}" ]]; then
        rm -f "${manual_link}"
      fi
    done
    rm -rf "${manual_install_dir}"
    log "Manual installation removed"
  fi

  # Setup repository if needed
  if ! check_repo_configured "${pkm}"; then
    log "Repository not configured for ${pkm}"
    setup_repo "${pkm}" || {
      err "Failed to setup repository, falling back to manual installation"
      install_manual
      return 0
    }
  fi

  # Install via package manager
  install_via_pkm "${pkm}" || {
    err "Package manager installation failed, falling back to manual installation"
    install_manual
    return 0
  }

  log "Successfully installed ${REPO_NAME} via ${pkm}"
  log "Shell completions have been installed automatically."
  log "Run: hash -r && source \"\$(radp-bf path init)\""
}

main "$@"
