#!/bin/bash

# omarchy:summary=Run pending Omarchy migrations.
# omarchy:args=[--pending|--baseline]

set -euo pipefail

mode="run"

usage() {
  echo "Usage: omarchy-migrate [--pending|--baseline]"
}

while (($#)); do
  case "$1" in
    --pending|--check)
      mode="pending"
      shift
      ;;
    --baseline)
      mode="baseline"
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "Unknown option: $1" >&2
      exit 1
      ;;
  esac
done

OMARCHY_PATH="${OMARCHY_PATH:-/usr/share/omarchy}"
STATE_DIR="${OMARCHY_MIGRATION_STATE:-$HOME/.local/state/omarchy/migrations}"
MIGRATIONS_DIR="$OMARCHY_PATH/migrations"

migration_entries() {
  [[ -d $MIGRATIONS_DIR ]] || return 0

  local file filename

  for file in "$MIGRATIONS_DIR"/*.sh; do
    [[ -f $file ]] || continue
    filename=$(basename "$file")
    printf '%s\t%s\t%s\n' "$filename" "$file" "$STATE_DIR/$filename"
  done
}

pending_migrations() {
  local name file marker

  while IFS=$'\t' read -r name file marker; do
    [[ -n $name ]] || continue
    if [[ ! -f $marker ]]; then
      printf '%s\n' "$name"
    fi
  done < <(migration_entries)
}

if [[ $mode == "pending" ]]; then
  pending_output=$(pending_migrations)
  if [[ -n $pending_output ]]; then
    printf '%s\n' "$pending_output"
    exit 0
  else
    exit 1
  fi
fi

# Baseline marks every migration currently present as done without running any
# of them. Fresh installs use this: the shipped defaults already include what
# old migrations changed, and pre-port (Arch-era) migrations must never run on
# a Fedora system. New migrations added after the baseline run normally.
if [[ $mode == "baseline" ]]; then
  mkdir -p "$STATE_DIR"
  while IFS=$'\t' read -r name file marker; do
    [[ -n $name ]] || continue
    mkdir -p "$(dirname "$marker")"
    touch "$marker"
  done < <(migration_entries)
  exit 0
fi

wait_for_dnf_transaction() {
  local lock_file=/usr/lib/sysimage/rpm/.rpm.lock

  # Only an actually-held lock counts: the lock file itself goes stale (it is
  # not removed after transactions), so mere existence must never block.
  # Without fuser there is nothing to observe with, so don't wait either.
  omarchy-cmd-present fuser || return 0
  fuser -s "$lock_file" 2>/dev/null || return 0
  echo "Waiting for dnf transaction to finish before running Omarchy migrations..."

  for _ in {1..900}; do
    fuser -s "$lock_file" 2>/dev/null || return 0
    sleep 1
  done

  echo "Dnf transaction is still running; Omarchy migrations will retry on next login."
  exit 0
}

wait_for_dnf_transaction

mkdir -p "$STATE_DIR"
[[ -d $MIGRATIONS_DIR ]] || exit 0

while IFS=$'\t' read -r name file marker <&3; do
  [[ -n $name ]] || continue

  if [[ ! -f $marker ]]; then
    echo -e "\e[32m\nRunning migration (${name%.sh})\e[0m"
    OMARCHY_PATH="$OMARCHY_PATH" bash -euo pipefail "$file" 3<&-
    mkdir -p "$(dirname "$marker")"
    touch "$marker"
  fi
done 3< <(migration_entries)

# Clear a login-time notification the user left sitting there and then resolved
# by running migrations some other way. The substring matches both the current
# and legacy notification titles.
omarchy-notification-dismiss "Omarchy Migrations" >/dev/null 2>&1 || true
