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

ROOT="${XH1_RESEARCH_ROOT:-research}"
CONFIG="${XH1_RESEARCH_CONFIG:-xh1-research.conf}"
STATE="${ROOT}/.xh1"

API_BASE_URL="${API_BASE_URL:-https://openrouter.ai/api/v1}"
API_KEY_ENV="${API_KEY_ENV:-OPENROUTER_API_KEY}"

RESEARCH_MODEL="${RESEARCH_MODEL:-}"
REVIEW_MODEL="${REVIEW_MODEL:-$RESEARCH_MODEL}"
REVISION_MODEL="${REVISION_MODEL:-$RESEARCH_MODEL}"

MAX_RESEARCH_ROUNDS="${MAX_RESEARCH_ROUNDS:-3}"
MAX_API_RETRIES="${MAX_API_RETRIES:-3}"
DELAY_SECONDS="${DELAY_SECONDS:-5}"
MAX_ITERATIONS="${MAX_ITERATIONS:-0}"

REVIEW_ENABLED="${REVIEW_ENABLED:-true}"
AUTO_COMMIT="${AUTO_COMMIT:-false}"

RUN_ID=""

mkdir -p "$STATE/logs" "$STATE/responses" "$STATE/runs"

die() {
    echo "ERROR: $*" >&2
    exit 1
}

log() {
    echo "[$(date -u '+%Y-%m-%dT%H:%M:%SZ')] $*" |
        tee -a "$STATE/logs/harness.log"
}

require() {
    command -v "$1" >/dev/null 2>&1 ||
        die "Required command not found: $1"
}

require_dependencies() {
    require bash
    require curl
    require jq
    require find
    require grep
    require sed
    require awk
}

timestamp() {
    date -u '+%Y%m%dT%H%M%SZ'
}

load_config() {
    if [[ -f "$CONFIG" ]]; then
        # shellcheck disable=SC1090
        source "$CONFIG"
    fi
}

get_api_key() {
    local key="${!API_KEY_ENV:-}"

    [[ -n "$key" ]] ||
        die "Missing API key. Set ${API_KEY_ENV}."

    printf '%s' "$key"
}

start_run() {
    RUN_ID="$(timestamp)"

    mkdir -p "$STATE/runs/$RUN_ID"

    : > "$STATE/runs/$RUN_ID/completed"
    : > "$STATE/runs/$RUN_ID/failed"
    : > "$STATE/runs/$RUN_ID/attempts"

    log "Started run: $RUN_ID"
}

run_has_completed() {
    grep -Fxq "$1" "$STATE/runs/$RUN_ID/completed" 2>/dev/null
}

run_has_failed() {
    grep -Fxq "$1" "$STATE/runs/$RUN_ID/failed" 2>/dev/null
}

mark_completed() {
    printf '%s\n' "$1" >> "$STATE/runs/$RUN_ID/completed"
}

mark_failed() {
    printf '%s\n' "$1" >> "$STATE/runs/$RUN_ID/failed"
}

record_attempt() {
    printf '%s\t%s\t%s\t%s\t%s\n' \
        "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" \
        "$1" "$2" "$3" "$4" \
        >> "$STATE/runs/$RUN_ID/attempts"
}

is_soon() {
    grep -qE '^SOON[[:space:]]*$' "$1"
}

