#!/usr/bin/env bash
set -e

# Nomarchy TTY Installer
# Golden path: BTRFS + LUKS2 encryption
#
# This is a minimal, single-path installer designed for TTY-only environments.
# For a customized installation, manually set up your disk and use the generated
# flake configuration as a starting point.

# Colors and styling
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
BOLD='\033[1m'

# Installer state
NOMARCHY_REPO=""
TARGET_DRIVE=""
USERNAME=""
LUKS_PASSWORD=""
USER_PASSWORD=""
TIMEZONE="UTC"
HARDWARE_MODULES=""
NOMARCHY_HW_OPTS=""
ENABLE_IMPERMANENCE="false"

# ============================================================================
# UTILITY FUNCTIONS
# ============================================================================

# Helper to run commands via nix run
nrun() {
    local pkg="$1"
    shift
    nix run --extra-experimental-features "nix-command flakes" "nixpkgs#$pkg" -- "$@"
}

header() {
    clear
    nrun gum style \
        --foreground 212 --border-foreground 212 --border double \
        --align center --width 60 --margin "1 2" --padding "2 4" \
        "NOMARCHY INSTALLER" "NixOS with Omarchy flavor"
    echo ""
}

section() {
    echo ""
    nrun gum style --foreground 14 --bold "━━━ $1 ━━━"
    echo ""
}

success() {
    nrun gum style --foreground 10 "✓ $1"
}

error() {
    nrun gum style --foreground 9 "✗ $1"
}

info() {
    nrun gum style --foreground 12 "→ $1"
}

# ============================================================================
# STEP 1: ENVIRONMENT CHECK
# ============================================================================

check_environment() {
    section "Environment Check"

    # Check for root
    if [[ $EUID -ne 0 ]]; then
        error "This installer must be run as root (use sudo)"
        exit 1
    fi
    success "Running as root"

    # Find Nomarchy repo
    if [[ -d "/etc/nomarchy" ]]; then
        NOMARCHY_REPO="/etc/nomarchy"
    elif [[ -d "$(dirname "$0")/.." ]] && [[ -f "$(dirname "$0")/../flake.nix" ]]; then
        NOMARCHY_REPO="$(realpath "$(dirname "$0")/..")"
    fi

    if [[ -z "$NOMARCHY_REPO" ]]; then
        error "Nomarchy repository not found"
        exit 1
    fi
    success "Found Nomarchy at $NOMARCHY_REPO"

    # Check internet
    gum spin --spinner dot --title "Checking internet connection..." -- sleep 1
    while ! ping -c 1 -W 2 1.1.1.1 &>/dev/null; do
        error "No internet connection"
        local choice
        choice=$(gum choose "Open Network Manager (nmtui)" "Retry" "Exit")
        case "$choice" in
            *nmtui*) nmtui ;;
            *Exit*) exit 1 ;;
        esac
    done
    success "Internet connection verified"
}

# ============================================================================
# STEP 2: DISK SELECTION
# ============================================================================

select_disk() {
    section "Disk Selection"

    info "Available drives:"
    echo ""
    lsblk -d -n -p -o NAME,SIZE,MODEL | grep -v loop
    echo ""

    local drives
    drives=$(lsblk -d -n -p -o NAME,SIZE | grep -v loop)
    TARGET_DRIVE=$(echo "$drives" | gum choose --header "Select target drive" | awk '{print $1}')

    if [[ -z "$TARGET_DRIVE" ]]; then
        error "No drive selected"
        exit 1
    fi

    echo ""
    gum style --foreground 9 --bold "⚠ WARNING: All data on $TARGET_DRIVE will be DESTROYED!"
    echo ""

    if ! gum confirm "Are you sure you want to use $TARGET_DRIVE?"; then
        error "Aborted"
        exit 1
    fi

    success "Selected: $TARGET_DRIVE"
}

# ============================================================================
# STEP 3: LUKS PASSPHRASE
# ============================================================================

get_luks_passphrase() {
    section "Disk Encryption"

    info "Your disk will be encrypted with LUKS2."
    info "Enter a strong passphrase (you'll need this at every boot)."
    echo ""

    local pass1 pass2
    while true; do
        pass1=$(gum input --password --placeholder "Enter LUKS passphrase")
        [[ -z "$pass1" ]] && continue

        pass2=$(gum input --password --placeholder "Confirm passphrase")

        if [[ "$pass1" == "$pass2" ]]; then
            LUKS_PASSWORD="$pass1"
            break
        else
            error "Passphrases do not match. Try again."
        fi
    done

    success "Encryption passphrase set"
}

# ============================================================================
# STEP 4: USER CONFIGURATION
# ============================================================================

