#!/usr/bin/env bash
# Repo-local VisualHUD CLI.

set -euo pipefail

SCRIPT_SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SCRIPT_SOURCE" ]; do
    SCRIPT_DIR="$(cd -P "$(dirname "$SCRIPT_SOURCE")" && pwd)"
    SCRIPT_SOURCE="$(readlink "$SCRIPT_SOURCE")"
    if [[ "$SCRIPT_SOURCE" != /* ]]; then
        SCRIPT_SOURCE="$SCRIPT_DIR/$SCRIPT_SOURCE"
    fi
done
ROOT_DIR="${VISUALHUD_ROOT:-$(cd -P "$(dirname "$SCRIPT_SOURCE")" && pwd)}"
THEMES_DIR="${VISUALHUD_THEMES_DIR:-$ROOT_DIR/themes}"
ACTIVE_THEME_FILE="${VISUALHUD_THEME_FILE:-$ROOT_DIR/theme}"
DEFAULT_THEME="${VISUALHUD_DEFAULT_THEME:-pokemon}"
JSON_HELPER="${VISUALHUD_JSON_HELPER:-$ROOT_DIR/scripts/visualhud-json.js}"

json_helper() {
    node "$JSON_HELPER" "$@"
}

usage() {
    cat <<'EOF'
Quick start:
  cd /path/to/repo
  npx -y visualhud@latest
  codex --yolo

Usage:
  visualhud [--theme <name>] [--platform macos|windows|wezterm]
  visualhud install codex --target <repo> [--theme <name>] [--platform macos|windows|wezterm]
  visualhud theme list
  visualhud theme current
  visualhud theme set <name>
  visualhud theme reset
  visualhud theme calibrate [name] [--json|--live] [--delay seconds] [--pause] [--limit n]
EOF
}

theme_exists() {
    local theme="$1"
    [ -f "$THEMES_DIR/$theme/theme.json" ]
}

active_theme() {
    if [ -n "${VISUALHUD_THEME:-}" ]; then
        printf '%s\n' "$VISUALHUD_THEME"
    elif [ -f "$ACTIVE_THEME_FILE" ]; then
        tr -d '[:space:]' < "$ACTIVE_THEME_FILE"
        printf '\n'
    else
        printf '%s\n' "$DEFAULT_THEME"
    fi
}

theme_display_name() {
    local theme="$1"
    json_helper theme-display-name "$THEMES_DIR/$theme/theme.json" "$theme" 2>/dev/null || printf '%s\n' "$theme"
}

list_themes() {
    local current theme theme_json marker display_name
    current=$(active_theme)

    if [ ! -d "$THEMES_DIR" ]; then
        printf 'No themes directory: %s\n' "$THEMES_DIR" >&2
        return 1
    fi

    shopt -s nullglob
    for theme_json in "$THEMES_DIR"/*/theme.json; do
        theme=$(basename "$(dirname "$theme_json")")
        marker=" "
        if [ "$theme" = "$current" ]; then
            marker="*"
        fi
        display_name=$(theme_display_name "$theme")
        printf '%s %s\t%s\n' "$marker" "$theme" "$display_name"
    done
}

set_theme() {
    local theme="$1"
    if ! theme_exists "$theme"; then
        printf 'Unknown theme: %s\n' "$theme" >&2
        printf 'Run visualhud theme list to see available themes.\n' >&2
        return 1
    fi

    mkdir -p "$(dirname "$ACTIVE_THEME_FILE")"
    printf '%s\n' "$theme" > "$ACTIVE_THEME_FILE"
    printf 'Active theme: %s\n' "$theme"
}

reset_theme() {
    rm -f "$ACTIVE_THEME_FILE"
    printf 'Active theme reset to default: %s\n' "$DEFAULT_THEME"
}

detect_platform() {
    local system
    system=$(uname -s 2>/dev/null || printf unknown)
    case "$system" in
        Darwin)
            printf 'macos\n'
            ;;
        MINGW*|MSYS*|CYGWIN*)
            printf 'windows\n'
            ;;
        *)
            printf '%s\n' "$system" | tr '[:upper:]' '[:lower:]'
            ;;
    esac
}

