#!/usr/bin/env bash
#
# a development environment setup tool.
sudo apt update -qq && sudo apt install -y curl

# sudo install -dm 755 /etc/apt/keyrings
DEST=${1:-/etc/skel}

URI="mise.jdx.dev"
TRANSPORT="https:/"
TYPES=(deb)
SUITES="stable"
COMPONENTS=(main)
ARCHITECTURES=(amd64)
KEY_DIR="/usr/share/keyrings"
KEY="${KEY_DIR}/mise-archive-keyring.gpg"
MISE_HOME="${DEST}/.config/mise"
MISE_CONFIG_DIR="${MISE_HOME}/conf.d"
mkdir -p "${MISE_CONFIG_DIR}"

curl -fSs ${TRANSPORT}/${URI}/gpg-key.pub | sudo gpg --dearmor --yes -o ${KEY} 1>/dev/null

conf_print_sources() {
  cat <<EOF
Enabled: yes
Types: ${TYPES[*]}
URIs: ${TRANSPORT}/${URI}/deb/
Suites: ${SUITES}
Components: ${COMPONENTS[*]}
Architectures: ${ARCHITECTURES[*]}
Signed-By: ${KEY}
EOF
}
conf_print_sources | sudo tee /etc/apt/sources.list-available/mise.sources
sudo ln -sf /etc/apt/sources.list-available/mise.sources /etc/apt/sources.list.d/mise.sources
sudo apt update -qq
sudo apt install -y mise

# Helper functions
# Move the previous config to .backup, date and prune
setup_config_file() {
  local target_file="$1"
  local provider_cmd="$2"
  local retention_days=30

  local target_dir
  target_dir=$(dirname "$target_file")
  local backup_dir="${target_dir}/.backups"
  local timestamp
  timestamp=$(date +%Y%m%d_%H%M%S)

  # 1. Ensure backup directory exists
  mkdir -p "$backup_dir"

  # 2. Capture new config first to prevent losing the old one if the command fails
  local temp_config
  temp_config=$(mktemp)

  if ! $provider_cmd >"$temp_config"; then
    echo "Error: Provider command failed. Keeping existing config."
    rm -f "$temp_config"
    return 1
  fi

  # 3. Rotate existing config if it exists
  if [[ -f "$target_file" ]]; then
    echo "Backing up $(basename "$target_file") to .backups/..."
    mv "$target_file" "${backup_dir}/$(basename "$target_file").${timestamp}.bak"
  fi

  # 4. Move new config into place
  mv "$temp_config" "$target_file"
  echo "New config written to $target_file"

  # 5. Cleanup
  find "$backup_dir" -name "*.bak" -type f -mtime +"$retention_days" -delete
}

# Have mise activated by zsh
echo "eval $(/usr/bin/mise activate zsh)" >"${DEST}/.zshrc.d/004_mise.zsh"

# mise plugins
mise plugins install conda
export MISE_CONDA_PYTHON_EXE=/opt/conda/bin/python
# then remove zgenom load bckim92/zsh-autoswitch-conda

# Link mise to existing containers in .mise.yml for a project
CONDA_ENVS_DIR="${DEST}/.conda/envs"
# mise use python@prefix:<path_to_your_conda_env>

# Example if your environment is named 'my-data-env'
# mise use python@prefix:~/anaconda3/envs/my-data-env
# mise use python@prefix:${CONDA_ENVS_DIR}/my-data-env
# mise use node@prefix:${CONDA_ENVS_DIR}/node_env
# mise use go@prefix:${CONDA_ENVS_DIR}/goenv

conf_print_mise_config() {
  cat <<EOF
[settings]
experimental = true
always_keep_download = false
plugin_autoupdate_last_check_duration = "7d"
jobs = 4
asdf_compat = true
auto_install = true

[tools]
# --- CORE BINARIES ---
usage = "latest"
fzf = "latest"
uv = "latest"

# --- LANGUAGES ---
python = "3.14"
node = "lts"
rust = "1.94"
go = "1.26"

[env]
EDITOR = "nvim"
GOPATH = "{{ config_root }}/go"
# Ensure Go binaries are available in your shell
PATH = "{{ config_root }}/go/bin:$PATH"

[tasks]
"clean:all" = { run = "mise prune && uv cache clean && cargo clean", description = "Deep clean all package managers" }
"update:tools" = { run = "mise upgrade && rustup update", description = "Upgrade mise tools and rust toolchain" }
"check:health" = { run = "mise doctor && go version && rustc --version", description = "Verify toolchain health" }

# Bonus: A quick setup task for new environments
"setup" = { run = "mise install && uv venv", description = "Install tools and create virtualenv" }
EOF
}

# Usage: setup_config_file "PATH" "GENERATOR_FUNCTION"
setup_config_file "${MISE_HOME}/config.toml" "conf_print_mise_config"

# Post setup
# Install all plugins/tools defined in config
mkdir -p ~/.gnupg
chmod 700 ~/.gnupg
sudo chown -R "$(whoami):$(whoami)" ~/.gnupg
mise install

# 📂 Recommended Project Structure
# To keep things organized, I suggest tracking your `source of truth` for
# shorthands inside the repository. This allows you to version control your
# private tool aliases.
# *    .github/workflows/mise-health-check.yml: Your CI logic.
# *    bin/bootstrap: The script above (remember to chmod +x bin/bootstrap).
# *    .mise.shorthands.toml: The actual list of your private my-cli mappings.
# *    mise.toml: Your standard tool versions (e.g., python = "3.12", uv = "latest").

# 🚀 GitHub Actions: mise-health-check.yml
# Create this file at .github/workflows/mise-health-check.yml. This workflow
# installs mise, uses it to setup your defined runtimes (Go, Rust, Python,
#  Node), and then triggers your check:health task.
conf_print_mise_action() {
  cat <<EOF
name: Environment Health Check

on:
  push:
    branches: [ main, master ]
  pull_request:
    branches: [ main, master ]

jobs:
  validate-environment:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Install mise
        uses: jdx/mise-action@v2
        with:
          # This automatically installs tools defined in your mise.toml
          install: true 
          # Optional: cache the mise directory to speed up subsequent runs
          cache: true

      - name: Verify Tool Versions
        run: mise ls --current

      - name: Run Project Health Check
        # This executes the specific task defined in your mise.toml
        run: mise run check:health

      - name: Python Environment Lint (uv)
        # Ensuring uv is doing its job and the lockfile is synced
        run: uv lock --check
        if: always()
EOF
}

# 🔍 Why this works for your 2026 stack:
# jdx/mise-action: This is the official action. By setting install: true, it reads
# your mise.toml and ensures every binary (Go, Node, etc.) is present in the
# runner's PATH immediately.
#
# Layered Validation: It doesn't just check if mise works; it runs your actual
# project-level health checks. If a developer forgets to update the uv.lock or a
# Rust crate is missing a system dependency, this job will catch it.
#
# The uv Check: Since you're using uv this ensures the dependencies haven't
# drifted from the pyproject.toml without a lockfile update.