configure_user() {
    section "User Configuration"

    USERNAME=$(nrun gum input --placeholder "Enter username (lowercase, no spaces)")
    if [[ -z "$USERNAME" ]] || [[ ! "$USERNAME" =~ ^[a-z][a-z0-9_-]*$ ]]; then
        error "Invalid username"
        exit 1
    fi

    success "Username: $USERNAME"

    # User password (can be same as LUKS or different)
    info "Set a password for your user account"
    local pass1 pass2
    while true; do
        pass1=$(nrun gum input --password --placeholder "Enter user password")
        [[ -z "$pass1" ]] && continue

        pass2=$(nrun gum input --password --placeholder "Confirm user password")

        if [[ "$pass1" == "$pass2" ]]; then
            USER_PASSWORD="$pass1"
            break
        else
            error "Passwords do not match. Try again."
        fi
    done

    success "User password set"
}

# ============================================================================
# STEP 5: TIMEZONE
# ============================================================================

select_timezone() {
    section "Timezone"

    local timezones
    timezones=$(timedatectl list-timezones 2>/dev/null || echo "UTC")
    TIMEZONE=$(echo "$timezones" | gum filter --placeholder "Search timezone...")

    [[ -z "$TIMEZONE" ]] && TIMEZONE="UTC"
    success "Timezone: $TIMEZONE"
}

# ============================================================================
# STEP 6: HARDWARE VENDOR
# ============================================================================

select_hardware() {
    section "Hardware Configuration"

    local product_name cpu_vendor
    product_name=$(cat /sys/class/dmi/id/product_name 2>/dev/null || echo "Unknown")
    cpu_vendor=$(lscpu 2>/dev/null | grep "Vendor ID" | awk '{print $3}' || echo "Unknown")

    info "Detected: $product_name"
    info "CPU: $cpu_vendor"
    echo ""

    # Set CPU-specific module
    if [[ "$cpu_vendor" == "AuthenticAMD" ]]; then
        HARDWARE_MODULES="inputs.nixos-hardware.nixosModules.common-cpu-amd"
    elif [[ "$cpu_vendor" == "GenuineIntel" ]]; then
        HARDWARE_MODULES="inputs.nixos-hardware.nixosModules.common-cpu-intel"
    fi

    local vendor
    vendor=$(gum choose --header "Select hardware vendor" \
        "Generic (Auto-detect)" \
        "Framework" \
        "Dell" \
        "Lenovo" \
        "Apple (T2 Mac)" \
        "Microsoft Surface" \
        "Other...")

    case "$vendor" in
        *Framework*)
            local model
            model=$(gum choose "16-7040-amd" "13-7040-amd" "13-intel-13th-gen" "13-intel-12th-gen")
            HARDWARE_MODULES="$HARDWARE_MODULES\n    inputs.nixos-hardware.nixosModules.framework-$model"
            NOMARCHY_HW_OPTS="nomarchy.hardware.isFramework = true;"
            ;;
        *Dell*)
            local model
            model=$(gum choose "xps-15-9500" "xps-15-9510" "xps-13-9310" "xps-13-9380" "precision-5530")
            HARDWARE_MODULES="$HARDWARE_MODULES\n    inputs.nixos-hardware.nixosModules.dell-$model"
            [[ "$model" == *"xps"* ]] && NOMARCHY_HW_OPTS="nomarchy.hardware.isXPS = true;"
            ;;
        *Lenovo*)
            local model
            model=$(gum choose "thinkpad-x1-carbon-gen10" "thinkpad-t14-amd" "thinkpad-t480" "thinkpad-x1-extreme")
            HARDWARE_MODULES="$HARDWARE_MODULES\n    inputs.nixos-hardware.nixosModules.lenovo-$model"
            ;;
        *Apple*)
            NOMARCHY_HW_OPTS="nomarchy.hardware.isT2Mac = true;"
            ;;
        *Surface*)
            local model
            model=$(gum choose "surface-pro-9" "surface-pro-8" "surface-laptop-4")
            HARDWARE_MODULES="$HARDWARE_MODULES\n    inputs.nixos-hardware.nixosModules.microsoft-$model"
            ;;
        *Other*)
            info "Enter nixos-hardware module path (or leave empty):"
            local custom_mod
            custom_mod=$(gum input --placeholder "e.g., inputs.nixos-hardware.nixosModules.asus-zephyrus-ga401")
            [[ -n "$custom_mod" ]] && HARDWARE_MODULES="$HARDWARE_MODULES\n    $custom_mod"
            ;;
    esac

    success "Hardware configuration set"
}

# ============================================================================
# STEP 7: IMPERMANENCE (OPTIONAL)
# ============================================================================

configure_impermanence() {
    section "Impermanence (Optional)"

    info "Impermanence erases your root filesystem on every boot."
    info "Only explicitly persisted files survive reboots."
    info "This provides a clean, reproducible system."
    echo ""

    if gum confirm "Enable Impermanence?"; then
        ENABLE_IMPERMANENCE="true"
        success "Impermanence enabled"
    else
        info "Impermanence disabled (traditional persistent root)"
    fi
}