target_repo_root() {
    local target="$1"
    if [ ! -d "$target" ]; then
        printf 'Target directory does not exist: %s\n' "$target" >&2
        return 1
    fi
    git -C "$target" rev-parse --show-toplevel 2>/dev/null || {
        printf 'Target is not a Git worktree: %s\n' "$target" >&2
        return 1
    }
}

copy_runtime_dir() {
    local source="$1" destination="$2"
    if [ -d "$source" ] && [ -d "$destination" ]; then
        local source_real destination_real
        source_real=$(cd "$source" && pwd -P)
        destination_real=$(cd "$destination" && pwd -P)
        if [ "$source_real" = "$destination_real" ]; then
            return 0
        fi
    fi
    rm -rf "$destination"
    mkdir -p "$(dirname "$destination")"
    cp -R "$source" "$destination"
}

copy_runtime_file() {
    local source="$1" destination="$2"
    if [ -f "$source" ] && [ -f "$destination" ]; then
        local source_dir destination_dir
        source_dir=$(cd "$(dirname "$source")" && pwd -P)
        destination_dir=$(cd "$(dirname "$destination")" && pwd -P)
        if [ "$source_dir/$(basename "$source")" = "$destination_dir/$(basename "$destination")" ]; then
            return 0
        fi
    fi
    cp "$source" "$destination"
}

copy_codex_runtime() {
    local target_root="$1"
    local runtime_dir="$target_root/.visualhud"

    mkdir -p "$runtime_dir/.codex/hooks" "$target_root/.codex/hooks"
    copy_runtime_file "$ROOT_DIR/engine.sh" "$runtime_dir/engine.sh"
    copy_runtime_file "$ROOT_DIR/set_bg.py" "$runtime_dir/set_bg.py"
    copy_runtime_file "$ROOT_DIR/setup-iterm2.sh" "$runtime_dir/setup-iterm2.sh"
    copy_runtime_file "$ROOT_DIR/setup-wezterm.ps1" "$runtime_dir/setup-wezterm.ps1"
    copy_runtime_file "$ROOT_DIR/visualhud" "$runtime_dir/visualhud"
    copy_runtime_file "$ROOT_DIR/.codex/hooks/visualhud-codex.sh" "$runtime_dir/.codex/hooks/visualhud-codex.sh"
    copy_runtime_dir "$ROOT_DIR/themes" "$runtime_dir/themes"
    copy_runtime_dir "$ROOT_DIR/scripts" "$runtime_dir/scripts"
    copy_runtime_dir "$ROOT_DIR/wezterm" "$runtime_dir/wezterm"
    copy_runtime_dir "$ROOT_DIR/skills" "$runtime_dir/skills"
    chmod +x "$runtime_dir/visualhud" "$runtime_dir/setup-iterm2.sh" "$runtime_dir/.codex/hooks/visualhud-codex.sh"
}

install_codex_skills() {
    local target_root="$1"
    local skills_source="$ROOT_DIR/skills"
    local skills_target="$target_root/.agents/skills"
    local skill_dir skill_name

    if [ ! -d "$skills_source" ]; then
        return 0
    fi

    mkdir -p "$skills_target"
    shopt -s nullglob
    for skill_dir in "$skills_source"/visualhud-*; do
        skill_name=$(basename "$skill_dir")
        copy_runtime_dir "$skill_dir" "$skills_target/$skill_name"
    done
    shopt -u nullglob
}

write_codex_hook_wrapper() {
    local target_root="$1"
    local renderer="${2:-}"
    local wrapper="$target_root/.codex/hooks/visualhud-codex.sh"
    {
        cat <<'EOF'
#!/usr/bin/env bash
# VisualHUD installed Codex hook wrapper.

set -euo pipefail

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
VISUALHUD_ROOT="$REPO_ROOT/.visualhud"

export VISUALHUD_ENGINE="$VISUALHUD_ROOT/engine.sh"
export VISUALHUD_THEMES_DIR="$VISUALHUD_ROOT/themes"
export VISUALHUD_SET_BG="$VISUALHUD_ROOT/set_bg.py"
EOF
        if [ -n "$renderer" ]; then
            printf 'export VISUALHUD_RENDERER="%s"\n' "$renderer"
        fi
        cat <<'EOF'

exec bash "$VISUALHUD_ROOT/.codex/hooks/visualhud-codex.sh"
EOF
    } > "$wrapper"
    chmod +x "$wrapper"
}

