#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"

usage() {
  cat <<'EOF'
Usage: bin/qa-changed [options]

Run packages/pi-packages quality checks (typecheck + package tests) on changed packages.

Options:
  --base-ref <ref>     Base git ref for changed-file detection
  --head-ref <ref>     Head git ref (default: HEAD)
  --package <name>     Check a specific package (repeatable, e.g. pi-dcp)
  --all                Check all pi-* packages
  -h, --help           Show this help
EOF
}

base_ref=""
head_ref="HEAD"
run_all=0
packages=()

while [[ $# -gt 0 ]]; do
  case "$1" in
    --base-ref)
      base_ref="${2:-}"
      shift 2
      ;;
    --head-ref)
      head_ref="${2:-}"
      shift 2
      ;;
    --package)
      packages+=("${2:-}")
      shift 2
      ;;
    --all)
      run_all=1
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "error: unknown arg: $1" >&2
      usage >&2
      exit 2
      ;;
  esac
done

changed_files=()
if [[ ${#packages[@]} -eq 0 && $run_all -eq 0 ]]; then
  if [[ -z "$base_ref" ]]; then
    if upstream_ref=$(git -C "$ROOT_DIR" rev-parse --abbrev-ref --symbolic-full-name '@{upstream}' 2>/dev/null); then
      base_ref="$upstream_ref"
    elif git -C "$ROOT_DIR" rev-parse --verify origin/main >/dev/null 2>&1; then
      base_ref="origin/main"
    elif git -C "$ROOT_DIR" rev-parse --verify HEAD~1 >/dev/null 2>&1; then
      base_ref="HEAD~1"
    else
      base_ref="HEAD"
    fi
  fi

  range="$base_ref...$head_ref"
  while IFS= read -r file; do
    changed_files+=("$file")
  done < <(git -C "$ROOT_DIR" diff --name-only "$range" -- 'packages/pi-packages/**')

  if [[ ${#changed_files[@]} -gt 0 ]]; then
    for file in "${changed_files[@]}"; do
      if [[ "$file" =~ ^packages/pi-packages/(pi-[^/]+)/ ]]; then
        packages+=("${BASH_REMATCH[1]}")
      fi
    done
  fi
else
  while IFS= read -r file; do
    changed_files+=("$file")
  done < <(git -C "$ROOT_DIR" diff --name-only "${base_ref:-HEAD~1}...$head_ref" -- 'packages/pi-packages/**' 2>/dev/null || true)
fi

if [[ $run_all -eq 1 ]]; then
  while IFS= read -r package; do
    packages+=("$package")
  done < <(find "$ROOT_DIR/packages/pi-packages" -mindepth 1 -maxdepth 1 -type d -name 'pi-*' -exec basename {} \; | sort)
fi

if [[ ${#packages[@]} -eq 0 ]]; then
  echo "qa-changed: no packages/pi-packages changes detected"
  exit 0
fi

unique_packages=()
while IFS= read -r package; do
  unique_packages+=("$package")
done < <(
  if [[ ${#packages[@]} -gt 0 ]]; then
    printf '%s\n' "${packages[@]}" | sed '/^$/d' | sort -u
  fi
)
packages=()
if [[ ${#unique_packages[@]} -gt 0 ]]; then
  for package in "${unique_packages[@]}"; do
    packages+=("$package")
  done
fi

echo "qa-changed: checking packages: ${packages[*]}"

arch_files=()
if [[ ${#changed_files[@]} -gt 0 ]]; then
  for file in "${changed_files[@]}"; do
    if [[ -f "$ROOT_DIR/$file" && "$file" =~ ^packages/pi-packages/pi-[^/]+/.*\.tsx?$ ]]; then
      arch_files+=("$file")
    fi
  done
fi

if [[ ${#arch_files[@]} -gt 0 ]]; then
  ./bin/lint-ts-architecture "${arch_files[@]}"
else
  echo "qa-changed: no changed TypeScript files for architecture lint"
fi

if ! command -v bun >/dev/null 2>&1; then
  echo "error: bun is required for qa-changed" >&2
  exit 1
fi

if ! command -v jq >/dev/null 2>&1; then
  echo "error: jq is required for qa-changed" >&2
  exit 1
fi

existing_packages=()
removed_packages=()
if [[ ${#packages[@]} -gt 0 ]]; then
  for pkg in "${packages[@]}"; do
    if [[ -f "$ROOT_DIR/packages/pi-packages/$pkg/package.json" ]]; then
      existing_packages+=("$pkg")
    else
      removed_packages+=("$pkg")
    fi
  done
fi

if [[ ${#removed_packages[@]} -gt 0 ]]; then
  echo "qa-changed: skipping removed packages: ${removed_packages[*]}"
fi
packages=()
if [[ ${#existing_packages[@]} -gt 0 ]]; then
  for pkg in "${existing_packages[@]}"; do
    packages+=("$pkg")
  done
fi

run_integration=0
if [[ $run_all -eq 1 ]]; then
  run_integration=1
else
  if [[ ${#changed_files[@]} -gt 0 ]]; then
    for file in "${changed_files[@]}"; do
      if [[ "$file" == packages/pi-packages/tests/* || "$file" == packages/pi-packages/package.json ]]; then
        run_integration=1
        break
      fi
      if [[ "$file" == packages/pi-packages/bun.lock && ${#packages[@]} -gt 0 ]]; then
        run_integration=1
        break
      fi
    done
  fi
fi

if [[ ${#packages[@]} -eq 0 && $run_integration -eq 0 ]]; then
  echo "qa-changed: no remaining packages or integration tests to check"
  exit 0
fi

while IFS= read -r name; do
  unset "$name"
done < <(git -C "$ROOT_DIR" rev-parse --local-env-vars)

echo "qa-changed: ensuring workspace deps are installed"
symlinked_node_modules=()
while IFS= read -r -d '' link_path; do
  link_target="$(readlink "$link_path")"
  symlinked_node_modules+=("$link_path=$link_target")
  rm -f "$link_path"
done < <(find "$ROOT_DIR/packages/pi-packages" -mindepth 2 -maxdepth 2 -type l -name node_modules -print0)

restore_symlinked_node_modules() {
  local record link_path link_target
  if [[ ${#symlinked_node_modules[@]} -gt 0 ]]; then
    for record in "${symlinked_node_modules[@]}"; do
      link_path="${record%%=*}"
      link_target="${record#*=}"
      rm -rf "$link_path"
      ln -s "$link_target" "$link_path"
    done
  fi
}
trap restore_symlinked_node_modules EXIT

(
  cd "$ROOT_DIR/packages/pi-packages"
  bun install --frozen-lockfile --silent
)

has_script() {
  local pkg_json="$1/package.json"
  local script_name="$2"
  jq -e --arg script_name "$script_name" '.scripts[$script_name] != null' "$pkg_json" >/dev/null
}

if [[ ${#packages[@]} -gt 0 ]]; then
  for pkg in "${packages[@]}"; do
    pkg_dir="$ROOT_DIR/packages/pi-packages/$pkg"

    if has_script "$pkg_dir" typecheck; then
      echo "qa-changed: $pkg -> typecheck"
      (cd "$pkg_dir" && bun run --silent typecheck)
    fi

    if has_script "$pkg_dir" test; then
      echo "qa-changed: $pkg -> test"
      (cd "$pkg_dir" && bun run --silent test)
    fi
  done
fi


if [[ $run_integration -eq 1 ]]; then
  echo "qa-changed: running packages/pi-packages integration tests"
  (cd "$ROOT_DIR/packages/pi-packages" && bun run --silent test:integration)
fi

echo "qa-changed: done"