# ============================================================================
# STEP 8: REVIEW & CONFIRM
# ============================================================================

review_configuration() {
    section "Review Configuration"

    echo "  Drive:         $TARGET_DRIVE (BTRFS + LUKS2)"
    echo "  Username:      $USERNAME"
    echo "  Timezone:      $TIMEZONE"
    echo "  Impermanence:  $ENABLE_IMPERMANENCE"
    echo ""

    nrun gum style --foreground 9 "This will DESTROY all data on $TARGET_DRIVE"
    echo ""

    if ! nrun gum confirm "Proceed with installation?"; then
        error "Aborted"
        exit 1
    fi
}

# ============================================================================
# STEP 9: EXECUTION
# ============================================================================

execute_installation() {
    section "Installing Nomarchy"

    # 9.1 Partition with disko
    info "Partitioning disk..."
    local disko_file tmp_disko
    disko_file="$NOMARCHY_REPO/installer/disko-golden.nix"
    tmp_disko=$(mktemp --suffix=.nix)

    sed "s|@TARGET_DRIVE@|${TARGET_DRIVE}|g" "$disko_file" > "$tmp_disko"

    # Provide the LUKS passphrase via a temporary file for disk encryption
    echo -n "$LUKS_PASSWORD" > /tmp/secret.key
    disko --mode disko "$tmp_disko"
    rm /tmp/secret.key
    success "Disk partitioned"

    # 9.2 Generate hardware config
    info "Generating hardware configuration..."
    mkdir -p /mnt/etc/nixos
    nixos-generate-config --root /mnt
    success "Hardware configuration generated"

    # 9.3 Generate flake configuration
    info "Creating system configuration..."
    generate_flake_config
    success "Configuration generated"

    # 9.4 Initialize git repo
    info "Initializing git repository..."
    (
        cd /mnt/etc/nixos
        nrun git git init -q
        nrun git git add .
        nrun git git config user.name "Nomarchy Installer"
        nrun git git config user.email "installer@nomarchy"
        nrun git git commit -qm "Initial Nomarchy configuration"
    )
    success "Git repository initialized"

    # 9.5 Handle impermanence
    if [[ "$ENABLE_IMPERMANENCE" == "true" ]]; then
        info "Setting up impermanence..."
        mkdir -p /mnt/persist/etc
        mv /mnt/etc/nixos /mnt/persist/etc/
        mkdir -p /mnt/etc
        ln -s /persist/etc/nixos /mnt/etc/nixos
        success "Impermanence configured"
    fi

    # 9.6 Install
    info "Running nixos-install (this will take a while)..."
    nixos-install --flake /mnt/etc/nixos#default --no-root-passwd
    success "Installation complete!"
}

# ============================================================================
# GENERATE FLAKE CONFIGURATION
# ============================================================================

