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

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
AGENT_OPS_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
PROJECT_ROOT="$(cd "$AGENT_OPS_DIR/.." && pwd)"
WORKSPACE_ROOT="$(cd "$PROJECT_ROOT/.." && pwd)"
LOCKS_FILE="${AGENT_ROADMAP_LOCKS_FILE:-$WORKSPACE_ROOT/.agent-roadmap-sync/locks.yaml}"

usage() {
  cat <<'EOF'
Usage: roadmap-dependency-checker.sh <lock-id> [locks.yaml]
       roadmap-dependency-checker.sh --find-milestone <identity> [locked|rely-on|both] [locks.yaml]

Validates locked, rely-on.target, and rely-on.status for <lock-id>.
Prints true when every rely-on.status is enable.
Prints false when at least one rely-on.status is disable.
With --find-milestone, prints matching lock ids as locked:<id> or rely-on:<id>,
or none when the milestone identity is not referenced.

Exit codes:
  0  all dependencies are enabled
  1  at least one dependency is still disabled
  2  configuration, input, or parse error
For --find-milestone, exit code 0 means the lookup completed; stdout is either
matching entries or none.
EOF
}

if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
  usage
  exit 0
fi

MODE="check"
LOCK_ID=""
FIND_IDENTITY=""
FIND_DIRECTION="both"

