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

VERSION="1.1.1"
TIMEOUT="${CLINE_TIMEOUT:-0}"
THINKING="${CLINE_THINKING:-high}"
RETRIES="${CLINE_RETRIES:-5}"

usage() {
  cat <<'USAGE'
askcline 1.1.1 - every task runs through Cline's full agent harness

Usage:
  askcline <task...>               Complete a task autonomously in the current workspace
  askcline                         Open the interactive Cline agent in the current workspace
  askcline agent <task...>         Explicit alias for the default agent mode
  askcline plan <task...>          Investigate and plan without autonomous edits
  askcline verify <question...>    Read-only research with evidence and abstention requirements
  askcline text <prompt...>        Read-only harness-backed direct answer
  askcline raw <prompt...>         Deprecated alias for `text`; still uses the harness
  askcline doctor                  Run the official Cline diagnostics
  askcline --version

Agent environment:
  ASKCLINE_AUTO_APPROVE  true/false (default: true)
  ASKCLINE_JSON          true/false NDJSON output (default: false)
  ASKCLINE_UNRESTRICTED  true bypasses the catastrophic-command deny policy
  CLINE_MODEL            Optional model override; otherwise use Cline configuration
  CLINE_PROVIDER         Optional provider override
  CLINE_TIMEOUT          Seconds; 0 means no timeout (default: 0)
  CLINE_THINKING         none|low|medium|high|xhigh (default: high)
  CLINE_RETRIES          Consecutive mistake limit (default: 5)
USAGE
}

fail() { printf 'askcline: %s\n' "$*" >&2; exit 1; }
need() { command -v "$1" >/dev/null 2>&1 || fail "missing dependency: $1"; }

validate_bool() {
  case "$2" in
    true|false) ;;
    *) fail "$1 must be true or false" ;;
  esac
}

apply_agent_guardrails() {
  local unrestricted="${ASKCLINE_UNRESTRICTED:-false}"
  validate_bool ASKCLINE_UNRESTRICTED "$unrestricted"
  if [ "$unrestricted" = false ] && [ -z "${CLINE_COMMAND_PERMISSIONS+x}" ]; then
    export CLINE_COMMAND_PERMISSIONS='{"deny":["sudo *","rm -rf /","rm -rf /*","rm -rf ~*","git push --force*","git push --force-with-lease*","git push -f *","git reset --hard*","git clean -fdx*"],"allowRedirects":true}'
  fi
}

cline_args() {
  local auto="$1"
  local json="$2"
  CLINE_ARGS=(--cwd "$PWD" --auto-approve "$auto" --thinking "$THINKING" --retries "$RETRIES")
  if [ "$TIMEOUT" != 0 ]; then CLINE_ARGS+=(--timeout "$TIMEOUT"); fi
  if [ -n "${CLINE_MODEL:-}" ]; then CLINE_ARGS+=(--model "$CLINE_MODEL"); fi
  if [ -n "${CLINE_PROVIDER:-}" ]; then CLINE_ARGS+=(--provider "$CLINE_PROVIDER"); fi
  if [ "$json" = true ]; then CLINE_ARGS+=(--json); fi
}

agent_mode() {
  need cline
  [ "$#" -gt 0 ] || fail "agent mode requires a task"
  local auto="${ASKCLINE_AUTO_APPROVE:-true}"
  local json="${ASKCLINE_JSON:-false}"
  validate_bool ASKCLINE_AUTO_APPROVE "$auto"
  validate_bool ASKCLINE_JSON "$json"
  apply_agent_guardrails
  cline_args "$auto" "$json"

  local task
  task="$(cat <<EOF_TASK
Operate as an end-to-end coding agent. Complete the user task in the current workspace rather than stopping at analysis or a plan.

Required loop:
1. Inspect the repository and existing instructions before changing anything.
2. Form a concise implementation plan internally.
3. Implement the smallest complete solution while preserving unrelated work.
4. Run the relevant formatter, linter, type checker, tests, and build that exist in the repository.
5. Diagnose failures and iterate until validation passes or a concrete external blocker remains.
6. Re-read the diff for correctness, security, and accidental scope expansion.
7. Finish with a concise summary of changes, exact validation performed, and any remaining risk.

Never claim a check passed unless you ran it. Do not push, merge, publish, or release unless the user explicitly asks for that action.

USER TASK:
$*
EOF_TASK
)"
  exec cline "${CLINE_ARGS[@]}" "$task"
}

interactive_mode() {
  need cline
  apply_agent_guardrails
  exec cline --cwd "$PWD"
}

plan_mode() {
  need cline
  [ "$#" -gt 0 ] || fail "plan mode requires a task"
  local json="${ASKCLINE_JSON:-false}"
  validate_bool ASKCLINE_JSON "$json"
  apply_agent_guardrails
  cline_args false "$json"
  exec cline "${CLINE_ARGS[@]}" --plan "$*"
}

verify_mode() {
  need cline
  [ "$#" -gt 0 ] || fail "verify mode requires a question"
  local json="${ASKCLINE_JSON:-false}"
  validate_bool ASKCLINE_JSON "$json"
  export CLINE_COMMAND_PERMISSIONS="${CLINE_COMMAND_PERMISSIONS:-{\"allow\":[\"git status\",\"git diff*\",\"git log*\",\"rg *\",\"find *\",\"cat *\"],\"deny\":[\"rm *\",\"sudo *\",\"git push*\",\"git reset*\",\"git clean*\"],\"allowRedirects\":false}}"
  cline_args false "$json"

  local task
  task="$(cat <<EOF_TASK
Operate in read-only verification mode. Do not modify files.

For every material factual claim:
1. Disambiguate the entity or event.
2. Retrieve evidence before accepting the premise.
3. Cite only sources you actually inspected.
4. Separate source facts from your inference.
5. State uncertainty and conflicting evidence.
6. Correct a false premise or abstain when evidence is insufficient.

QUESTION:
$*
EOF_TASK
)"
  exec cline "${CLINE_ARGS[@]}" --plan "$task"
}

text_mode() {
  need cline
  [ "$#" -gt 0 ] || fail "text mode requires a prompt"
  local json="${ASKCLINE_JSON:-false}"
  validate_bool ASKCLINE_JSON "$json"
  apply_agent_guardrails
  cline_args false "$json"

  local task
  task="$(cat <<EOF_TASK
Answer the user directly through the Cline harness in read-only Plan mode. Do not modify repository files. Use tools only when needed for accuracy. Return the useful final answer without narrating internal steps.

USER PROMPT:
$*
EOF_TASK
)"
  exec cline "${CLINE_ARGS[@]}" --plan "$task"
}

doctor_mode() {
  need cline
  exec cline doctor
}

case "${1:-}" in
  -h|--help) usage ;;
  -V|--version) printf '%s\n' "$VERSION" ;;
  '') interactive_mode ;;
  --) shift; agent_mode "$@" ;;
  agent) shift; agent_mode "$@" ;;
  plan) shift; plan_mode "$@" ;;
  verify) shift; verify_mode "$@" ;;
  text) shift; text_mode "$@" ;;
  raw) shift; printf 'askcline: raw is deprecated; routing through the Cline harness\n' >&2; text_mode "$@" ;;
  doctor) shift; doctor_mode "$@" ;;
  *) agent_mode "$@" ;;
esac
