#!/usr/bin/env bash

_force_overwrite_enabled() {
  [[ "${VIBEGUARD_SETUP_FORCE_OVERWRITE:-0}" == "1" ]]
}

_protect_rule_file_overwrite() {
  local src="$1" dest="$2" label="$3"
  [[ -e "${dest}" && ! -L "${dest}" ]] || return 0

  if [[ -f "${src}" ]] && cmp -s "${src}" "${dest}"; then
    rm -f "${dest}"
    return 0
  fi

  if _force_overwrite_enabled; then
    yellow "  FORCE: replacing local rule copy ${dest}"
    rm -f "${dest}"
    return 0
  fi

  red "  ERROR: refusing to overwrite modified local rule file: ${dest}"
  red "  Re-run with --force-overwrite only if this local ${label} rule copy should be replaced."
  return 1
}

_remove_rule_subtree_if_safe() {
  local src_dir="$1" dest_dir="$2" label="$3"
  [[ -d "${dest_dir}" ]] || return 0

  local file rel src_file
  while IFS= read -r file; do
    [[ -e "${file}" || -L "${file}" ]] || continue
    [[ -L "${file}" ]] && continue
    rel="${file#"${dest_dir}/"}"
    src_file="${src_dir}/${rel}"
    if [[ -f "${src_file}" ]] && cmp -s "${src_file}" "${file}"; then
      continue
    fi
    if _force_overwrite_enabled; then
      continue
    fi
    red "  ERROR: refusing to remove modified local rule file: ${file}"
    red "  Re-run with --force-overwrite only if this local ${label} rule tree should be replaced."
    return 1
  done < <(find "${dest_dir}" \( -type f -o -type l \) 2>/dev/null)

  rm -rf "${dest_dir}"
}

_install_claude_skill_link() {
  local src="$1" dst="$2" source_path="$3" skill="$4"
  safe_symlink "${src}" "${dst}"
  state_record_file "${dst}" "${source_path}" "symlink"
  green "  ${skill} -> ~/.claude/skills/${skill}"
}

