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

readonly staging_prefix=".agent-sidecar-tmp-agent-codex-seed-"
readonly global_seed_name="__global__"
active_staging_path=""

fail() {
  echo "agent-codex: $*" >&2
  exit 1
}

cleanup_active_staging_path() {
  if [[ -n "$active_staging_path" && ( -e "$active_staging_path" || -L "$active_staging_path" ) ]]; then
    rm -rf -- "$active_staging_path"
  fi
}

validate_seed_name() {
  local kind="$1"
  local name="$2"

  if [[ ! "$name" =~ ^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$ ]]; then
    fail "invalid $kind seed name: $name"
  fi
}

validate_source_tree() {
  local kind="$1"
  local source_dir="$2"
  local invalid_entry

  invalid_entry="$(find "$source_dir" -mindepth 1 ! -type d ! -type f -print -quit)"
  if [[ -n "$invalid_entry" ]]; then
    fail "$kind seed contains a symlink or special file: $invalid_entry"
  fi
}

cleanup_staging_directories() {
  local root="$1"
  local pattern="$2"
  local entry

  while IFS= read -r -d '' entry; do
    rm -rf -- "$entry"
  done < <(find "$root" -mindepth 1 -maxdepth 1 -type d -name "$pattern" -print0)
}

cleanup_staging_files() {
  local root="$1"
  local pattern="$2"
  local entry

  while IFS= read -r -d '' entry; do
    rm -f -- "$entry"
  done < <(find "$root" -mindepth 1 -maxdepth 1 -type f -name "$pattern" -print0)
}

seed_directory() {
  local kind="$1"
  local name="$2"
  local source_dir="$3"
  local destination_dir="$4"
  local staging_root="$5"
  local staging_name="$6"

  if [[ -L "$destination_dir" ]]; then
    fail "$kind seed destination is a symlink: $destination_dir"
  fi
  if [[ -e "$destination_dir" ]]; then
    if [[ ! -d "$destination_dir" ]]; then
      fail "$kind seed destination is not a directory: $destination_dir"
    fi
    echo "agent-codex: $kind already exists, skipping seed: $name"
    return
  fi

  active_staging_path="$(mktemp -d -- "$staging_root/${staging_name}.XXXXXX")"
  cp -a -- "$source_dir/." "$active_staging_path/"
  if [[ "$kind" == "project" ]]; then
    git init --quiet --initial-branch=main -- "$active_staging_path"
  fi
  mv --no-clobber --no-target-directory -- "$active_staging_path" "$destination_dir"

  if [[ -e "$active_staging_path" ]]; then
    if [[ -L "$destination_dir" || ! -d "$destination_dir" ]]; then
      fail "$kind seed destination became invalid while seeding: $destination_dir"
    fi
    rm -rf -- "$active_staging_path"
    active_staging_path=""
    echo "agent-codex: $kind already exists, skipping seed: $name"
    return
  fi

  active_staging_path=""
  echo "agent-codex: seeded $kind: $name"
}

seed_project() {
  local source_dir="$1"
  local projects_root="$2"
  local project_name="${source_dir##*/}"

  validate_seed_name "project" "$project_name"
  validate_source_tree "project" "$source_dir"
  seed_directory \
    "project" \
    "$project_name" \
    "$source_dir" \
    "$projects_root/$project_name" \
    "$projects_root" \
    "${staging_prefix}${project_name}"
}

validate_global_source() {
  local global_seed_dir="$1"
  local skills_seed_dir="$global_seed_dir/skills"
  local entry
  local entry_name

  while IFS= read -r -d '' entry; do
    entry_name="${entry##*/}"
    case "$entry_name" in
      AGENTS.md)
        if [[ -L "$entry" || ! -f "$entry" ]]; then
          fail "global AGENTS.md seed is not a normal file: $entry"
        fi
        ;;
      skills)
        if [[ -L "$entry" || ! -d "$entry" ]]; then
          fail "global skills seed is not a normal directory: $entry"
        fi
        ;;
      *)
        fail "global seed contains an unsupported entry: $entry"
        ;;
    esac
  done < <(find "$global_seed_dir" -mindepth 1 -maxdepth 1 -print0 | sort -z)

  if [[ ! -e "$skills_seed_dir" ]]; then
    return
  fi

  while IFS= read -r -d '' entry; do
    entry_name="${entry##*/}"
    if [[ -L "$entry" || ! -d "$entry" ]]; then
      fail "global skills seed contains a non-directory entry: $entry"
    fi
    validate_seed_name "global skill" "$entry_name"
    validate_source_tree "global skill" "$entry"
    if [[ -z "$(find "$entry" -type f -name SKILL.md -print -quit)" ]]; then
      fail "global skill seed contains no normal SKILL.md: $entry"
    fi
  done < <(find "$skills_seed_dir" -mindepth 1 -maxdepth 1 -print0 | sort -z)
}

