#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-3.0-or-later
#
# forge-sh — first-party provider for shell scripts (CONTRACT.md section 5).
# One verb: lint = shellcheck -x -f gcc over every *.sh under the component
# root. Ships in the same .deb as the engine; the version below is injected
# from the meson project version at build time (the engine refuses a
# MAJOR.MINOR skew with first-party providers).
set -uo pipefail

VERSION="0.3.2"

list_scripts() { # NUL-separated *.sh under ., excluding build trees and .git
  find . \( -name 'build*' -o -name '.git' \) -prune -o -name '*.sh' -type f -print0 | sort -z
}

case "${1:-}" in
  detect)
    root="${2:-.}"
    if find "$root" \( -name 'build*' -o -name '.git' \) -prune -o -name '*.sh' -type f -print -quit 2>/dev/null | grep -q .; then
      base="$(basename "$(cd "$root" 2>/dev/null && pwd || printf '%s' "$root")")"
      printf '[{"component":"//%s","root":"%s"}]\n' "$base" "$root"
    else
      printf '[]\n'
    fi
    ;;
  capabilities)
    printf '{"schema":"forge.capabilities/v1","provider":"sh","version":"%s","verbs":["lint"],"profiles":[],"scaffold":[]}\n' "$VERSION"
    ;;
  run)
    verb="${2:-}"
    if [ "$verb" != "lint" ]; then
      echo "forge-sh: unsupported verb: ${verb:-<none>}" >&2
      exit 2
    fi
    if ! command -v shellcheck >/dev/null 2>&1; then
      # No result object: a non-zero provider exit makes the core record
      # `error` (fix the environment), never a silent pass.
      echo "forge-sh: shellcheck not found on PATH" >&2
      exit 1
    fi
    mapfile -d '' -t files < <(list_scripts)
    if [ "${#files[@]}" -eq 0 ]; then
      # The discipline applies (the component declared this provider) but
      # there is nothing configured to lint -> missing, it blocks.
      printf '{"verb":"lint","profile":null,"status":"missing"}\n'
      exit 0
    fi
    out="$(shellcheck -x -f gcc "${files[@]}" 2>&1)"
    rc=$?
    if [ "$rc" -eq 0 ]; then
      printf '{"verb":"lint","profile":null,"status":"ok"}\n'
      exit 0
    fi
    # gcc-format lines are file:line:col: severity: msg -- exactly the
    # diagnostics shape (CONTRACT.md section 4).
    diags="$(printf '%s\n' "$out" | awk -F': ' '
      {
        n_pos = split($1, pos, ":")
        if (n_pos < 3 || pos[2] + 0 == 0) next
        file = pos[1]; line = pos[2] + 0; col = pos[3] + 0
        sev = $2
        msg = ""
        for (i = 3; i <= NF; i++) msg = msg (i > 3 ? ": " : "") $i
        gsub(/\\/, "\\\\", file); gsub(/"/, "\\\"", file)
        gsub(/\\/, "\\\\", msg);  gsub(/"/, "\\\"", msg)
        printf "%s{\"file\":\"%s\",\"line\":%d,\"col\":%d,\"severity\":\"%s\",\"msg\":\"%s\"}", (++n > 1 ? "," : ""), file, line, col, sev, msg
      }')"
    printf '{"verb":"lint","profile":null,"status":"fail","diagnostics":[%s]}\n' "$diags"
    ;;
  scaffold)
    echo "forge-sh: scaffold not implemented" >&2
    exit 1
    ;;
  *)
    echo "forge-sh: unknown subcommand: ${1:-<none>}" >&2
    exit 2
    ;;
esac
