#!/usr/bin/env bash
# FILE: git_release_menu.sh
# VERSION: 1.0.0
# PURPOSE: Interactive, cautious Git learning menu for the fixnames project.
#
# This script intentionally performs ONE Git operation per menu selection.
# Read the explanation, choose an action, inspect the result, then continue.
# It does not run git add -A or delete files automatically.

set -u

PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEFAULT_BASELINE_TAG="v1.7-autocode"
DEFAULT_FEATURE_BRANCH="feature/docviewer-v2-rebuild"

COLOR_RESET='\033[0m'
COLOR_BOLD='\033[1m'
COLOR_GREEN='\033[0;32m'
COLOR_YELLOW='\033[0;33m'
COLOR_RED='\033[0;31m'
COLOR_CYAN='\033[0;36m'

say() { printf '%b\n' "$*"; }
rule() { printf '%*s\n' 78 '' | tr ' ' '-'; }
pause() { read -r -p "Press Enter to return to the menu..." _; }

run_git() {
    rule
    say "${COLOR_CYAN}$ $*${COLOR_RESET}"
    "$@"
    local code=$?
    say "${COLOR_YELLOW}Exit code: ${code}${COLOR_RESET}"
    rule
    return "$code"
}

require_git_repo() {
    if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
        say "${COLOR_RED}This directory is not a Git repository yet.${COLOR_RESET}"
        say "Choose menu option 3 to initialize it."
        return 1
    fi
    return 0
}

show_context() {
    rule
    say "${COLOR_BOLD}Git learning menu${COLOR_RESET}"
    say "Project: ${PROJECT_ROOT}"
    if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
        say "Repository: yes"
        say "Branch: $(git branch --show-current 2>/dev/null || true)"
        say "HEAD:   $(git log -1 --oneline 2>/dev/null || echo 'No commits yet')"
    else
        say "Repository: no"
    fi
    rule
}

show_status() {
    require_git_repo || return
    say "Git status answers: What changed? What is staged? What branch am I on?"
    run_git git status
}

show_history() {
    require_git_repo || return
    say "Git log shows saved commits. Decorations show branches and release tags."
    run_git git log --oneline --decorate -10
}

initialize_repo() {
    if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
        say "${COLOR_YELLOW}Git is already initialized here. No action taken.${COLOR_RESET}"
        return
    fi

    say "This creates .git/ in this project only."
    say "Git will begin tracking snapshots after you explicitly add and commit files."
    read -r -p "Initialize this directory with branch name 'main'? [y/N] " answer
    [[ "$answer" =~ ^[Yy]$ ]] || return

    if git init -b main; then
        say "${COLOR_GREEN}Repository initialized on main.${COLOR_RESET}"
    else
        say "Your Git may not support 'git init -b main'. Trying compatible setup..."
        git init && git branch -M main
    fi
}

create_gitignore() {
    require_git_repo || return
    local file="${PROJECT_ROOT}/.gitignore"

    say "A .gitignore prevents local backups, temp files, installers, and editor noise"
    say "from being accidentally staged. It does not delete any existing file."
    if [[ -f "$file" ]]; then
        say "${COLOR_YELLOW}.gitignore already exists. This menu will not overwrite it.${COLOR_RESET}"
        say "Review it manually: ${file}"
        return
    fi

    read -r -p "Create the recommended .gitignore? [y/N] " answer
    [[ "$answer" =~ ^[Yy]$ ]] || return

    cat > "$file" <<'EOF'
# FILE: .gitignore
# VERSION: 1.0.0
# Local/generated DocViewer backups and audit output
data/docviewer-backups/
data/docviewer-audit/

# Side-by-side backups and temporary installer output
*.bak-*
*.tmp.*

# Generated local installer scripts
install_docviewer_*.php
rebuild_docviewer_*.php
update_docviewer_*.php

# Runtime/local scratch directories
out/
run/
tmp/
log/
logs/
todo/

# macOS/editor artifacts
.DS_Store
*.swp
*.swo
*~

# Python artifacts
__pycache__/
*.py[cod]
EOF
    say "${COLOR_GREEN}Created .gitignore.${COLOR_RESET}"
    say "Next: use option 6 to stage only intentional source files."
}

