#!/usr/bin/env bash
# Omeron - Modular System Setup Framework
# Usage: ./install.sh [--fresh] [--modules m1,m2] [--skip-packages] [--with-sddm] [--help]
set -euo pipefail

OMERON_ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
export OMERON_ROOT
export OMERON_PROJECT_DIR="$OMERON_ROOT"

source "$OMERON_ROOT/lib/log.sh"
source "$OMERON_ROOT/lib/tui.sh"
source "$OMERON_ROOT/lib/tui-fs.sh"
source "$OMERON_ROOT/lib/utils.sh"
source "$OMERON_ROOT/lib/config.sh"
source "$OMERON_ROOT/lib/modules.sh"

OMERON_FRESH_INSTALL="${OMERON_FRESH_INSTALL:-0}"
export OMERON_FRESH_INSTALL

DEFAULT_MODULES=(
  "core/preflight"
  "core/packages"
  "core/ags"
  "core/dotfiles"
  "core/services"
  "homelab/setup"
  "optional/install"
  "post/apply-theme"
  "core/sddm"
)

FRESH_MODULES=(
  "core/packages"
  "core/ags"
  "core/dotfiles"
  "core/services"
  "homelab/setup"
  "optional/install"
  "post/apply-theme"
  "core/sddm"
)

RUN_MODULES=()
SKIP_MODULES=()
WITH_SDDM=0

usage() {
  cat <<EOF
Omeron - Modular System Setup Framework

Usage: ./install.sh [OPTIONS]

Options:
  --fresh            Full system setup (Hyprland + GPU drivers + all deps)
  --modules m1,m2    Run only specific modules (comma-separated)
  --skip m1,m2       Skip specific modules (comma-separated)
  --skip-packages    Skip package installation
  --with-sddm        Include SDDM theme installation
  --list-modules     List all available modules
  --help             Show this help message

Examples:
  ./install.sh                    Interactive (detects fresh install automatically)
  ./install.sh --fresh            Force full setup on a running system
  ./install.sh --modules core/dotfiles,post/apply-theme
  ./install.sh --skip core/packages
EOF
  exit 0
}

list_modules() {
  echo "Available modules:"
  for module in $(module_list); do
    local rel_path="${module#$OMERON_MODULE_DIR/}"
    rel_path="${rel_path%.sh}"
    local description=""
    if source "$module" 2>/dev/null && declare -F "module_description" >/dev/null 2>&1; then
      description="$(module_description)"
    fi
    printf "  %-30s %s\n" "$rel_path" "$description"
  done
  exit 0
}

parse_args() {
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --fresh) OMERON_FRESH_INSTALL=1; shift ;;
      --modules) IFS=',' read -ra RUN_MODULES <<< "$2"; shift 2 ;;
      --skip) IFS=',' read -ra SKIP_MODULES <<< "$2"; shift 2 ;;
      --skip-packages) SKIP_MODULES+=("core/packages"); shift ;;
      --with-sddm) WITH_SDDM=1; shift ;;
      --list-modules) list_modules ;;
      -h|--help) usage ;;
      *) echo "Unknown option: $1" >&2; usage ;;
    esac
  done
}