generate_flake_config() {
    local impermanence_opt=""
    [[ "$ENABLE_IMPERMANENCE" == "true" ]] && impermanence_opt="nomarchy.system.impermanence.enable = true;"

    # flake.nix
    cat > /mnt/etc/nixos/flake.nix << 'FLAKE_EOF'
{
  description = "My Nomarchy Configuration";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
    nomarchy.url = "github:bemagri/nomarchy";
    nixos-hardware.url = "github:NixOS/nixos-hardware/master";
    home-manager = {
      url = "github:nix-community/home-manager/release-25.11";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = { self, nixpkgs, nomarchy, home-manager, nixos-hardware, ... }@inputs: {
    nixosConfigurations.default = nixpkgs.lib.nixosSystem {
      specialArgs = { inputs = nomarchy.inputs // inputs; };
      modules = [
        { nixpkgs.hostPlatform = "x86_64-linux"; }
        ./hardware-configuration.nix
        ./hardware-selection.nix
        nomarchy.nixosModules.system
        ./system.nix
      ];
    };

    homeConfigurations.@USERNAME@ = home-manager.lib.homeManagerConfiguration {
      pkgs = nixpkgs.legacyPackages.x86_64-linux;
      extraSpecialArgs = { inputs = nomarchy.inputs // inputs; };
      modules = [
        nomarchy.nixosModules.home
        ./home.nix
        {
          home.username = "@USERNAME@";
          home.homeDirectory = "/home/@USERNAME@";
          home.stateVersion = "25.11";
        }
      ];
    };
  };
}
FLAKE_EOF
    sed -i "s/@USERNAME@/$USERNAME/g" /mnt/etc/nixos/flake.nix

    # hardware-selection.nix
    cat > /mnt/etc/nixos/hardware-selection.nix << EOF
{ inputs, ... }:
{
  imports = [
    $HARDWARE_MODULES
  ];
  $NOMARCHY_HW_OPTS
}
EOF

    # system.nix — curated system-level options. Uncomment what you want and
    # run \`sudo nixos-rebuild switch --flake /etc/nixos#default\` to apply.
    cat > /mnt/etc/nixos/system.nix << EOF
{ pkgs, ... }:
{
  time.timeZone = "$TIMEZONE";

  $impermanence_opt

  # System-wide packages. Most tools belong in home.nix instead — only put
  # things here that need to be available to all users or to root (e.g. CLI
  # tools used by sudo, system admin utilities).
  environment.systemPackages = with pkgs; [
    home-manager
    # --- CLI tools useful as root ---
    # wget
    # curl
    # rsync
    # htop
    # tree
    # tmux
  ];

  services.displayManager.autoLogin.enable = true;
  services.displayManager.autoLogin.user = "$USERNAME";

  users.users."$USERNAME" = {
    isNormalUser = true;
    initialPassword = "$USER_PASSWORD";
    extraGroups = [ "networkmanager" "wheel" "video" "audio" "render" ];
  };

  # --- Optional system services ---
  # Uncomment to enable. Some require extra groups on your user (see below).

  # Containers / virtualization
  # virtualisation.docker.enable = true;       # adds "docker" group
  # virtualisation.libvirtd.enable = true;     # adds "libvirtd" group — needed for virt-manager

  # Networking / sync
  # services.tailscale.enable = true;
  # services.syncthing = {
  #   enable = true;
  #   user = "$USERNAME";
  #   dataDir = "/home/$USERNAME";
  # };

  # Printing
  # services.printing.enable = true;

  # Flatpak (alternative app delivery)
  # services.flatpak.enable = true;
  # xdg.portal.enable = true;

  # Gaming (system-level — pairs with home.packages.steam)
  # programs.steam.enable = true;
  # programs.gamemode.enable = true;

  system.stateVersion = "25.11";
}
EOF

    # home.nix — curated app menu. Uncomment what you want and run
    # `nomarchy-env-update` to apply.
    cat > /mnt/etc/nixos/home.nix << 'EOF'
{ pkgs, ... }:
{
  # User-level packages (Home Manager).
  #
  # Nomarchy already ships a minimal desktop (firefox, thunar, mpv, imv, mako,
  # hyprlock, swww, wl-clipboard, grim, slurp, rofi-wayland, etc.). The list
  # below is a menu of extras — uncomment what you want and run
  # `nomarchy-env-update`.
  home.packages = with pkgs; [
    # --- Enabled by default ---
    btop                # Resource monitor (TUI)
    fastfetch           # System info at login
    chromium            # Secondary browser

    # --- Editors & dev ---
    # vscode
    # jetbrains.idea-community
    # neovide
    # zed-editor
    # lazygit
    # gh                  # GitHub CLI
    # docker-compose
    # postman
    # dbeaver-bin

    # --- Productivity ---
    # obsidian
    # libreoffice
    # thunderbird
    # zathura             # PDF viewer
    # zotero
    # xournalpp

    # --- Media ---
    # vlc
    # obs-studio
    # gimp
    # inkscape
    # kdenlive
    # spotify
    # audacity
    # yt-dlp

    # --- Comms ---
    # discord
    # telegram-desktop
    # signal-desktop
    # slack
    # zoom-us

    # --- Security ---
    # keepassxc
    # bitwarden-desktop
    # _1password-gui

    # --- Gaming ---
    # steam
    # lutris
    # heroic

    # --- CLI / utilities ---
    # ripgrep
    # fd
    # bat
    # eza
    # zoxide
    # fzf
    # httpie
    # tldr
  ];

  # Extra Home Manager modules go here (program configs, services, etc.).
}
EOF
}

# ============================================================================
# FINISH
# ============================================================================

finish() {
    header

    nrun gum style --foreground 10 --bold --align center "INSTALLATION COMPLETE!"
    echo ""
    echo "Nomarchy has been successfully installed."
    echo ""
    echo "Next steps:"
    echo "  1. Remove the installation media"
    echo "  2. Reboot your computer"
    echo "  3. Log in with username: $USERNAME"
    echo "  4. Your configuration is at /etc/nixos/"
    echo ""
    echo "Tip: run 'nomarchy-themes-prebuild' once to pre-cache every theme"
    echo "     variant. Theme switches after that are instant (no rebuild)."
    echo ""

    if nrun gum confirm "Reboot now?"; then
        reboot
    fi
}

# ============================================================================
# MAIN
# ============================================================================

main() {
    header

    check_environment
    select_disk
    get_luks_passphrase
    configure_user
    select_timezone
    select_hardware
    configure_impermanence
    review_configuration
    execute_installation
    finish
}

main "$@"
finish
}

main "$@"