install_codex_hooks_json() {
    local target_root="$1"
    local hooks_json="$target_root/.codex/hooks.json" tmp command
    command="bash \"\$(git rev-parse --show-toplevel)/.codex/hooks/visualhud-codex.sh\""
    mkdir -p "$(dirname "$hooks_json")"
    if [ ! -f "$hooks_json" ]; then
        printf '{"hooks":{}}\n' > "$hooks_json"
    fi
    tmp="${hooks_json}.tmp.$$"
    json_helper merge-codex-hooks "$hooks_json" "$command" > "$tmp"
    mv "$tmp" "$hooks_json"
}

install_codex() {
    local target="" theme="pokemon" platform="" target_root runtime_dir renderer

    while [ "$#" -gt 0 ]; do
        case "$1" in
            --target)
                target="${2:-}"
                if [ -z "$target" ]; then
                    printf 'Missing --target value.\n' >&2
                    return 2
                fi
                shift
                ;;
            --theme)
                theme="${2:-}"
                if [ -z "$theme" ]; then
                    printf 'Missing --theme value.\n' >&2
                    return 2
                fi
                shift
                ;;
            --platform)
                platform="${2:-}"
                if [ -z "$platform" ]; then
                    printf 'Missing --platform value.\n' >&2
                    return 2
                fi
                shift
                ;;
            *)
                printf 'Unknown install option: %s\n' "$1" >&2
                usage >&2
                return 2
                ;;
        esac
        shift
    done

    target="${target:-.}"
    platform="${platform:-$(detect_platform)}"
    case "$platform" in
        macos|darwin)
            renderer="iterm2"
            ;;
        windows|win32|powershell)
            renderer="windows"
            ;;
        wezterm|windows-wezterm)
            renderer="wezterm"
            ;;
        *)
            printf 'VisualHUD Codex install supports macOS/iTerm2 and Windows Terminal/PowerShell for now; detected platform: %s\n' "$platform" >&2
            return 1
            ;;
    esac

    if ! theme_exists "$theme"; then
        printf 'Unknown theme: %s\n' "$theme" >&2
        printf 'Run visualhud theme list to see available themes.\n' >&2
        return 1
    fi

    target_root=$(target_repo_root "$target")
    runtime_dir="$target_root/.visualhud"
    copy_codex_runtime "$target_root"
    printf '%s\n' "$theme" > "$runtime_dir/theme"
    install_codex_skills "$target_root"
    write_codex_hook_wrapper "$target_root" "$renderer"
    install_codex_hooks_json "$target_root"

    printf 'Installed VisualHUD Codex hooks in: %s\n' "$target_root"
    printf 'Active theme: %s\n' "$theme"
    printf 'Runtime: %s\n' "$runtime_dir"
    case "$renderer" in
        iterm2)
            printf 'Renderer: iTerm2\n'
            printf 'If iTerm2 visuals are not enabled yet, run: %s/setup-iterm2.sh\n' "$runtime_dir"
            ;;
        windows)
            printf 'Renderer: Windows Terminal/PowerShell\n'
            printf 'Windows renderer updates the tab title and Windows Terminal progress indicator; background images require iTerm2 or WezTerm.\n'
            printf 'For richer Windows colors/backgrounds in WezTerm, rerun this install with --platform wezterm, then run: pwsh -ExecutionPolicy Bypass -File "%s/setup-wezterm.ps1"\n' "$runtime_dir"
            ;;
        wezterm)
            printf 'Renderer: WezTerm\n'
            printf 'Run once to enable live WezTerm backgrounds: pwsh -ExecutionPolicy Bypass -File "%s/setup-wezterm.ps1"\n' "$runtime_dir"
            ;;
    esac
    printf 'Then start Codex in the target repo: codex --yolo\n'
}

calibration_counter_file() {
    local session_key
    session_key=$(printf '%s' "${ITERM_SESSION_ID:-${WT_SESSION:-visualhud-calibration}}" | tr ':/' '__')
    printf '%s/claude-cooking-counter_%s' "${VISUALHUD_STATE_DIR:-${TMPDIR:-/tmp}}" "$session_key"
}