find_next_task() {
    while IFS= read -r -d '' file; do

        [[ "$file" == "$STATE"/* ]] && continue

        if is_soon "$file" &&
           ! run_has_completed "$file" &&
           ! run_has_failed "$file"
        then
            printf '%s\n' "$file"
            return 0
        fi

    done < <(
        find "$ROOT" \
            -type f \
            -name '*.md' \
            -not -path "$STATE/*" \
            -print0
    )

    return 1
}

build_context() {
    local file="$1"
    local relative="${file#"$ROOT"/}"
    local area="${relative%%/*}"

    cat <<EOF
XH-1 RESEARCH PROJECT
=====================

Project:
XH-1

Architecture:
Custom 128-core RISC-V processor

Repository:
XH-1 Research

Current document:
$file

Research area:
$area

CURRENT DOCUMENT
================

$(cat "$file")

RELATED DOCUMENTS
=================

EOF

    if [[ -d "$ROOT/$area" ]]; then
        find "$ROOT/$area" \
            -maxdepth 1 \
            -type f \
            -name '*.md' \
            ! -path "$file" |
            sort |
            head -20 |
            while read -r related; do
                echo
                echo "----- $related -----"
                cat "$related"
            done
    fi
}

research_system_prompt() {
cat <<'EOF'
You are a senior computer architecture researcher working on
the XH-1 processor project.

XH-1 is a custom 128-core RISC-V CPU.

Produce rigorous engineering research.

Never invent:
- citations
- papers
- measurements
- benchmarks
- processor capabilities
- URLs
- experimental results

Clearly distinguish:
FACT
ASSUMPTION
PROPOSAL
RECOMMENDATION
OPEN QUESTION

If evidence is unavailable, say INSUFFICIENT EVIDENCE.

Quantitative claims must have an identifiable source or must
be explicitly labeled as estimates.

Always consider:
- latency
- throughput
- area
- power
- energy
- bandwidth
- scalability
- contention
- implementation complexity
- verification complexity
- software implications
- 128-core replication

Do not assume XH-1 is in-order or out-of-order unless the
repository context establishes that fact.

Return ONLY the Markdown document.
EOF
}

research_user_prompt() {
    local file="$1"

    cat <<EOF
Research the following XH-1 topic:

$(build_context "$file")

Produce a complete engineering research document.

Use sections where applicable:

# Topic

## Status

## Abstract

## Research Question

## Background

## Existing Approaches

## Alternative Designs

## Comparison

## Advantages

## Disadvantages

## XH-1 Considerations

## 128-Core Scalability

## Performance Considerations

## Area Considerations

## Power and Energy Considerations

## Implementation Considerations

## Verification Considerations

## Software Considerations

## Recommendation

## Confidence

## Open Questions

## Sources

Do not force a recommendation if evidence is insufficient.
EOF
}

review_system_prompt() {
cat <<'EOF'
You are the independent technical reviewer for XH-1.

XH-1 is a custom 128-core RISC-V processor.

Aggressively check research for:

- factual errors
- incorrect RISC-V information
- unsupported claims
- fabricated citations
- fabricated measurements
- contradictory recommendations
- missing alternatives
- missing assumptions
- failure to consider 128-core scaling
- unrealistic implementation claims
- unsupported performance claims
- unsupported area claims
- unsupported power claims
- weak verification reasoning
- incorrect terminology
- insufficient source specificity
- assumptions presented as facts

Check quantitative claims especially carefully.

Check whether recommendations actually follow from the analysis.

Check that the document distinguishes:
FACT
ASSUMPTION
PROPOSAL
RECOMMENDATION
OPEN QUESTION

Return exactly:

VERDICT: PASS

or:

VERDICT: FAIL

Then:

ISSUES:
- ...

REQUIRED_FIXES:
- ...

CONFIDENCE: HIGH/MEDIUM/LOW
EOF
}

review_user_prompt() {
    local document="$1"

    cat <<EOF
Review this XH-1 research document independently.

DOCUMENT
========

$(cat "$document")

END DOCUMENT

Identify every substantive technical problem.

Do not rewrite the document.

Return a PASS only when the research is technically acceptable,
internally consistent, and sufficiently supported.
EOF
}

revision_system_prompt() {
cat <<'EOF'
You are a senior computer architecture researcher revising
research for the XH-1 128-core RISC-V CPU.

The previous version was rejected by an independent reviewer.

Fix every substantive reviewer issue.

You must:
- correct factual errors
- remove unsupported quantitative claims
- add missing alternatives
- reconcile contradictions
- make assumptions explicit
- improve citations
- reconsider unsupported recommendations
- consider 128-core scaling
- consider area
- consider power
- consider energy
- consider implementation
- consider verification

Never invent evidence.

If evidence cannot be established, write:
INSUFFICIENT EVIDENCE

Do not merely respond to the reviewer.

Produce a clean replacement document.

Return ONLY Markdown.
EOF
}

revision_user_prompt() {
    local document="$1"
    local review="$2"

    cat <<EOF
Revise this XH-1 research document.

ORIGINAL
========

$(cat "$document")

REVIEW
======

$(cat "$review")

Fix every substantive issue.

Do not add a response-to-reviewer section.

Return the complete corrected Markdown document only.
EOF
}

api_call() {
    local system_prompt="$1"
    local user_prompt="$2"
    local output="$3"
    local model="$4"

    local key
    key="$(get_api_key)"

    [[ -n "$model" ]] ||
        die "No model configured."

    local payload
    payload="$(
        jq -n \
            --arg model "$model" \
            --arg system "$system_prompt" \
            --arg user "$user_prompt" \
            '{
                model: $model,
                messages: [
                    {role:"system", content:$system},
                    {role:"user", content:$user}
                ],
                temperature:0.2
            }'
    )"

    local attempt=1

    while (( attempt <= MAX_API_RETRIES )); do

        local json="${output}.json"

        log "API request: model=$model attempt=$attempt"

        if curl \
            --fail \
            --silent \
            --show-error \
            --connect-timeout 30 \
            --max-time 1800 \
            -H "Authorization: Bearer ${key}" \
            -H "Content-Type: application/json" \
            -H "HTTP-Referer: https://github.com/riscvcxh1/xh1-research" \
            -H "X-Title: XH-1 Research Harness" \
            "${API_BASE_URL%/}/chat/completions" \
            -d "$payload" > "$json"
        then

            if jq -er \
                '.choices[0].message.content' \
                "$json" > "$output"
            then
                log "API response received: $(wc -c < "$output" | tr -d ' ') bytes"
                return 0
            fi
        fi

        log "API request failed."

        sleep $((attempt * attempt))
        ((attempt++))
    done

    return 1
}

replace_soon() {
    local target="$1"
    local replacement="$2"

    is_soon "$target" ||
        die "Safety check failed: $target is no longer SOON."

    cp "$replacement" "$target"
}

git_commit() {
    [[ "$AUTO_COMMIT" == "true" ]] || return 0

    git rev-parse --is-inside-work-tree >/dev/null 2>&1 || return 0

    git add "$1"

    git commit \
        -m "research: $(basename "$1" .md | tr '-' ' ')" ||
        true
}

research_topic() {
    local file="$1"

    log "=================================================="
    log "Researching: $file"
    log "=================================================="

    local round=1

    local current="$STATE/runs/$RUN_ID/${file//\//_}.current.md"
    local review="$STATE/runs/$RUN_ID/${file//\//_}.review.md"

    while (( round <= MAX_RESEARCH_ROUNDS )); do

        log "Research round $round/$MAX_RESEARCH_ROUNDS"

        local candidate="$STATE/runs/$RUN_ID/${file//\//_}.round${round}.md"

        if (( round == 1 )); then

            log "Running researcher."

            if ! api_call \
                "$(research_system_prompt)" \
                "$(research_user_prompt "$file")" \
                "$candidate" \
                "$RESEARCH_MODEL"
            then
                record_attempt "$file" "$round" "research" "api-failure"
                mark_failed "$file"
                return 1
            fi

            record_attempt "$file" "$round" "research" "completed"

        else

            log "Running revision agent."

            if ! api_call \
                "$(revision_system_prompt)" \
                "$(revision_user_prompt "$current" "$review")" \
                "$candidate" \
                "$REVISION_MODEL"
            then
                record_attempt "$file" "$round" "revision" "api-failure"
                mark_failed "$file"
                return 1
            fi

            record_attempt "$file" "$round" "revision" "completed"
        fi

        cp "$candidate" "$current"

        if [[ "$REVIEW_ENABLED" != "true" ]]; then
            replace_soon "$file" "$candidate"
            mark_completed "$file"
            git_commit "$file"
            return 0
        fi

        log "Running reviewer."

        if ! api_call \
            "$(review_system_prompt)" \
            "$(review_user_prompt "$candidate")" \
            "$review" \
            "$REVIEW_MODEL"
        then
            record_attempt "$file" "$round" "review" "api-failure"
            mark_failed "$file"
            return 1
        fi

        echo
        echo "=========================================="
        echo "RESEARCH REVIEW"
        echo "=========================================="
        cat "$review"
        echo "=========================================="
        echo

        local verdict
        verdict="$(grep -m1 '^VERDICT:' "$review" || true)"

        record_attempt "$file" "$round" "review" "$verdict"

        if [[ "$verdict" == "VERDICT: PASS" ]]; then

            log "Research PASSED review."
            replace_soon "$file" "$candidate"
            mark_completed "$file"
            git_commit "$file"

            log "Completed: $file"

            return 0
        fi

        log "Research rejected by reviewer."

        if (( round >= MAX_RESEARCH_ROUNDS )); then

            log "Maximum research rounds reached."
            log "Leaving original document unchanged."
            log "Marking topic failed for this run."

            mark_failed "$file"

            return 2
        fi

        log "Preparing revision round $((round + 1))."

        ((round++))

        sleep "$DELAY_SECONDS"
    done

    mark_failed "$file"
    return 2
}

run_single() {
    start_run

    local file="${1:-}"

    if [[ -z "$file" ]]; then
        file="$(find_next_task || true)"
    fi

    [[ -n "$file" ]] ||
        die "No research topics remain."

    research_topic "$file"
}

run_all() {
    start_run

    local iteration=0

    while true; do

        if (( MAX_ITERATIONS > 0 &&
              iteration >= MAX_ITERATIONS )); then

            log "Maximum run iterations reached."
            break
        fi

        local file
        file="$(find_next_task || true)"

        if [[ -z "$file" ]]; then
            log "No remaining research topics."
            break
        fi

        ((iteration += 1))

        echo
        echo "##################################################"
        echo "XH-1 AUTONOMOUS RESEARCH"
        echo "Iteration: $iteration"
        echo "Topic: $file"
        echo "##################################################"
        echo

        research_topic "$file" || true

        sleep "$DELAY_SECONDS"
    done

    status
}

status() {
    local total
    local soon

    total="$(
        find "$ROOT" \
            -type f \
            -name '*.md' \
            -not -path "$STATE/*" |
        wc -l |
        tr -d ' '
    )"

    soon="$(
        grep -RIl \
            '^SOON[[:space:]]*$' \
            "$ROOT" \
            --include='*.md' \
            --exclude-dir='.xh1' \
            2>/dev/null |
        wc -l |
        tr -d ' '
    )"

    local completed=$((total - soon))

    echo
    echo "╔══════════════════════════════════════════╗"
    echo "║          XH-1 RESEARCH STATUS            ║"
    echo "╚══════════════════════════════════════════╝"
    echo

    printf "  Total documents : %s\n" "$total"
    printf "  Completed       : %s\n" "$completed"
    printf "  Remaining SOON  : %s\n" "$soon"

    if (( total > 0 )); then
        awk \
            -v done="$completed" \
            -v total="$total" \
            'BEGIN {
                printf "  Progress        : %.1f%%\n",
                (done / total) * 100
            }'
    fi

    echo
    echo "Next topic:"
    find_next_task || echo "  None"
    echo
}

reset_failure() {
    local file="${1:-}"

    [[ -n "$file" ]] ||
        die "Usage: $0 reset-failure <file>"

    [[ -f "$file" ]] ||
        die "File does not exist: $file"

    if [[ -n "$RUN_ID" &&
          -f "$STATE/runs/$RUN_ID/failed" ]]; then

        sed -i "\|^${file}$|d" \
            "$STATE/runs/$RUN_ID/failed"
    fi

    log "Failure reset: $file"
}

review_command() {
    local file="${1:-}"

    [[ -n "$file" ]] ||
        die "Usage: $0 review <file>"

    [[ -f "$file" ]] ||
        die "File does not exist: $file"

    local output="$STATE/manual-review-$(timestamp).md"

    api_call \
        "$(review_system_prompt)" \
        "$(review_user_prompt "$file")" \
        "$output" \
        "$REVIEW_MODEL"

    cat "$output"
}

help() {
cat <<'HELP'

XH-1 RESEARCH HARNESS

COMMANDS

  init
      Create configuration.

  status
      Show research status.

  next
      Show next SOON document.

  run
      Research the next topic.

  run <file>
      Research a specific topic.

  run-all
      Process all SOON documents.

      Each topic:

          RESEARCH
              |
              v
           REVIEW
              |
          +---+---+
          |       |
         PASS    FAIL
          |       |
          v       v
        WRITE   REVISE
                  |
                  v
                REVIEW

      Maximum rounds are controlled by:

          MAX_RESEARCH_ROUNDS

  review <file>
      Manually review a document.

  reset-failure <file>
      Clear a failed topic from the current run.

  help
      Show this help.


SAFETY

A document is only replaced after:

    VERDICT: PASS

If all rounds fail:

    The original SOON file remains untouched.

The failed topic is skipped for the remainder of that run.


CONFIGURATION

API_BASE_URL
API_KEY_ENV
RESEARCH_MODEL
REVIEW_MODEL
REVISION_MODEL
MAX_RESEARCH_ROUNDS
MAX_API_RETRIES
DELAY_SECONDS
MAX_ITERATIONS
REVIEW_ENABLED
AUTO_COMMIT


EXAMPLE

  export OPENROUTER_API_KEY="..."

  ./xh1-research status

  ./xh1-research run

  ./xh1-research run-all

HELP
}

load_config
require_dependencies

case "${1:-status}" in
    init)
        echo "Configuration is created manually in $CONFIG."
        exit 0
        ;;

    status)
        status
        ;;

    next)
        find_next_task || true
        ;;

    run)
        run_single "${2:-}"
        ;;

    run-all|loop|resume)
        run_all
        ;;

    review)
        review_command "${2:-}"
        ;;

    reset-failure)
        reset_failure "${2:-}"
        ;;

    help|-h|--help)
        help
        ;;

    *)
        die "Unknown command: $1. Use ./xh1-research help"
        ;;
esac