if [[ "${1:-}" == "--find-milestone" ]]; then
  MODE="find"
  if [[ $# -lt 2 || $# -gt 4 ]]; then
    usage >&2
    exit 2
  fi
  FIND_IDENTITY="$2"
  if [[ -z "$FIND_IDENTITY" ]]; then
    echo "error: milestone identity is required" >&2
    exit 2
  fi
  if [[ $# -ge 3 ]]; then
    case "$3" in
      locked|rely-on|both)
        FIND_DIRECTION="$3"
        if [[ $# -eq 4 ]]; then
          LOCKS_FILE="$4"
        fi
        ;;
      *)
        if [[ $# -eq 3 ]]; then
          LOCKS_FILE="$3"
        else
          usage >&2
          exit 2
        fi
        ;;
    esac
  fi
elif [[ $# -lt 1 || $# -gt 2 ]]; then
  usage >&2
  exit 2
else
  LOCK_ID="$1"
  if [[ -n "${2:-}" ]]; then
    LOCKS_FILE="$2"
  fi
fi

if [[ "$MODE" == "check" && -z "$LOCK_ID" ]]; then
  echo "error: lock id is required" >&2
  exit 2
fi

if [[ ! -r "$LOCKS_FILE" ]]; then
  echo "error: locks file not readable: $LOCKS_FILE" >&2
  exit 2
fi

if [[ "$MODE" == "find" ]]; then
  awk -v identity="$FIND_IDENTITY" -v direction="$FIND_DIRECTION" '
function trim(value) {
  gsub(/\r/, "", value)
  sub(/^[[:space:]]+/, "", value)
  sub(/[[:space:]]+$/, "", value)
  return value
}

function unquote(value) {
  value = trim(value)
  sub(/[[:space:]]+#.*$/, "", value)
  value = trim(value)
  if (value ~ /^".*"$/ || value ~ /^'\''.*'\''$/) {
    return substr(value, 2, length(value) - 2)
  }
  return trim(value)
}

function reset_entry() {
  entry_id = ""
  locked = ""
  in_rely_on = 0
  rely_count = 0
  delete rely_targets
}

function finish_entry(   i) {
  if (entry_id == "") {
    return
  }
  if ((direction == "both" || direction == "locked") && locked == identity) {
    print "locked:" entry_id
    found = 1
  }
  if (direction == "both" || direction == "rely-on") {
    for (i = 1; i <= rely_count; i++) {
      if (rely_targets[i] == identity) {
        print "rely-on:" entry_id
        found = 1
        break
      }
    }
  }
}

BEGIN {
  found = 0
  reset_entry()
}

/^[[:space:]]*($|#)/ {
  next
}

/^[[:space:]]*-[[:space:]]*id:[[:space:]]*/ {
  finish_entry()
  reset_entry()
  value = $0
  sub(/^[[:space:]]*-[[:space:]]*id:[[:space:]]*/, "", value)
  entry_id = unquote(value)
  next
}

entry_id != "" && /^[[:space:]]*locked:[[:space:]]*/ {
  value = $0
  sub(/^[[:space:]]*locked:[[:space:]]*/, "", value)
  locked = unquote(value)
  next
}

entry_id != "" && /^[[:space:]]*rely-on:[[:space:]]*/ {
  in_rely_on = 1
  next
}

entry_id != "" && in_rely_on && /^[[:space:]]*-[[:space:]]*target:[[:space:]]*/ {
  value = $0
  sub(/^[[:space:]]*-[[:space:]]*target:[[:space:]]*/, "", value)
  rely_targets[++rely_count] = unquote(value)
  next
}

entry_id != "" && in_rely_on && /^[[:space:]]*target:[[:space:]]*/ {
  value = $0
  sub(/^[[:space:]]*target:[[:space:]]*/, "", value)
  rely_targets[++rely_count] = unquote(value)
  next
}

END {
  finish_entry()
  if (!found) {
    print "none"
  }
}
' "$LOCKS_FILE"
  exit 0
fi

awk -v wanted="$LOCK_ID" '
function trim(value) {
  gsub(/\r/, "", value)
  sub(/^[[:space:]]+/, "", value)
  sub(/[[:space:]]+$/, "", value)
  return value
}

function unquote(value) {
  value = trim(value)
  sub(/[[:space:]]+#.*$/, "", value)
  value = trim(value)
  if (value ~ /^".*"$/ || value ~ /^'\''.*'\''$/) {
    return substr(value, 2, length(value) - 2)
  }
  return trim(value)
}

function fail(message) {
  error = message
  printf "error: %s\n", error > "/dev/stderr"
  exit 2
}

function finish_dependency() {
  if (!selected || !in_dependency) {
    return
  }
  if (!dependency_has_target) {
    fail("missing rely-on.target for lock id: " wanted)
  }
  if (!dependency_has_status) {
    fail("missing rely-on.status for lock id: " wanted)
  }
  in_dependency = 0
}

function finish_entry() {
  if (!selected) {
    return
  }
  finish_dependency()
  if (!entry_has_locked) {
    fail("missing locked for lock id: " wanted)
  }
  if (total == 0) {
    fail("no rely-on.status entries for lock id: " wanted)
  }
  selected = 0
}

BEGIN {
  selected = 0
  matches = 0
  total = 0
  enabled = 0
  error = ""
  entry_has_locked = 0
  in_rely_on = 0
  in_dependency = 0
  dependency_has_target = 0
  dependency_has_status = 0
}

/^[[:space:]]*($|#)/ {
  next
}

/^[[:space:]]*-[[:space:]]*id:[[:space:]]*/ {
  finish_entry()
  value = $0
  sub(/^[[:space:]]*-[[:space:]]*id:[[:space:]]*/, "", value)
  id = unquote(value)
  if (id == wanted) {
    if (matches > 0) {
      fail("duplicate lock id: " wanted)
    }
    selected = 1
    matches++
    total = 0
    enabled = 0
    entry_has_locked = 0
    in_rely_on = 0
    in_dependency = 0
    dependency_has_target = 0
    dependency_has_status = 0
  }
  next
}

selected && /^[[:space:]]*locked:[[:space:]]*/ {
  value = $0
  sub(/^[[:space:]]*locked:[[:space:]]*/, "", value)
  locked = unquote(value)
  if (locked == "") {
    fail("empty locked for lock id: " wanted)
  }
  entry_has_locked = 1
  next
}

selected && /^[[:space:]]*rely-on:[[:space:]]*/ {
  in_rely_on = 1
  next
}

selected && in_rely_on && /^[[:space:]]*-[[:space:]]*target:[[:space:]]*/ {
  finish_dependency()
  in_dependency = 1
  dependency_has_target = 0
  dependency_has_status = 0
  value = $0
  sub(/^[[:space:]]*-[[:space:]]*target:[[:space:]]*/, "", value)
  target = unquote(value)
  if (target == "") {
    fail("empty rely-on.target for lock id: " wanted)
  }
  dependency_has_target = 1
  next
}

selected && in_rely_on && /^[[:space:]]*target:[[:space:]]*/ {
  if (!in_dependency) {
    fail("rely-on.target outside dependency item for lock id: " wanted)
  }
  value = $0
  sub(/^[[:space:]]*target:[[:space:]]*/, "", value)
  target = unquote(value)
  if (target == "") {
    fail("empty rely-on.target for lock id: " wanted)
  }
  dependency_has_target = 1
  next
}

selected && in_rely_on && /^[[:space:]]*status:[[:space:]]*/ {
  if (!in_dependency) {
    fail("rely-on.status outside dependency item for lock id: " wanted)
  }
  value = $0
  sub(/^[[:space:]]*status:[[:space:]]*/, "", value)
  status = unquote(value)
  if (status != "enable" && status != "disable") {
    fail("invalid rely-on.status for " wanted ": " status)
  }
  if (dependency_has_status) {
    fail("duplicate rely-on.status for lock id: " wanted)
  }
  dependency_has_status = 1
  total++
  if (status == "enable") {
    enabled++
  }
  next
}

selected && in_rely_on && /^[[:space:]]*-[[:space:]]*/ {
  finish_dependency()
  fail("missing rely-on.target for lock id: " wanted)
}

selected && /^[[:space:]]*status:[[:space:]]*/ {
  fail("status outside rely-on for lock id: " wanted)
}

END {
  if (error != "") {
    exit 2
  }
  if (matches == 0) {
    printf "error: lock id not found: %s\n", wanted > "/dev/stderr"
    exit 2
  }
  finish_entry()
  if (total == enabled) {
    print "true"
    exit 0
  }
  print "false"
  exit 1
}
' "$LOCKS_FILE"
