#!/usr/bin/env bash
# ai-commit - High-Speed Minimalist Git Commit Generator

set -euo pipefail

trap 'echo -e "\n[aborted]" >&2; exit 130' INT

# 1. Verify Git Repository
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
    echo "[error] Not inside a git repository." >&2
    exit 1
fi

# 2. Extract Only the Last 3 Staged Files
mapfile -t target_files < <(git diff --cached --name-only | tail -n 3)
if [[ ${#target_files[@]} -eq 0 ]]; then
    echo "[info] No staged changes found. Run 'git add' first." >&2
    exit 0
fi

# 3. Model Server Pre-Flight Check
CFG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/py-agent"
server_online=0

if curl -s -m 0.15 "http://127.0.0.1:8080/v1/models" >/dev/null 2>&1; then
    server_online=1
elif grep -E -q '^(GEMINI_API_KEY|OPENROUTER_API_KEY|CUSTOM_API_KEY)=.+[a-zA-Z0-9]' "$CFG_DIR/.env" 2>/dev/null; then
    server_online=1
fi

base_file=$(basename "${target_files[-1]}" 2>/dev/null || echo "files")
fallback_msg="Update $base_file and related components"

if [[ "$server_online" -eq 0 ]]; then
    echo -e "\n\033[90m[warn] Server offline (:8080). Using file fallback.\033[0m" >&2
    message="$fallback_msg"
else
    # 4. Ultra-Compact Context: Only status + max 8 diff lines across the 3 files
    stats=$(git diff --cached --name-status -- "${target_files[@]}" || true)
    changes=$(git diff --cached -U0 -- "${target_files[@]}" \
        ':(exclude)*lock*' ':(exclude)*.svg' ':(exclude)*.png' ':(exclude)*.jpg' ':(exclude)*.gif' \
        | awk '
        /^\+[^+]/ || /^-[^-]/ {
            val = substr($0, 2)
            sub(/^[ \t]+/, "", val)
            if (val != "" && val !~ /^(#|\/\/|\/\*|\*)/) {
                print $0
                count++
                if (count >= 8) { exit }
            }
        }' || true)

    SYSTEM_PROMPT="Write a 4-8 word imperative git commit message. No quotes, explanations, markdown, or trailing period."
    USER_PROMPT="Files:
$stats

Changes:
$changes"

    raw_message=""
    printf "\033[90m[generating commit...]\033[0m" >&2

    # 5. Direct Local HTTP Fast-Path (< 2s total round-trip on CPU)
    if curl -s -m 0.15 "http://127.0.0.1:8080/v1/models" >/dev/null 2>&1; then
        payload=$(python3 -c '
import json, sys
sys_p, usr_p = sys.argv[1], sys.argv[2]
print(json.dumps({
    "messages": [
        {"role": "system", "content": sys_p},
        {"role": "user", "content": usr_p}
    ],
    "temperature": 0.2,
    "max_tokens": 16,
    "stream": False,
    "chat_template_kwargs": {"reasoning_effort": "none", "enable_thinking": False}
}))' "$SYSTEM_PROMPT" "$USER_PROMPT" 2>/dev/null || echo "")

        if [[ -n "$payload" ]]; then
            resp=$(curl -s -m 6 -H "Content-Type: application/json" -d "$payload" "http://127.0.0.1:8080/v1/chat/completions" 2>/dev/null || echo "")
            raw_message=$(echo "$resp" | python3 -c '
import json, sys
try:
    data = json.load(sys.stdin)
    print(data["choices"][0]["message"]["content"].strip())
except Exception:
    pass' 2>/dev/null || echo "")
        fi
    fi

    # Fallback to py-agent CLI if local server was busy or returned empty
    if [[ -z "$raw_message" ]]; then
        _AI_SCRIPT_PATH="${CFG_DIR}/ai-agent.py"
        _AI_PYTHON_BIN=$(command -v python3 2>/dev/null || echo "python3")
        combined_prompt="$SYSTEM_PROMPT

$USER_PROMPT"
        raw_message=$("$_AI_PYTHON_BIN" "$_AI_SCRIPT_PATH" --talk "$combined_prompt" 2>/dev/null || echo "")
    fi

    printf "\r\033[2K" >&2

    # 6. Sanitize Output: Strip ANSI escape sequences & model prefixes
    message=$(echo "$raw_message" | sed -E 's/\x1b\[[0-9;]*[a-zA-Z]//g')
    message=$(echo "$message" | sed -E 's/^(AI|Agent):\s*//')

    # 7. Strip stray <think> blocks
    message=$(echo "$message" | perl -0777 -pe 's/<think>.*?<\/think>//gs' 2>/dev/null || echo "$message")
    message=$(echo "$message" | perl -0777 -pe 's/<think>.*//gs' 2>/dev/null || echo "$message")

    # 8. Clean First Line
    message=$(echo "$message" | sed -E \
        -e 's/^[Cc]ommit [Mm]essage:?\s*//' \
        -e 's/^[-*]\s*//' \
        -e 's/^[`"'\''\s]+//' \
        -e 's/[`"'\''\s\.]+$//' \
        -e 's/^[[:space:]]+//; s/[[:space:]]+$//' \
        | awk 'NF {print; exit}' || echo "")

    # 9. Format Capitalization & Word Bounds
    if [[ -n "$message" ]]; then
        word_count=$(echo "$message" | wc -w)
        if [[ $word_count -gt 8 ]]; then
            message=$(echo "$message" | awk '{for(i=1;i<=8;i++) printf "%s%s", $i, (i<8?" ":"\n")}')
            message=$(echo "$message" | sed -E 's/\s+(in|to|for|with|and|or|the|a|an|of|by|from|on|at|as)$//I')
        fi
        first_char=$(echo "${message:0:1}" | tr '[:lower:]' '[:upper:]')
        message="${first_char}${message:1}"
    else
        message="$fallback_msg"
    fi
fi

# 10. Interactive Input Prompt
user_message=""
if [ -t 0 ]; then
    read -e -i "$message" -p "commit: " user_message
elif [ -c /dev/tty ]; then
    read -e -i "$message" -p "commit: " user_message < /dev/tty
else
    user_message="$message"
fi

if [[ -z "$user_message" ]]; then
    echo "[error] Commit message cannot be empty. Aborted." >&2
    exit 1
fi

git commit -m "$user_message"