seed_global_agents() {
  local source_file="$1"
  local codex_home="$2"
  local destination_file="$codex_home/AGENTS.md"

  if [[ -L "$destination_file" ]]; then
    fail "global AGENTS.md seed destination is a symlink: $destination_file"
  fi
  if [[ -e "$destination_file" ]]; then
    if [[ ! -f "$destination_file" ]]; then
      fail "global AGENTS.md seed destination is not a regular file: $destination_file"
    fi
    echo "agent-codex: global AGENTS.md already exists, skipping seed"
    return
  fi

  active_staging_path="$(mktemp -- "$codex_home/${staging_prefix}global-AGENTS.md.XXXXXX")"
  cp -a -- "$source_file" "$active_staging_path"
  mv --no-clobber --no-target-directory -- "$active_staging_path" "$destination_file"

  if [[ -e "$active_staging_path" ]]; then
    if [[ -L "$destination_file" || ! -f "$destination_file" ]]; then
      fail "global AGENTS.md seed destination became invalid while seeding: $destination_file"
    fi
    rm -f -- "$active_staging_path"
    active_staging_path=""
    echo "agent-codex: global AGENTS.md already exists, skipping seed"
    return
  fi

  active_staging_path=""
  echo "agent-codex: seeded global AGENTS.md"
}

seed_global() {
  local global_seed_dir="$1"
  local codex_home="$2"
  local skills_root="$codex_home/skills"
  local entry
  local skill_name

  validate_global_source "$global_seed_dir"

  if [[ -f "$global_seed_dir/AGENTS.md" ]]; then
    seed_global_agents "$global_seed_dir/AGENTS.md" "$codex_home"
  fi

  if [[ ! -d "$global_seed_dir/skills" ]]; then
    return
  fi

  while IFS= read -r -d '' entry; do
    skill_name="${entry##*/}"
    # Seed each top-level skill or group atomically, preserving nested paths.
    seed_directory \
      "global skill" \
      "$skill_name" \
      "$entry" \
      "$skills_root/$skill_name" \
      "$skills_root" \
      "${staging_prefix}global-skill-${skill_name}"
  done < <(find "$global_seed_dir/skills" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z)
}

main() {
  if [[ "$#" -ne 3 ]]; then
    fail "usage: agent-codex-seed-projects PROJECT_SEEDS_DIR PROJECTS_ROOT_DIR CODEX_HOME_DIR"
  fi

  local project_seeds_dir="${1%/}"
  local projects_root="${2%/}"
  local codex_home="${3%/}"
  local skills_root="$codex_home/skills"
  local global_seed_dir="$project_seeds_dir/$global_seed_name"
  local lock_file
  local entry

  if [[ ! -d "$project_seeds_dir" || -L "$project_seeds_dir" ]]; then
    fail "project seeds directory is not a normal directory: $project_seeds_dir"
  fi
  if [[ ! -d "$projects_root" || -L "$projects_root" ]]; then
    fail "projects root is not a normal directory: $projects_root"
  fi
  if [[ ! -d "$codex_home" || -L "$codex_home" ]]; then
    fail "Codex home is not a normal directory: $codex_home"
  fi
  if [[ -L "$skills_root" || ( -e "$skills_root" && ! -d "$skills_root" ) ]]; then
    fail "global skills root is not a normal directory: $skills_root"
  fi
  mkdir -p -- "$skills_root"

  lock_file="$projects_root/${staging_prefix}lock"
  if [[ -L "$lock_file" || ( -e "$lock_file" && ! -f "$lock_file" ) ]]; then
    fail "project seed lock is not a normal file: $lock_file"
  fi
  exec {lock_fd}>"$lock_file"
  flock "$lock_fd"

  cleanup_staging_directories "$projects_root" "${staging_prefix}*"
  cleanup_staging_files "$codex_home" "${staging_prefix}global-AGENTS.md.*"
  cleanup_staging_directories "$skills_root" "${staging_prefix}global-skill-*"

  if [[ -L "$global_seed_dir" ]]; then
    fail "global seed is a symlink: $global_seed_dir"
  fi
  if [[ -e "$global_seed_dir" ]]; then
    if [[ ! -d "$global_seed_dir" ]]; then
      fail "global seed is not a normal directory: $global_seed_dir"
    fi
    seed_global "$global_seed_dir" "$codex_home"
  fi

  while IFS= read -r -d '' entry; do
    if [[ "${entry##*/}" == "$global_seed_name" ]]; then
      continue
    fi
    if [[ -L "$entry" ]]; then
      fail "project seeds directory contains a symlink: $entry"
    fi
    if [[ -d "$entry" ]]; then
      seed_project "$entry" "$projects_root"
      continue
    fi
    if [[ ! -f "$entry" ]]; then
      fail "project seeds directory contains a special file: $entry"
    fi
  done < <(find "$project_seeds_dir" -mindepth 1 -maxdepth 1 -print0 | sort -z)
}

trap cleanup_active_staging_path EXIT
main "$@"