detect_environment() {
  tui_detect

  if ((!OMERON_HAS_GUM)) && have pacman; then
    printf '\033[1;36m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m\n'
    printf '\033[1;36m  O M E R O N  —  Modular System Setup Framework\033[0m\n'
    printf '\033[1;36m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m\n'
    printf '\n'
    printf '  \033[1;33mgum is not installed.\033[0m Installing it enables the full TUI experience.\n'
    printf '\n'

    if tui_install_gum; then
      printf '  \033[1;32m✓ gum installed!\033[0m\n'
    else
      if ((OMERON_HAS_WHIPTAIL)); then
        printf '  \033[1;33musing whiptail as fallback\033[0m\n'
      else
        printf '  \033[1;33musing basic text mode (install gum for UI: pacman -S gum)\033[0m\n'
      fi
    fi
    printf '\n'
  fi

  if ((!OMERON_FRESH_INSTALL)) && ((${#RUN_MODULES[@]} == 0)); then
    log_info "Checking for fresh install..."
    if is_fresh_install; then
      OMERON_FRESH_INSTALL=1
      export OMERON_FRESH_INSTALL
    fi
  fi

  if ((OMERON_FRESH_INSTALL)); then
    if ((!OMERON_HAS_GUM)) && have pacman; then
      tui_install_gum 2>/dev/null || true
    fi
    if ! have paru && ! have yay; then
      install_aur_helper
    fi
  fi
}

collect_modules() {
  if ((${#RUN_MODULES[@]})); then
    for mod in "${RUN_MODULES[@]}"; do
      local module_file="$OMERON_MODULE_DIR/$mod.sh"
      [[ -f "$module_file" ]] && printf '%s\n' "$module_file"
    done
    return
  fi

  local modules=()
  if ((OMERON_FRESH_INSTALL)); then
    modules=("${FRESH_MODULES[@]}")
  else
    modules=("${DEFAULT_MODULES[@]}")
  fi

  for mod in "${modules[@]}"; do
    local skip=0
    for skipped in "${SKIP_MODULES[@]}"; do
      if [[ "$mod" == "$skipped" || "$mod" == "core/$skipped" ]]; then
        skip=1
        break
      fi
    done
    [[ "$mod" == "core/sddm" && "$WITH_SDDM" -eq 0 && "$OMERON_FRESH_INSTALL" -eq 0 ]] && skip=1
    ((skip)) && continue
    local module_file="$OMERON_MODULE_DIR/$mod.sh"
    [[ -f "$module_file" ]] && printf '%s\n' "$module_file"
  done
}

collect_all_interactive() {
  exec 3>&1
  exec 1>&2

  local modules=()
  if ((OMERON_FRESH_INSTALL)); then
    modules=("${FRESH_MODULES[@]}")
  else
    modules=("${DEFAULT_MODULES[@]}")
  fi

  local module_order=()

  for mod in "${modules[@]}"; do
    local module_file="$OMERON_MODULE_DIR/$mod.sh"
    [[ -f "$module_file" ]] || continue

    source "$module_file" 2>/dev/null || continue

    local description=""
    if declare -F "module_description" >/dev/null 2>&1; then
      description="$(module_description)"
    fi

    if declare -F "module_required" >/dev/null 2>&1; then
      if module_required; then
        module_order+=("$module_file")
        continue
      fi
    fi

    printf '  '
    if tui_confirm "${description:-$mod}"; then
      module_order+=("$module_file")
    fi
  done

  printf '%s\n' "${module_order[@]}" >&3
  exec 3>&-
}

show_banner() {
  tui_header "O M E R O N  —  Modular System Setup"
  printf '\n'
  if ((OMERON_FRESH_INSTALL)); then
    tui_info "Fresh install: Hyprland + GPU drivers + all dependencies"
    printf '\n'
  fi
}

main() {
  OMERON_LOG_FILE="${OMERON_LOG_FILE:-$HOME/.local/share/omeron/install-$(date +%Y%m%d-%H%M%S).log}"
  export OMERON_LOG_FILE

  parse_args "$@"

  mkdir -p "$(dirname "$OMERON_LOG_FILE")"
  log_info "Omeron installation started"
  log_info "Log file: $OMERON_LOG_FILE"
  log_info "Project: $OMERON_ROOT"

  sudo_init
  trap 'sudo_cleanup' EXIT

  detect_environment

  show_banner

  tui_separator
  printf '\n'
  if ! tui_confirm "Continue with installation"; then
    tui_info "Installation cancelled."
    exit 0
  fi
  printf '\n'

  local modules_to_run=()
  if ((${#RUN_MODULES[@]})); then
    mapfile -t modules_to_run < <(collect_modules)
  else
    mapfile -t modules_to_run < <(collect_all_interactive)
  fi

  if ((${#modules_to_run[@]} == 0)); then
    tui_warn "No modules selected. Nothing to do."
    exit 0
  fi

  local total=${#modules_to_run[@]}
  local idx=1

  tui_fs_init
  local fs_active=$?

  for module_path in "${modules_to_run[@]}"; do
    local description=""
    if source "$module_path" 2>/dev/null && declare -F "module_description" >/dev/null 2>&1; then
      description="$(module_description)"
    fi

    ((fs_active == 0)) && tui_fs_set_overall "$idx" "$total" "${description:-$(basename "$module_path" .sh)}"
    printf '\n'
    log_step "$idx" "$total" "${description:-$(basename "$module_path" .sh)}"

    module_run "$module_path" || {
      local rc=$?
      if declare -F "module_required" >/dev/null 2>&1; then
        source "$module_path"
        if module_required 2>/dev/null; then
          ((fs_active == 0)) && tui_fs_exit
          tui_error "Required module failed. Aborting."
          exit $rc
        fi
      fi
      tui_warn "Module completed with warnings"
    }
    ((idx++))
  done

  ((fs_active == 0)) && tui_fs_exit

  printf '\n'
  tui_header "O M E R O N  —  Done"
  tui_success "Installation Complete!"
  printf '\n'
  tui_info "Log: ${OMERON_LOG_FILE}"
  printf '\n'

  if ((OMERON_FRESH_INSTALL)); then
    tui_bold "Your system is ready for Hyprland!"
    tui_list \
      "Start Hyprland:  Hyprland" \
      "Or enable SDDM:  sudo systemctl enable --now sddm" \
      "Reload config:   hyprctl reload"
  else
    tui_bold "What next?"
    tui_list \
      "Reload config:   hyprctl reload" \
      "Re-run installer: ./install.sh"
  fi
  printf '\n'

  if have notify-send; then
    notify-send "Omeron" "Installation complete!" >/dev/null 2>&1 || true
  fi
}

main "$@"
