#!/usr/bin/env bash
set -euo pipefail

# ─────────────────────────────────────────────────────────────────────────────
# 06-quality-gates.sh — Pre-commit Quality Gate Runner
#
# Description:
#   Runs configurable quality gates (format, lint, test, build, security)
#   with timing, pass/fail tracking, and summary. Can install as git hook.
#
# Usage:
#   ./06-quality-gates.sh [OPTIONS] [GATES...]
#   Gates: format lint test build security (omit to run all)
#
# Options:
#   --install-hook    Install as git pre-commit hook
#   --changed-only    Run tests only on changed files (where supported)
#   --fix             Auto-fix formatter/linter issues
#   --no-fail         Report results but exit 0 regardless
#   --verbose         Show full command output
#   -h, --help        Show this help
# ─────────────────────────────────────────────────────────────────────────────

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/lib/securegit-common.sh"

ALL_GATES=(format lint test build security)

# ─── Argument parsing ───────────────────────────────────────────────────────
OPT_HOOK=false; OPT_CHANGED=false; OPT_FIX=false; OPT_NOFAIL=false; OPT_VERBOSE=false
SELECTED_GATES=()
while [[ $# -gt 0 ]]; do
    case "$1" in
        --install-hook)  OPT_HOOK=true ;;
        --changed-only)  OPT_CHANGED=true ;;
        --fix)           OPT_FIX=true ;;
        --no-fail)       OPT_NOFAIL=true ;;
        --verbose)       OPT_VERBOSE=true ;;
        format|lint|test|build|security) SELECTED_GATES+=("$1") ;;
        -h|--help)
            echo "Usage: $0 [OPTIONS] [GATES...]"
            echo "Gates: format lint test build security"
            echo "Options: --install-hook --changed-only --fix --no-fail --verbose"
            exit 0 ;;
        *) sg_die "Unknown: $1. Use --help." ;;
    esac; shift
done
[[ ${#SELECTED_GATES[@]} -eq 0 ]] && SELECTED_GATES=("${ALL_GATES[@]}")

# ─── Pre-flight ──────────────────────────────────────────────────────────────
sg_require_repo
REPO_ROOT="$(git rev-parse --show-toplevel)"
DETECTED_LANG="$(sg_detect_language)"

# ─── Hook installation ──────────────────────────────────────────────────────
if $OPT_HOOK; then
    sg_header "Install Pre-commit Hook"
    if command -v securegit &>/dev/null && _sg_cmd hook install pre-commit 2>/dev/null; then
        sg_success "Pre-commit hook installed via securegit."; exit 0
    fi
    hook_file="$REPO_ROOT/.git/hooks/pre-commit"
    [[ -f "$hook_file" ]] && { sg_warn "Hook exists."; sg_confirm "Overwrite?" || exit 0; cp "$hook_file" "${hook_file}.bak"; }
    this_script="$(cd "$(dirname "$0")" && pwd)/$(basename "$0")"
    mkdir -p "$(dirname "$hook_file")"
    cat > "$hook_file" <<HOOK
#!/usr/bin/env bash
set -euo pipefail
echo "Running SecureGit quality gates..."
[[ -x "$this_script" ]] && exec "$this_script" "\$@"
echo "Warning: quality gate script not found: $this_script"
HOOK
    chmod +x "$hook_file"
    sg_success "Pre-commit hook installed at: $hook_file"; exit 0
fi

# ─── Gate tracking ───────────────────────────────────────────────────────────
declare -A GATE_RESULT=() GATE_TIME=() GATE_CMD=()
PASSED=0; FAILED=0; SKIPPED=0

_run_gate() {
    local name="$1" cmd="$2" label="$3"
    # Skip "No ... detected" commands
    if [[ "$cmd" == echo\ \'No\ * ]]; then
        GATE_RESULT[$name]="skip"; GATE_TIME[$name]=0; GATE_CMD[$name]="$cmd"
        (( SKIPPED++ )) || true
        printf "  ${_C_DIM}SKIP${_C_RESET}  %-12s ${_C_DIM}(not detected)${_C_RESET}\n" "$label"
        return 0
    fi
    GATE_CMD[$name]="$cmd"
    printf "  ${_C_CYAN}RUN ${_C_RESET}  %-12s %s\n" "$label" "$cmd"
    local t0=$SECONDS ec=0 tmpf; tmpf="$(mktemp)"
    if $OPT_VERBOSE; then eval "$cmd" 2>&1 | tee "$tmpf" || ec=$?
    else eval "$cmd" > "$tmpf" 2>&1 || ec=$?; fi
    local elapsed=$(( SECONDS - t0 )); GATE_TIME[$name]=$elapsed
    if (( ec == 0 )); then
        GATE_RESULT[$name]="pass"; (( PASSED++ )) || true
        printf "\r  ${_C_GREEN}PASS${_C_RESET}  %-12s ${_C_DIM}(%ds)${_C_RESET}\n" "$label" "$elapsed"
    else
        GATE_RESULT[$name]="fail"; (( FAILED++ )) || true
        printf "\r  ${_C_RED}FAIL${_C_RESET}  %-12s ${_C_DIM}(%ds)${_C_RESET}\n" "$label" "$elapsed"
        if ! $OPT_VERBOSE; then
            local lines; lines="$(wc -l < "$tmpf")"
            (( lines > 0 )) && { echo; head -25 "$tmpf" | sed 's/^/    /'; (( lines > 25 )) && printf "    ${_C_DIM}... (%d more)${_C_RESET}\n" "$(( lines-25 ))"; echo; }
        fi
    fi
    rm -f "$tmpf"
}

# ─── Gate: format ────────────────────────────────────────────────────────────
_gate_format() {
    local cmd; cmd="$(sg_detect_fmt_cmd)"
    if $OPT_FIX; then
        case "$DETECTED_LANG" in
            rust) cmd="cargo fmt" ;; go) cmd="gofmt -w ." ;;
            python) command -v ruff &>/dev/null && cmd="ruff format ." || cmd="black ." ;;
            js) [[ -f "$REPO_ROOT/biome.json" ]] && cmd="npx biome format --write ." || cmd="npx prettier --write ." ;;
        esac
    fi
    _run_gate format "$cmd" "Format"
}

# ─── Gate: lint ──────────────────────────────────────────────────────────────
_gate_lint() {
    local cmd; cmd="$(sg_detect_lint_cmd)"
    if $OPT_FIX; then
        case "$DETECTED_LANG" in
            rust) cmd="cargo clippy --fix --allow-dirty -- -D warnings" ;;
            python) command -v ruff &>/dev/null && cmd="ruff check --fix ." ;;
            js) [[ -f "$REPO_ROOT/biome.json" ]] && cmd="npx biome check --write" || cmd="npx eslint --fix ." ;;
        esac
    fi
    _run_gate lint "$cmd" "Lint"
}

