#!/usr/bin/env bash

# Append one redacted-but-otherwise-verbatim question/answer pair to a
# person/day Markdown archive and optionally push the archive paths to Codeup.

set -euo pipefail

for required_command in git rg date dirname tr mkdir cat; do
  if ! command -v "$required_command" >/dev/null 2>&1; then
    printf 'ERROR: required command not found: %s. Install it and ensure it is available in PATH.\n' "$required_command" >&2
    exit 127
  fi
done

usage() {
  printf '%s\n' "Usage: ${0##*/} (--question-file <question.md> --answer-file <answer.md> | --entry-file <preformatted-qa.md>) [--knowledge-file <knowledge.md>] [--skill-candidate-file <candidate.md>] [--date YYYY-MM-DD] [--push] [--dry-run]"
}

person=""
entry_file=""
question_file=""
answer_file=""
knowledge_file=""
skill_file=""
archive_date="$(date +%F)"
push=false
dry_run=false

while (($#)); do
  case "$1" in
    --entry-file) entry_file="${2:-}"; shift 2 ;;
    --question-file) question_file="${2:-}"; shift 2 ;;
    --answer-file) answer_file="${2:-}"; shift 2 ;;
    --knowledge-file) knowledge_file="${2:-}"; shift 2 ;;
    --skill-candidate-file) skill_file="${2:-}"; shift 2 ;;
    --date) archive_date="${2:-}"; shift 2 ;;
    --push) push=true; shift ;;
    --dry-run) dry_run=true; shift ;;
    -h|--help) usage; exit 0 ;;
    *) usage >&2; exit 2 ;;
  esac
done

if [[ -n "$entry_file" && ( -n "$question_file" || -n "$answer_file" ) ]]; then
  printf 'ERROR: use either --entry-file or the --question-file/--answer-file pair, not both.\n' >&2
  usage >&2
  exit 2
fi

if [[ -n "$entry_file" ]]; then
  if [[ ! -s "$entry_file" ]]; then
    printf 'ERROR: preformatted Q&A file is missing or empty: %s\n' "$entry_file" >&2
    exit 2
  fi
  if ! rg -q '^### 问[[:space:]]*$' "$entry_file" || ! rg -q '^### 答[[:space:]]*$' "$entry_file"; then
    printf 'ERROR: --entry-file must preserve the original exchange with both "### 问" and "### 答" headings; summaries are not accepted.\n' >&2
    exit 2
  fi
elif [[ -n "$question_file" || -n "$answer_file" ]]; then
  if [[ -z "$question_file" || -z "$answer_file" ]]; then
    printf 'ERROR: --question-file and --answer-file must be supplied together.\n' >&2
    exit 2
  fi
  if [[ ! -s "$question_file" || ! -s "$answer_file" ]]; then
    printf 'ERROR: question and answer files must both exist and be non-empty.\n' >&2
    exit 2
  fi
else
  usage >&2
  exit 2
fi