render_calibration_step() {
    local theme="$1" step_json="$2"
    local kind count counter_file payload fields

    if [ -z "${ITERM_SESSION_ID:-}" ]; then
        printf 'Live calibration requires ITERM_SESSION_ID from a real terminal pane.\n' >&2
        return 1
    fi

    fields=$(printf '%s' "$step_json" | json_helper calibration-payload 2>/dev/null || true)
    if [ -z "$fields" ]; then
        printf 'Unknown calibration step.\n' >&2
        return 1
    fi
    IFS=$'\t' read -r kind count payload <<< "$fields"
    counter_file=$(calibration_counter_file)
    if [ "$kind" = "stage" ] || [ "$kind" = "stage-shade" ] || [ "$kind" = "context" ]; then
        printf '%s' "$((count - 1))" > "$counter_file"
    fi

    printf '%s\n' "$payload" | VISUALHUD_THEME="$theme" VISUALHUD_THEMES_DIR="$THEMES_DIR" bash "$ROOT_DIR/engine.sh" >/dev/null
}

calibration_label() {
    local step_json="$1"
    printf '%s' "$step_json" | json_helper calibration-label
}

calibrate_theme() {
    local theme="${1:-}" output_format="text" live="0" delay="0.8" pause="0" limit="0"
    local theme_file step_json label

    if [ -z "$theme" ] || [[ "$theme" == --* ]]; then
        theme=$(active_theme)
    else
        shift
    fi

    while [ "$#" -gt 0 ]; do
        case "$1" in
            --json)
                output_format="json"
                ;;
            --live)
                live="1"
                ;;
            --delay)
                delay="${2:-}"
                if [ -z "$delay" ]; then
                    printf 'Missing --delay value.\n' >&2
                    return 2
                fi
                shift
                ;;
            --pause)
                pause="1"
                ;;
            --limit)
                limit="${2:-}"
                if [ -z "$limit" ]; then
                    printf 'Missing --limit value.\n' >&2
                    return 2
                fi
                shift
                ;;
            *)
                printf 'Unknown calibrate option: %s\n' "$1" >&2
                usage >&2
                return 2
                ;;
        esac
        shift
    done

    if ! theme_exists "$theme"; then
        printf 'Unknown theme: %s\n' "$theme" >&2
        printf 'Run visualhud theme list to see available themes.\n' >&2
        return 1
    fi

    theme_file="$THEMES_DIR/$theme/theme.json"
    if [ "$live" != "1" ]; then
        python3 "$ROOT_DIR/scripts/theme-calibration-steps.py" \
            --theme "$theme_file" \
            --theme-name "$theme" \
            --format "$output_format" \
            --limit "$limit"
        return
    fi

    while IFS= read -r step_json; do
        label=$(calibration_label "$step_json")
        printf '%s\n' "$label"
        render_calibration_step "$theme" "$step_json"
        if [ "$pause" = "1" ]; then
            printf 'Press Enter for next calibration step, or Ctrl-C to stop... ' >&2
            IFS= read -r _
        elif [ "$delay" != "0" ]; then
            sleep "$delay"
        fi
    done < <(
        python3 "$ROOT_DIR/scripts/theme-calibration-steps.py" \
            --theme "$theme_file" \
            --theme-name "$theme" \
            --format json-lines \
            --limit "$limit"
    )
}

if [ "$#" -lt 1 ]; then
    install_codex
    exit
fi

case "${1:-}" in
    -h|--help|help)
        usage
        ;;
    --target|--theme|--platform)
        install_codex "$@"
        ;;
    install)
        subcommand="${2:-}"
        case "$subcommand" in
            codex)
                shift 2
                install_codex "$@"
                ;;
            *)
                printf 'Unknown install command: %s\n' "$subcommand" >&2
                usage >&2
                exit 2
                ;;
        esac
        ;;
    theme|themes)
        subcommand="${2:-list}"
        case "$subcommand" in
            list)
                list_themes
                ;;
            current)
                active_theme
                ;;
            set)
                if [ -z "${3:-}" ]; then
                    printf 'Missing theme name.\n' >&2
                    usage >&2
                    exit 2
                fi
                set_theme "$3"
                ;;
            reset)
                reset_theme
                ;;
            calibrate)
                shift 2
                calibrate_theme "$@"
                ;;
            *)
                printf 'Unknown theme command: %s\n' "$subcommand" >&2
                usage >&2
                exit 2
                ;;
        esac
        ;;
    *)
        printf 'Unknown command: %s\n' "$1" >&2
        usage >&2
        exit 2
        ;;
esac