install_claude_home_assets() {
  echo "Step 2: Install Claude Code skills"
  install_manifest_skills "~/.claude/skills/" "${CLAUDE_DIR}/skills" _install_claude_skill_link || return 1
  echo

  echo "Step 3: Install agents"
  mkdir -p "${CLAUDE_DIR}/agents"
  for agent in "${REPO_DIR}"/agents/*.md; do
    [[ -f "$agent" ]] || continue
    local name
    name=$(basename "$agent")
    rm -f "${CLAUDE_DIR}/agents/${name}"
    cp "$agent" "${CLAUDE_DIR}/agents/${name}"
    state_record_file "${CLAUDE_DIR}/agents/${name}" "agents/${name}" "copy"
    green "  ${name} -> ~/.claude/agents/${name}"
  done
  echo

  echo "Step 4: Install context profiles"
  install_context_profiles "${CLAUDE_DIR}/context-profiles" "~/.claude/context-profiles"
  echo

  echo "Step 5: Install custom commands"
  mkdir -p "${CLAUDE_DIR}/commands"
  safe_symlink "${REPO_DIR}/.claude/commands/vibeguard" "${CLAUDE_DIR}/commands/vibeguard"
  state_record_file "${CLAUDE_DIR}/commands/vibeguard" ".claude/commands/vibeguard" "symlink"
  green "  vibeguard commands -> ~/.claude/commands/vibeguard"
  echo

  echo "Step 5.5: Install native rules (symlinked)"
  local rules_src="${REPO_DIR}/rules/claude-rules"
  local rules_dest="${HOME}/.claude/rules/vibeguard"
  if [[ -d "${rules_src}" ]]; then
    mkdir -p "${rules_dest}"
    # Helper: symlink each .md file in a subdirectory
    _symlink_rule_dir() {
      local src_dir="$1" dest_dir="$2" label="$3"
      mkdir -p "${dest_dir}"
      # Remove only safe stale copies that are now replaced by symlinks.
      for f in "${dest_dir}"/*.md; do
        [[ -f "$f" && ! -L "$f" ]] || continue
        local stale_name stale_src
        stale_name=$(basename "$f")
        stale_src="${src_dir}/${stale_name}"
        if [[ -f "${stale_src}" ]]; then
          _protect_rule_file_overwrite "${stale_src}" "$f" "${label}" || return 1
        elif _force_overwrite_enabled; then
          yellow "  FORCE: removing stale local rule copy ${f}"
          rm -f "$f"
        else
          red "  ERROR: refusing to remove local rule file not present in source: ${f}"
          red "  Re-run with --force-overwrite only if this local ${label} rule copy should be removed."
          return 1
        fi
      done
      local count=0
      for f in "${src_dir}"/*.md; do
        [[ -f "$f" ]] || continue
        local name
        name=$(basename "$f")
        _protect_rule_file_overwrite "$f" "${dest_dir}/${name}" "${label}" || return 1
        ln -sf "$f" "${dest_dir}/${name}"
        state_record_file "${dest_dir}/${name}" "${label}/${name}" "symlink"
        count=$((count + 1))
      done
      green "  ${label}/ -> ~/.claude/rules/vibeguard/${label}/ (${count} rules, symlinked)"
    }
    if [[ -d "${rules_src}/common" ]]; then
      _symlink_rule_dir "${rules_src}/common" "${rules_dest}/common" "common"
    fi
    for subdir in rust golang typescript python; do
      if [[ -d "${rules_src}/${subdir}" ]]; then
        if lang_selected "$subdir"; then
          _symlink_rule_dir "${rules_src}/${subdir}" "${rules_dest}/${subdir}" "${subdir}"
        else
          if [[ -d "${rules_dest}/${subdir}" ]]; then
            _remove_rule_subtree_if_safe "${rules_src}/${subdir}" "${rules_dest}/${subdir}" "${subdir}" || return 1
            yellow "  ${subdir}/ removed (not in --languages filter)"
          else
            yellow "  SKIP ${subdir}/ (not in --languages filter)"
          fi
        fi
      fi
    done
    if [[ -d "${VIBEGUARD_HOME}/user-rules" ]]; then
      local local_rules_count
      local_rules_count=$(find "${VIBEGUARD_HOME}/user-rules" -name "*.md" 2>/dev/null | wc -l | tr -d ' ')
      if [[ "${local_rules_count}" -gt 0 ]]; then
        mkdir -p "${rules_dest}/custom"
        for f in "${VIBEGUARD_HOME}/user-rules/"*.md; do
          [[ -f "$f" ]] || continue
          ln -sf "$f" "${rules_dest}/custom/$(basename "$f")"
        done
        state_record_tree "${rules_dest}/custom" "user-rules"
        green "  custom/ -> ~/.claude/rules/vibeguard/custom/ (${local_rules_count} user rules, symlinked)"
      fi
    fi
    unset -f _symlink_rule_dir
  else
    yellow "  SKIP native rules (source not found: ${rules_src})"
  fi
  echo
}

claude_rule_id_count() {
  local root="$1"
  local total=0 file_count rule_file
  if [[ ! -d "${root}" ]]; then
    printf '0\n'
    return 0
  fi
  while IFS= read -r rule_file; do
    file_count=$(grep -cE '^## [A-Z]+-[0-9]+' "${rule_file}" 2>/dev/null || true)
    total=$((total + file_count))
  done < <(find "${root}" \( -type f -o -type l \) -name "*.md" 2>/dev/null)
  printf '%s\n' "${total}"
}

claude_rule_count_for_banner() {
  local rules_dest="${HOME}/.claude/rules/vibeguard"
  local rules_src="${REPO_DIR}/rules/claude-rules"
  local total=0 dir_count subdir

  if [[ "${VIBEGUARD_SETUP_DRY_RUN}" != "1" && -d "${rules_dest}" ]]; then
    claude_rule_id_count "${rules_dest}"
    return 0
  fi

  if [[ -d "${rules_src}/common" ]]; then
    dir_count=$(claude_rule_id_count "${rules_src}/common")
    total=$((total + dir_count))
  fi
  for subdir in rust golang typescript python; do
    if [[ -d "${rules_src}/${subdir}" ]]; then
      if ! declare -F lang_selected >/dev/null || lang_selected "${subdir}"; then
        dir_count=$(claude_rule_id_count "${rules_src}/${subdir}")
        total=$((total + dir_count))
      fi
    fi
  done
  if [[ -d "${HOME}/.vibeguard/user-rules" ]]; then
    dir_count=$(claude_rule_id_count "${HOME}/.vibeguard/user-rules")
    total=$((total + dir_count))
  fi
  printf '%s\n' "${total}"
}

configure_claude_home_runtime() {
  echo "Step 9: Configure Claude hooks (${PROFILE} profile)"
  local settings_diff
  if ! settings_diff=$(settings_upsert_diff "${SETTINGS_FILE}" "${PROFILE}" 2>&1); then
    red "  Failed to compute settings.json diff"
    return 1
  fi
  if ! confirm_high_context_write "~/.claude/settings.json" "${settings_diff}"; then
    if [[ "${VIBEGUARD_SETUP_DRY_RUN}" == "1" ]]; then
      echo
      return 0
    fi
    return 1
  fi
  if settings_upsert "${SETTINGS_FILE}" "${PROFILE}" >/dev/null; then
    state_record_file "${SETTINGS_FILE}" "generated/settings.json" "copy"
    green "  Hooks configured in ~/.claude/settings.json (${PROFILE})"
  else
    red "  Failed to configure settings.json"
  fi
  echo
}

inject_claude_home_rules() {
  echo "Step 10: Update VibeGuard rules in CLAUDE.md"
  inject_vibeguard_rules "${CLAUDE_DIR}/CLAUDE.md" "~/.claude/CLAUDE.md" "generated/CLAUDE.md"
}

check_claude_home_installation() {
  if [[ -f "${CLAUDE_DIR}/CLAUDE.md" ]] && grep -q "VibeGuard" "${CLAUDE_DIR}/CLAUDE.md" 2>/dev/null; then
    green "[OK] VibeGuard rules in ~/.claude/CLAUDE.md"
  else
    red "[MISSING] VibeGuard rules not in ~/.claude/CLAUDE.md"
  fi

  local link skill_links source_path skill
  skill_links="$(manifest_skill_links_checked "~/.claude/skills/")" || return 1
  while IFS=$'\t' read -r source_path skill; do
    [[ -n "${source_path}" && -n "${skill}" ]] || continue
    link="${CLAUDE_DIR}/skills/${skill}"
    if [[ -L "${link}" ]]; then
      if [[ -e "${link}" ]]; then
        green "[OK] ${skill} skill symlinked to ~/.claude/skills/"
      else
        red "[BROKEN] ${skill} symlink exists but target missing: $(readlink "${link}")"
      fi
    else
      red "[MISSING] ${skill} skill not in ~/.claude/skills/"
    fi
  done <<< "${skill_links}"

  if [[ -L "${CLAUDE_DIR}/commands/vibeguard" ]]; then
    green "[OK] vibeguard commands symlinked to ~/.claude/commands/"
  else
    red "[MISSING] vibeguard commands not in ~/.claude/commands/"
  fi

  local agent_count
  if [[ -d "${CLAUDE_DIR}/agents" ]] && [[ -n "$(ls -A "${CLAUDE_DIR}/agents" 2>/dev/null)" ]]; then
    agent_count=$(ls "${CLAUDE_DIR}/agents"/*.md 2>/dev/null | wc -l | tr -d ' ')
    green "[OK] ${agent_count} agents installed in ~/.claude/agents/"
  else
    yellow "[MISSING] agents not in ~/.claude/agents/"
  fi

  if [[ -d "${CLAUDE_DIR}/context-profiles" ]] && [[ -n "$(ls -A "${CLAUDE_DIR}/context-profiles" 2>/dev/null)" ]]; then
    green "[OK] context profiles installed in ~/.claude/context-profiles/"
  else
    yellow "[MISSING] context profiles not in ~/.claude/context-profiles/"
  fi

  local rules_dest="${HOME}/.claude/rules/vibeguard"
  local rule_file_count actual_rule_count claude_md declared_count
  local symlink_count copy_count
  if [[ -d "${rules_dest}" ]]; then
    rule_file_count=$(find "${rules_dest}" -name "*.md" \( -type f -o -type l \) 2>/dev/null | wc -l | tr -d ' ')
    symlink_count=$(find "${rules_dest}" -name "*.md" -type l 2>/dev/null | wc -l | tr -d ' ')
    copy_count=$((rule_file_count - symlink_count))
    if [[ "${rule_file_count}" -ge 7 ]]; then
      green "[OK] ${rule_file_count} native rule files in ~/.claude/rules/vibeguard/ (${symlink_count} symlinked)"
    else
      yellow "[PARTIAL] Only ${rule_file_count} native rule files (expected 7+)"
    fi
    if [[ "${copy_count}" -gt 0 ]]; then
      yellow "[DRIFT] ${copy_count} rule files are copies instead of symlinks — re-run setup.sh to fix"
    fi

    actual_rule_count=$(claude_rule_id_count "${rules_dest}")
    claude_md="${CLAUDE_DIR}/CLAUDE.md"
    if [[ -f "${claude_md}" ]]; then
      declared_count=$(grep -o '[0-9]* rules' "${claude_md}" 2>/dev/null | grep -o '[0-9]*' | head -1)
      declared_count="${declared_count:-0}"
      if [[ "${actual_rule_count}" -eq "${declared_count}" ]]; then
        green "[OK] Rule count in sync: ${actual_rule_count} rules"
      else
        yellow "[DRIFT] CLAUDE.md declares ${declared_count} rules, actual: ${actual_rule_count}"
        yellow "[INFO] Re-run 'bash setup.sh' to repair the rule count banner in ~/.claude/CLAUDE.md"
      fi
    fi
  else
    red "[MISSING] Native rules not in ~/.claude/rules/vibeguard/"
  fi

  if settings_check "${SETTINGS_FILE}" "pre-hooks"; then
    green "[OK] PreToolUse hooks configured (Write block + Bash block + Edit guard)"
  else
    yellow "[MISSING] PreToolUse hooks not fully configured"
  fi

  if settings_check "${SETTINGS_FILE}" "post-hooks"; then
    green "[OK] PostToolUse hooks configured (Edit quality + Write dedup)"
  else
    yellow "[MISSING] PostToolUse hooks not fully configured"
  fi

  if settings_check "${SETTINGS_FILE}" "full-hooks"; then
    green "[OK] Full profile hooks configured (Stop gate + Build check + Learn evaluator)"
  else
    yellow "[INFO] Full profile hooks not configured (current install may be core profile)"
  fi

  local stale_hooks_report
  if stale_hooks_report="$(settings_stale_hooks_report "${SETTINGS_FILE}" 2>&1)"; then
    :
  else
    while IFS= read -r line; do
      [[ -n "${line}" ]] && red "[BROKEN] ${line}"
    done <<< "${stale_hooks_report}"
  fi
}

clean_claude_home_installation() {
  if [[ -f "${CLAUDE_DIR}/CLAUDE.md" ]]; then
    local result
    result=$(python3 "${CLAUDE_MD_HELPER}" remove "${CLAUDE_DIR}/CLAUDE.md" 2>/dev/null || echo "ERROR")
    case "${result}" in
      REMOVED|REMOVED_LEGACY) yellow "Removed VibeGuard rules from ~/.claude/CLAUDE.md" ;;
      NOT_FOUND) yellow "No VibeGuard rules found in ~/.claude/CLAUDE.md" ;;
      *) red "Failed to clean CLAUDE.md" ;;
    esac
  fi

  rm -f "${CLAUDE_DIR}/commands/vibeguard" 2>/dev/null || rm -rf "${CLAUDE_DIR}/commands/vibeguard" 2>/dev/null || true
  local skill_links source_path skill
  skill_links="$(manifest_skill_links_for_cleanup "~/.claude/skills/")"
  while IFS=$'\t' read -r source_path skill; do
    [[ -n "${source_path}" && -n "${skill}" ]] || continue
    rm -f "${CLAUDE_DIR}/skills/${skill}"
  done <<< "${skill_links}"
  cleanup_retired_manifest_skill_links "~/.claude/skills/" "${CLAUDE_DIR}/skills"

  local agent
  for agent in "${REPO_DIR}"/agents/*.md; do
    [[ -f "${agent}" ]] || continue
    rm -f "${CLAUDE_DIR}/agents/$(basename "${agent}")"
  done
  rmdir "${CLAUDE_DIR}/agents" 2>/dev/null || true

  local profile
  for profile in "${REPO_DIR}"/context-profiles/*.md; do
    [[ -f "${profile}" ]] || continue
    rm -f "${CLAUDE_DIR}/context-profiles/$(basename "${profile}")"
  done
  rmdir "${CLAUDE_DIR}/context-profiles" 2>/dev/null || true

  if [[ -d "${HOME}/.claude/rules/vibeguard" ]]; then
    rm -rf "${HOME}/.claude/rules/vibeguard"
    yellow "Removed native rules from ~/.claude/rules/vibeguard/"
  fi

  if [[ -f "${SETTINGS_FILE}" ]]; then
    local clean_result
    if clean_result=$(settings_remove "${SETTINGS_FILE}" 2>/dev/null); then
      if [[ "${clean_result}" == "CHANGED" ]]; then
        yellow "Removed VibeGuard hooks and legacy MCP entries from settings.json"
      fi
    fi
  fi
}