stage_baseline() {
    require_git_repo || return

    say "This stages a deliberately limited baseline."
    say "It does NOT use 'git add -A', so scratch files and installers remain unstaged."
    say "Before staging, docs/samples/unreadable.txt is made readable so Git can index it."
    say
    say "Targets, if present:"
    say "  .gitignore README.md ADMIN.md API.md ARCHITECTURE.md CHANGELOG.md"
    say "  PROJECT.md AGENTS.md STATUS.md TODO.md TASKS.md ROLLBACK.md DEPLOYMENT.md STD_AUTH.md"
    say "  docviewer.php docs viewer test test_suite"
    read -r -p "Stage this baseline set? [y/N] " answer
    [[ "$answer" =~ ^[Yy]$ ]] || return

    if [[ -f docs/samples/unreadable.txt ]]; then
        chmod 0644 docs/samples/unreadable.txt || {
            say "${COLOR_RED}Could not restore read permission on docs/samples/unreadable.txt.${COLOR_RESET}"
            return 1
        }
        say "Restored docs/samples/unreadable.txt to 0644 so Git can read it."
    fi

    local targets=()
    local item
    for item in \
        .gitignore README.md ADMIN.md API.md ARCHITECTURE.md CHANGELOG.md \
        PROJECT.md AGENTS.md STATUS.md TODO.md TASKS.md ROLLBACK.md DEPLOYMENT.md STD_AUTH.md \
        docviewer.php docs viewer test test_suite; do
        [[ -e "$item" ]] && targets+=("$item")
    done

    if ((${#targets[@]} == 0)); then
        say "${COLOR_RED}No expected baseline paths were found.${COLOR_RESET}"
        return 1
    fi

    run_git git add -- "${targets[@]}"
    say "Now choose option 7 to review staged files before committing."
}

review_staged() {
    require_git_repo || return
    say "Review before commit. Nothing is saved permanently until you commit."
    run_git git status
    run_git git diff --cached --stat
    say "Whitespace/conflict-marker check:"
    run_git git diff --cached --check || true
}

commit_baseline() {
    require_git_repo || return
    if git diff --cached --quiet; then
        say "${COLOR_YELLOW}Nothing is staged. Use option 6, then option 7 first.${COLOR_RESET}"
        return
    fi

    say "A commit creates a named, permanent local snapshot of what is staged."
    read -r -p "Commit staged baseline as 'release: v1.7-autocode DocViewer baseline'? [y/N] " answer
    [[ "$answer" =~ ^[Yy]$ ]] || return

    run_git git commit -m "release: v1.7-autocode DocViewer baseline"
}

create_tag() {
    require_git_repo || return
    if ! git rev-parse HEAD >/dev/null 2>&1; then
        say "${COLOR_YELLOW}There is no commit to tag yet. Commit first with option 8.${COLOR_RESET}"
        return
    fi

    local tag
    read -r -p "Baseline tag name [${DEFAULT_BASELINE_TAG}]: " tag
    tag="${tag:-$DEFAULT_BASELINE_TAG}"

    if git rev-parse -q --verify "refs/tags/${tag}" >/dev/null; then
        say "${COLOR_YELLOW}Tag '${tag}' already exists. No action taken.${COLOR_RESET}"
        return
    fi

    say "An annotated tag marks this exact commit as a release/checkpoint."
    read -r -p "Create annotated tag '${tag}' on current commit? [y/N] " answer
    [[ "$answer" =~ ^[Yy]$ ]] || return

    run_git git tag -a "$tag" -m "DocViewer baseline before Viewer 2.0 rebuild"
}

create_feature_branch() {
    require_git_repo || return
    if ! git rev-parse HEAD >/dev/null 2>&1; then
        say "${COLOR_YELLOW}There is no commit yet. Commit and tag the baseline first.${COLOR_RESET}"
        return
    fi

    local branch
    read -r -p "Feature branch name [${DEFAULT_FEATURE_BRANCH}]: " branch
    branch="${branch:-$DEFAULT_FEATURE_BRANCH}"

    if git show-ref --verify --quiet "refs/heads/${branch}"; then
        say "${COLOR_YELLOW}Branch '${branch}' already exists.${COLOR_RESET}"
        read -r -p "Switch to it? [y/N] " answer
        [[ "$answer" =~ ^[Yy]$ ]] && run_git git switch "$branch"
        return
    fi

    say "A branch lets Viewer 2.0 changes proceed without changing main."
    read -r -p "Create and switch to '${branch}'? [y/N] " answer
    [[ "$answer" =~ ^[Yy]$ ]] || return

    run_git git switch -c "$branch"
}

show_tags_branches() {
    require_git_repo || return
    say "Branches are active lines of work; tags are fixed release labels."
    run_git git branch --all
    run_git git tag -n
}

show_restore_help() {
    require_git_repo || return
    cat <<EOF
A tag is a safe checkpoint. These commands DO NOT run automatically here.

View a past release without changing your branch:
  git switch --detach ${DEFAULT_BASELINE_TAG}

Return to your feature branch:
  git switch ${DEFAULT_FEATURE_BRANCH}

Restore one file from the baseline into your current branch:
  git restore --source=${DEFAULT_BASELINE_TAG} -- viewer/includes/viewer-content.php

Discard uncommitted edits to one file (be careful):
  git restore -- viewer/includes/viewer-content.php
EOF
}

show_next_steps() {
    cat <<EOF
Recommended order:

  1. Initialize Git once.
  2. Create .gitignore once.
  3. Stage the deliberate v1 baseline.
  4. Review exactly what is staged.
  5. Commit the baseline.
  6. Tag it as ${DEFAULT_BASELINE_TAG}.
  7. Create ${DEFAULT_FEATURE_BRANCH}.
  8. Build Viewer 2.0 only on that feature branch.

Why:
- main remains your stable baseline.
- the tag gives you a permanent named restore point.
- the feature branch isolates major Viewer 2.0 work.
EOF
}

cd "$PROJECT_ROOT" || exit 1

while true; do
    clear
    show_context
    cat <<'MENU'
1) Show Git status and working tree explanation
2) Show recent commits/history
3) Initialize this directory as a Git repository
4) Create recommended .gitignore
5) Show the recommended Git workflow and why
6) Stage the deliberate v1 baseline
7) Review staged changes before commit
8) Commit the staged v1.7-autocode baseline
9) Create the v1.7-autocode release tag
10) Create/switch to the Viewer 2.0 feature branch
11) Show branches and tags
12) Show restore/rollback learning commands
0) Exit
MENU
    rule
    read -r -p "Choose an action: " choice

    case "$choice" in
        1) show_status; pause ;;
        2) show_history; pause ;;
        3) initialize_repo; pause ;;
        4) create_gitignore; pause ;;
        5) show_next_steps; pause ;;
        6) stage_baseline; pause ;;
        7) review_staged; pause ;;
        8) commit_baseline; pause ;;
        9) create_tag; pause ;;
        10) create_feature_branch; pause ;;
        11) show_tags_branches; pause ;;
        12) show_restore_help; pause ;;
        0) say "Exiting without further changes."; exit 0 ;;
        *) say "${COLOR_RED}Unknown selection.${COLOR_RESET}"; pause ;;
    esac
done