if [[ ! "$archive_date" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then
  printf 'ERROR: date must use YYYY-MM-DD: %s\n' "$archive_date" >&2
  exit 2
fi

for optional_file in "$knowledge_file" "$skill_file"; do
  if [[ -n "$optional_file" && ! -f "$optional_file" ]]; then
    printf 'ERROR: input file not found: %s\n' "$optional_file" >&2
    exit 2
  fi
done

for candidate in "$entry_file" "$question_file" "$answer_file" "$knowledge_file" "$skill_file"; do
  if [[ -n "$candidate" ]] && rg -n -i 'accesskeysecret|x-yunxiao-token|begin [a-z ]*private key|cookie:|set-cookie:|authorization: bearer' "$candidate" >/dev/null; then
    printf 'ERROR: possible credential detected; redact it before archiving: %s\n' "$candidate" >&2
    exit 1
  fi
done

repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
person="$(git -C "$repo_root" config --get research-institute.archivePerson || true)"
if [[ -z "$person" ]]; then
  person="$(git -C "$repo_root" config --get user.name || true)"
fi
if [[ -z "$person" ]]; then
  printf 'ERROR: collaborator identity is missing; run the collaborator bootstrap or set Git user.name.\n' >&2
  exit 1
fi
person_slug="$(printf '%s' "$person" | LC_ALL=C tr -cs 'A-Za-z0-9._-' '-')"
person_slug="${person_slug#-}"
person_slug="${person_slug%-}"
person_slug="${person_slug:-person}"
day_key="${person_slug}-${archive_date}"
archive_dir="$repo_root/archives/daily/$day_key"
knowledge_dir="$repo_root/knowledge/daily/$day_key"
skill_dir="$repo_root/skill-candidates/daily/$day_key"
qa_target="$archive_dir/$day_key.md"
knowledge_target="$knowledge_dir/knowledge.md"
skill_target="$skill_dir/skill-candidates.md"
timestamp="$(date '+%F %T %Z')"

if [[ "$dry_run" == true ]]; then
  input_mode="question-answer-files"
  [[ -n "$entry_file" ]] && input_mode="preformatted-entry"
  printf 'DRY_RUN_OK person=%s mode=%s qa=%s knowledge=%s skill_candidates=%s\n' "$person" "$input_mode" "$qa_target" "$knowledge_target" "$skill_target"
  exit 0
fi

append_record() {
  local target="$1"
  local heading="$2"
  local source="$3"
  local intro="$4"

  mkdir -p "$(dirname "$target")"
  if [[ ! -f "$target" ]]; then
    printf '# %s\n\n%s\n' "$heading" "$intro" > "$target"
  fi
  printf '\n## %s\n\n' "$timestamp" >> "$target"
  cat "$source" >> "$target"
  printf '\n' >> "$target"
}

append_qa_record() {
  local target="$1"
  local sequence=1

  mkdir -p "$(dirname "$target")"
  if [[ ! -f "$target" ]]; then
    printf '# %s 原始问答归档 — %s\n\n' "$person" "$archive_date" > "$target"
    printf '按发生顺序保留完整的一问一答；除必要的凭据、隐私和敏感信息脱敏外，不使用摘要替代原文。\n' >> "$target"
  else
    sequence="$(rg -c '^## 问答 [0-9]+ — ' "$target" || true)"
    sequence="${sequence:-0}"
    sequence=$((sequence + 1))
  fi

  printf '\n## 问答 %s — %s\n\n' "$sequence" "$timestamp" >> "$target"
  if [[ -n "$entry_file" ]]; then
    cat "$entry_file" >> "$target"
    printf '\n' >> "$target"
    return
  fi

  printf '### 问\n\n' >> "$target"
  cat "$question_file" >> "$target"
  printf '\n\n### 答\n\n' >> "$target"
  cat "$answer_file" >> "$target"
  printf '\n' >> "$target"
}

append_qa_record "$qa_target"

if [[ -n "$knowledge_file" ]]; then
  append_record "$knowledge_target" "$person Knowledge — $archive_date" "$knowledge_file" 'Verified or reviewable knowledge extracted from Q&A.'
fi

if [[ -n "$skill_file" ]]; then
  append_record "$skill_target" "$person Skill Candidates — $archive_date" "$skill_file" 'Candidates only; human review is required before promotion to skills/.'
fi

printf 'ARCHIVE_OK format=verbatim-qa qa=%s\n' "$qa_target"
[[ -n "$knowledge_file" ]] && printf 'KNOWLEDGE_OK path=%s\n' "$knowledge_target"
[[ -n "$skill_file" ]] && printf 'SKILL_CANDIDATE_OK path=%s\n' "$skill_target"

if [[ "$push" == true ]]; then
  git -C "$repo_root" add -- "$archive_dir"
  [[ -d "$knowledge_dir" ]] && git -C "$repo_root" add -- "$knowledge_dir"
  [[ -d "$skill_dir" ]] && git -C "$repo_root" add -- "$skill_dir"

  if git -C "$repo_root" diff --cached --quiet; then
    printf 'PUSH_SKIPPED no archive changes to commit\n'
    exit 0
  fi

  git -C "$repo_root" commit -m "docs: archive ${person_slug} Q&A ${archive_date}"
  if ! git -C "$repo_root" push origin HEAD:master; then
    printf 'PUSH_RETRY remote master changed; checking whether a safe merge is possible.\n' >&2
    if ! git -C "$repo_root" diff --quiet || ! git -C "$repo_root" diff --cached --quiet; then
      printf 'ERROR: archive commit is preserved locally, but tracked worktree changes prevent an automatic remote merge. Commit or resolve them, then push again.\n' >&2
      exit 1
    fi
    git -C "$repo_root" fetch origin master
    if ! git -C "$repo_root" merge --no-edit origin/master; then
      printf 'ERROR: archive commit is preserved locally, but the remote merge conflicted. Resolve the conflict without discarding either collaborator archive, then push again.\n' >&2
      exit 1
    fi
    git -C "$repo_root" push origin HEAD:master
  fi
  printf 'PUSH_OK remote=origin branch=master\n'
fi
