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

usage() {
  cat <<'USAGE'
Usage: install-workflow [--target DIR] [--force] [--github-labels]

Installs the AgentRail workflow templates into a project.

Options:
  --target DIR      Project directory to install into. Defaults to current directory.
  --force           Overwrite existing files.
  --github-labels   Create/update GitHub labels with gh CLI.
  -h, --help        Show this help.
USAGE
}

target_dir="$(pwd)"
force=0
github_labels=0

while [[ $# -gt 0 ]]; do
  case "$1" in
    --target)
      target_dir="${2:-}"
      [[ -n "$target_dir" && "$target_dir" != --* ]] || { echo "--target requires a directory" >&2; exit 2; }
      shift 2
      ;;
    --force)
      force=1
      shift
      ;;
    --github-labels)
      github_labels=1
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "Unknown option: $1" >&2
      usage >&2
      exit 2
      ;;
  esac
done

script_source="${BASH_SOURCE[0]}"
while [[ -L "$script_source" ]]; do
  script_dir="$(cd "$(dirname "$script_source")" && pwd)"
  script_source="$(readlink "$script_source")"
  [[ "$script_source" == /* ]] || script_source="${script_dir}/${script_source}"
done
script_dir="$(cd "$(dirname "$script_source")" && pwd)"
repo_dir="$(cd "${script_dir}/.." && pwd)"
templates_dir="${repo_dir}/templates"
skills_dir="${repo_dir}/skills"

[[ -d "$templates_dir" ]] || { echo "Missing templates directory: $templates_dir" >&2; exit 1; }
[[ -d "$skills_dir" ]] || { echo "Missing skills directory: $skills_dir" >&2; exit 1; }
command -v node >/dev/null 2>&1 || { echo "node is required to install AgentRail state" >&2; exit 1; }
mkdir -p "$target_dir"
state_manifest="$(mktemp)"
existing_before_manifest="$(mktemp)"
cleanup_state_temp() {
  rm -f "$state_manifest" "$existing_before_manifest"
}
trap cleanup_state_temp EXIT

copy_file() {
  local src_root="$1"
  local dest_root="$2"
  local src="$3"
  local inventory_prefix="$4"
  local rel="${src#"$src_root"/}"
  local dest="${dest_root}/${rel}"
  local inventory_path="${rel}"
  if [[ -n "$inventory_prefix" ]]; then
    inventory_path="${inventory_prefix}/${rel}"
  fi

  printf '%s\t%s\n' "$inventory_path" "$src" >>"$state_manifest"
  if [[ -e "$dest" ]]; then
    printf '%s\n' "$inventory_path" >>"$existing_before_manifest"
  fi

  mkdir -p "$(dirname "$dest")"

  if [[ -e "$dest" && "$force" -ne 1 ]]; then
    echo "skip existing: ${inventory_path}"
    return
  fi

  cp "$src" "$dest"
  echo "installed: ${inventory_path}"
}

should_skip_template() {
  local rel="$1"
  case "$rel" in
    scripts/*)                    return 0 ;;
    TASTE.md)                     return 0 ;;
    docs/memory/*)                return 0 ;;
    docs/prd/context-engine.md)   return 0 ;;
    .claude/agents/*)             return 0 ;;
    .codex/agents/*)              return 0 ;;
  esac
  return 1
}

copy_tree() {
  local src_root="$1"
  local dest_root="$2"
  local inventory_prefix="${3:-}"

  while IFS= read -r -d '' file; do
    local rel="${file#"$src_root"/}"
    if [[ -z "$inventory_prefix" ]] && should_skip_template "$rel"; then
      continue
    fi
    copy_file "$src_root" "$dest_root" "$file" "$inventory_prefix"
  done < <(find "$src_root" -type f -print0 | sort -z)
}

copy_tree "$templates_dir" "$target_dir"
copy_tree "$skills_dir" "${target_dir}/skills" "skills"
copy_file "$repo_dir" "$target_dir" "${repo_dir}/scripts/agentrail" ""

source_support_dir="${target_dir}/.agentrail/source"
if [[ "$(cd "$repo_dir" && pwd -P)" != "$(mkdir -p "$source_support_dir" && cd "$source_support_dir" && pwd -P)" ]]; then
  mkdir -p "${source_support_dir}/scripts"
  cp "${repo_dir}/package.json" "${source_support_dir}/package.json"
  cp "${repo_dir}/scripts/agentrail" "${source_support_dir}/scripts/agentrail"
  cp "${repo_dir}/scripts/agentrail-legacy" "${source_support_dir}/scripts/agentrail-legacy"
  cp "${repo_dir}/scripts/install-workflow" "${source_support_dir}/scripts/install-workflow"
  chmod +x "${source_support_dir}/scripts/agentrail" "${source_support_dir}/scripts/agentrail-legacy" "${source_support_dir}/scripts/install-workflow"
  rm -rf "${source_support_dir}/templates" "${source_support_dir}/skills" "${source_support_dir}/agentrail"
  cp -R "$templates_dir" "${source_support_dir}/templates"
  cp -R "$skills_dir" "${source_support_dir}/skills"
  cp -R "${repo_dir}/agentrail" "${source_support_dir}/agentrail"
fi

write_agentrail_state() {
  AGENTRAIL_REPO_DIR="$repo_dir" \
  AGENTRAIL_TARGET_DIR="$target_dir" \
  AGENTRAIL_STATE_MANIFEST="$state_manifest" \
  AGENTRAIL_EXISTING_BEFORE_MANIFEST="$existing_before_manifest" \
  AGENTRAIL_FORCE="$force" \
  node <<'NODE'
const fs = require("fs");
const path = require("path");
const crypto = require("crypto");

const repoDir = process.env.AGENTRAIL_REPO_DIR;
const targetDir = process.env.AGENTRAIL_TARGET_DIR;
const manifestPath = process.env.AGENTRAIL_STATE_MANIFEST;
const existingBeforePath = process.env.AGENTRAIL_EXISTING_BEFORE_MANIFEST;
const force = process.env.AGENTRAIL_FORCE === "1";
const stateDir = path.join(targetDir, ".agentrail");
const statePath = path.join(stateDir, "state.json");
const packageJson = JSON.parse(fs.readFileSync(path.join(repoDir, "package.json"), "utf8"));

function readJsonIfPresent(file) {
  try {
    return JSON.parse(fs.readFileSync(file, "utf8"));
  } catch (error) {
    if (error.code === "ENOENT") return null;
    throw error;
  }
}

function sha256(file) {
  return `sha256:${crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex")}`;
}

const previousState = readJsonIfPresent(statePath);
const now = new Date().toISOString();
const existingBefore = new Set(
  fs.readFileSync(existingBeforePath, "utf8")
    .split(/\r?\n/)
    .filter(Boolean)
);

const managedFiles = fs.readFileSync(manifestPath, "utf8")
  .split(/\r?\n/)
  .filter(Boolean)
  .map((line) => {
    const [relativePath, sourcePath] = line.split("\t");
    const targetPath = path.join(targetDir, relativePath);
    const existedBefore = existingBefore.has(relativePath);
    let installStatus = "installed";
    if (existedBefore && previousState) installStatus = force ? "updated" : "preserved";
    if (existedBefore && !previousState) installStatus = force ? "updated" : "legacy-adopted";

    return {
      path: relativePath,
      source: path.relative(repoDir, sourcePath),
      contentHash: sha256(targetPath),
      installStatus,
    };
  });

const defaultWorkflow = {
  phase: "idle",
  activePhase: null,
  activeIssue: null,
  activePullRequest: null,
  activePrd: null,
  activeMilestone: null,
  activeRun: null,
  completedRuns: [],
  goals: [],
  worktrees: [],
  lastCompletedStep: null,
  nextSuggestedAction: "Pick a ready-for-agent issue or create a PRD/milestone before starting implementation.",
};

const state = {
  schemaVersion: 1,
  agentrailVersion: packageJson.version,
  installedAt: previousState?.installedAt || now,
  updatedAt: now,
  legacyAdopted: Boolean(previousState?.legacyAdopted || (!previousState && existingBefore.size > 0)),
  managedFiles,
  workflow: {
    ...defaultWorkflow,
    ...(previousState?.workflow || {}),
    completedRuns: Array.isArray(previousState?.workflow?.completedRuns) ? previousState.workflow.completedRuns : [],
    goals: Array.isArray(previousState?.workflow?.goals) ? previousState.workflow.goals : [],
    worktrees: Array.isArray(previousState?.workflow?.worktrees) ? previousState.workflow.worktrees : [],
  },
};

fs.mkdirSync(stateDir, { recursive: true });
fs.writeFileSync(statePath, `${JSON.stringify(state, null, 2)}\n`);
console.log("updated: .agentrail/state.json");
NODE
}

write_agentrail_state

config_file="${target_dir}/.agentrail/config.json"
if [[ ! -e "$config_file" || "$force" -eq 1 ]]; then
  mkdir -p "$(dirname "$config_file")"
  cat >"$config_file" <<'JSON'
{
  "schemaVersion": 1,
  "runner": {
    "name": "codex",
    "command": "codex exec --sandbox danger-full-access -"
  },
  "context": {
    "includeGlobs": ["**/*"],
    "excludeGlobs": [
      ".git/**",
      "node_modules/**",
      "dist/**",
      "build/**",
      ".next/**",
      "target/**",
      "coverage/**",
      ".cache/**",
      ".turbo/**",
      ".agentrail/context/**",
      ".agentrail/source/**",
      ".env",
      ".env.*",
      "**/.env",
      "**/.env.*",
      "**/*.pem",
      "**/*.key",
      "**/*credentials*",
      "**/*secret*"
    ],
    "maxFileSizeBytes": 262144,
    "skipBinary": true,
    "respectGitIgnore": true,
    "secretRedaction": {
      "enabled": true,
      "action": "exclude",
      "denyGlobs": [
        ".env",
        ".env.*",
        "**/.env",
        "**/.env.*",
        "**/*.pem",
        "**/*.key",
        "**/*credentials*",
        "**/*secret*"
      ]
    },
    "embedding": {
      "mode": "disabled",
      "provider": null,
      "model": null
    },
    "summary": {
      "mode": "disabled",
      "provider": null,
      "model": null
    },
    "externalSources": []
  }
}
JSON
  echo "updated: .agentrail/config.json"
fi

if [[ "$github_labels" -eq 1 ]]; then
  if ! command -v gh >/dev/null 2>&1; then
    echo "gh CLI is not installed; skipping labels" >&2
    exit 0
  fi

  (
    cd "$target_dir"
    gh label create ready-for-agent --color 0E8A16 --description "Fully specified, ready for an agent to implement." --force
    gh label create afk --color 5319E7 --description "Approved for unattended AFK agent execution." --force
    gh label create afk-in-progress --color BFDADC --description "Currently claimed by AFK workflow." --force
    gh label create review-fix --color D93F0B --description "Follow-up issue created from PR review." --force
    gh label create memory-suggestion --color FBCA04 --description "Suggested project memory update for human review." --force
    gh label create pr-reviewed --color 1D76DB --description "Implementation PR has been reviewed." --force
  )
fi

echo
echo "AgentRail installed in: ${target_dir}"
echo
echo "Next steps:"
echo "  1. Start with a grilling session to define your project context:"
echo "     cd ${target_dir} && agentrail grill"
echo "     (or use /grill inside Claude Code or Codex)"
echo "  2. The grill will create CONTEXT.md and sharpen your domain language."
echo "  3. Then create issues and run: agentrail run issue NUMBER --agent claude"
