#!/usr/bin/env bash
# quixos-prepare-hooks-v1
set -euo pipefail

package_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
packages_dir="$(cd "$package_dir/.." && pwd)"
package_name="$(basename "$package_dir")"
flake_path="$package_dir/flake.nix"
deps=()

assert_safe_absolute_dir() {
  local value="$1"
  local label="$2"
  if [[ -z "$value" || "$value" != /* || "$value" == "/" ]]; then
    echo "Refusing unsafe ${label}: ${value:-<empty>}" >&2
    exit 1
  fi
}

safe_rm_rf_under() {
  local root="$1"
  local target="$2"

  assert_safe_absolute_dir "$root" "root path"
  if [[ -z "$target" || "$target" != /* || "$target" == "/" || "$target" == "$root" ]]; then
    echo "Refusing unsafe rm target: ${target:-<empty>}" >&2
    exit 1
  fi

  case "$target" in
    "$root"/*) ;;
    *)
      echo "Refusing to remove path outside root: $target (root: $root)" >&2
      exit 1
      ;;
  esac

  rm -rf "$target"
}

assert_valid_package_name() {
  local value="$1"
  if [[ ! "$value" =~ ^[a-z0-9-]+$ ]]; then
    echo "Invalid package name: $value" >&2
    exit 1
  fi
}

load_deps() {
  deps=()
  if [[ -f "$flake_path" ]]; then
    while IFS= read -r dep; do
      deps+=("$dep")
    done < <(
      grep -Eoh 'packageSchema_[A-Za-z0-9_-]+' "$flake_path" | sed 's/^packageSchema_//' | sort -u
    )
  fi
}

update_src_yarnrc() {
  local yarnrc_path="$package_dir/src/.yarnrc.yml"
  if [[ ! -f "$yarnrc_path" ]]; then
    return
  fi

  local block_tmp
  local tmp
  block_tmp="$(mktemp)"
  tmp="$(mktemp)"

  {
    printf '%s\n' 'packageExtensions:'
    printf '%s\n' '  "quixos-package@*":'
    printf '%s\n' '    dependencies:'
    printf '      "@quixos-package-schemas/%s": "portal:./quixos-package-schemas/%s"\n' \
      "$package_name" "$package_name"
    for dep in "${deps[@]}"; do
      printf '      "@quixos-package-schemas/%s": "portal:./quixos-package-schemas/%s"\n' \
        "$dep" "$dep"
    done
  } > "$block_tmp"

  awk -v blockFile="$block_tmp" '
    BEGIN {
      while ((getline line < blockFile) > 0) {
        block = block line "\n"
      }
    }
    /^# BEGIN packageExtensions/ { print; printf "%s", block; skip = 1; next }
    /^# END packageExtensions/ { skip = 0; print; next }
    !skip { print }
  ' "$yarnrc_path" > "$tmp"

  mv "$tmp" "$yarnrc_path"
  rm -f "$block_tmp"
}

refresh_src_dependency_wiring() {
  load_deps
  if [[ ! -d "$package_dir/src" ]]; then
    return
  fi

  update_src_yarnrc
  link_root="$package_dir/src/quixos-package-schemas"
  assert_safe_absolute_dir "$link_root" "link_root"
  mkdir -p "$link_root"

  if [[ -d "$package_dir/schema" ]]; then
    safe_rm_rf_under "$link_root" "$link_root/$package_name"
    ln -s "$package_dir/schema" "$link_root/$package_name"
  fi

  for dep in "${deps[@]}"; do
    target="$packages_dir/$dep/schema"
    if [[ ! -d "$target" ]]; then
      continue
    fi
    safe_rm_rf_under "$link_root" "$link_root/$dep"
    ln -s "$target" "$link_root/$dep"
  done
}

prepare_schema_project() {
  if [[ ! -f "$package_dir/schema/package.json" ]]; then
    return
  fi

  (
    cd "$package_dir/schema"
    env YARN_ENABLE_NETWORK=1 yarn_enable_network=1 yarn install
    yarn build
  )
}

install_src_project() {
  if [[ ! -f "$package_dir/src/package.json" ]]; then
    return
  fi

  (
    cd "$package_dir/src"
    env YARN_ENABLE_NETWORK=1 yarn_enable_network=1 yarn install
  )
}

replace_template_placeholders() {
  local requested_name="$1"

  assert_valid_package_name "$requested_name"
  if [[ "$requested_name" != "$package_name" ]]; then
    echo "Package name mismatch: expected $package_name, got $requested_name" >&2
    exit 1
  fi

  rg -uuu -l -0 '\{\{PACKAGE_NAME\}\}' . | xargs -0 sed -i "s/{{PACKAGE_NAME}}/${requested_name}/g"
}

template_prepare_post_clone() {
  if [[ "$#" -ne 1 ]]; then
    echo "Usage: $0 template_prepare_post_clone <package-name>" >&2
    exit 1
  fi

  replace_template_placeholders "$1"
  refresh_src_dependency_wiring
  prepare_schema_project
  install_src_project
}

pre_stage() {
  :
}

pre_dep_change() {
  :
}

post_dep_change() {
  refresh_src_dependency_wiring
  prepare_schema_project
  install_src_project
}

full_prepare() {
  refresh_src_dependency_wiring
  prepare_schema_project
  install_src_project
}

assert_safe_absolute_dir "$package_dir" "package_dir"
assert_safe_absolute_dir "$packages_dir" "packages_dir"

hook="${1:-}"
case "$hook" in
  template_prepare_post_clone)
    shift
    template_prepare_post_clone "$@"
    ;;
  pre_stage)
    shift
    pre_stage "$@"
    ;;
  pre_dep_change)
    shift
    pre_dep_change "$@"
    ;;
  post_dep_change)
    shift
    post_dep_change "$@"
    ;;
  full_prepare)
    shift
    full_prepare "$@"
    ;;
  "")
    echo "Usage: $0 <template_prepare_post_clone|pre_stage|pre_dep_change|post_dep_change|full_prepare> [args...]" >&2
    exit 1
    ;;
  *)
    echo "Unknown quixos-prepare hook: $hook" >&2
    exit 1
    ;;
esac