# ─── Gate: test ──────────────────────────────────────────────────────────────
_gate_test() {
    local cmd; cmd="$(sg_detect_test_cmd)"
    if $OPT_CHANGED; then
        local changed; changed="$(git diff --cached --name-only; git diff --name-only)"
        case "$DETECTED_LANG" in
            js) local tfiles; tfiles="$(echo "$changed" | grep -E '\.(test|spec)\.(js|ts|jsx|tsx)$' || true)"
                [[ -n "$tfiles" ]] && cmd="npx vitest run $tfiles" ;;
            python) local pf; pf="$(echo "$changed" | grep -E '(test_|_test\.py)' || true)"
                [[ -n "$pf" ]] && command -v pytest &>/dev/null && cmd="pytest $pf" ;;
            rust) sg_info "Running tests for changed crates..." ;;
        esac
    fi
    _run_gate test "$cmd" "Test"
}

# ─── Gate: build ─────────────────────────────────────────────────────────────
_gate_build() { _run_gate build "$(sg_detect_build_cmd)" "Build"; }

# ─── Gate: security ──────────────────────────────────────────────────────────
_gate_security() {
    if ! command -v securegit &>/dev/null; then
        GATE_RESULT[security]="skip"; GATE_TIME[security]=0; GATE_CMD[security]="n/a"
        (( SKIPPED++ )) || true
        printf "  ${_C_DIM}SKIP${_C_RESET}  %-12s ${_C_DIM}(securegit not installed)${_C_RESET}\n" "Security"
        return 0
    fi
    local cmd; [[ -n "$(sg_staged_files)" ]] && cmd="securegit pre-commit" || cmd="securegit scan ."
    _run_gate security "$cmd" "Security"
}

# ─── Run gates ───────────────────────────────────────────────────────────────
sg_header "Quality Gates"
printf "  ${_C_DIM}Language: %s | Project: %s${_C_RESET}\n" "$DETECTED_LANG" "$REPO_ROOT"
$OPT_CHANGED && printf "  ${_C_DIM}Scope: changed files only${_C_RESET}\n"
$OPT_FIX && printf "  ${_C_DIM}Mode: auto-fix enabled${_C_RESET}\n"
echo; sg_divider

TOTAL_START=$SECONDS
_is_selected() { for s in "${SELECTED_GATES[@]}"; do [[ "$s" == "$1" ]] && return 0; done; return 1; }

_is_selected format   && _gate_format
_is_selected lint     && _gate_lint
_is_selected test     && _gate_test
_is_selected build    && _gate_build
_is_selected security && _gate_security

TOTAL_ELAPSED=$(( SECONDS - TOTAL_START ))

# ─── Summary ─────────────────────────────────────────────────────────────────
sg_divider; sg_header "Results"
printf "  ${_C_BOLD}%-12s %-8s %6s  %s${_C_RESET}\n" "Gate" "Result" "Time" "Command"
sg_divider
for g in "${ALL_GATES[@]}"; do
    [[ -z "${GATE_RESULT[$g]:-}" ]] && continue
    rd=""; case "${GATE_RESULT[$g]}" in
        pass) rd="${_C_GREEN}PASS${_C_RESET}" ;; fail) rd="${_C_RED}FAIL${_C_RESET}" ;; *) rd="${_C_DIM}SKIP${_C_RESET}" ;;
    esac
    cs="${GATE_CMD[$g]:-}"; (( ${#cs} > 45 )) && cs="${cs:0:42}..."
    printf "  %-12s %b   %4ss  ${_C_DIM}%s${_C_RESET}\n" "$g" "$rd" "${GATE_TIME[$g]:-0}" "$cs"
done
echo
printf "  ${_C_BOLD}Total:${_C_RESET} ${_C_GREEN}%d passed${_C_RESET}" "$PASSED"
(( FAILED > 0 ))  && printf "  ${_C_RED}%d failed${_C_RESET}" "$FAILED"
(( SKIPPED > 0 )) && printf "  ${_C_DIM}%d skipped${_C_RESET}" "$SKIPPED"
printf "  ${_C_DIM}(%ds)${_C_RESET}\n\n" "$TOTAL_ELAPSED"

if (( FAILED > 0 )); then
    $OPT_NOFAIL && { sg_warn "Failures detected, but --no-fail is set."; exit 0; }
    sg_error "Quality gates failed. Fix issues before committing."
    sg_info "Tips: --fix (auto-fix)  --no-fail (report only)  $0 lint format (subset)"
    exit 1
fi
sg_success "All quality gates passed."
