#!/usr/bin/env bash
# wm-dispatch: Execute action plan tasks via agent sessions.
#
# Usage:
#   wm-dispatch <task-id>              # dispatch one task (foreground)
#   wm-dispatch <task-id> <task-id>...  # dispatch multiple in parallel
#   wm-dispatch --wave <N>             # dispatch all unblocked tasks in wave N
#   wm-dispatch --next [N]             # dispatch next N unblocked tasks (default 1)
#
# Options:
#   --dry-run     Print the prompt instead of dispatching
#   --backend B   Override backend (default: openrouter)
#   --model M     Override model (default: qwen/qwen3-coder)
#   --keep        Keep session on success (failures always kept)
#   --bg          Submit and return immediately (use wm-collect to harvest)
#
# See also: wm-gen (ad-hoc tasks from templates)

set -euo pipefail

ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
TOOLS="$ROOT/tools/wm-port"
MOUNT="${OLLIE:-$HOME/mnt/ollie}"
DONE_FILE="$TOOLS/done.txt"
LOG_DIR="$TOOLS/logs"

source "$TOOLS/task-map.sh"

# Defaults
backend="openrouter"
model="qwen/qwen3-coder"
dry_run=0
keep=0
bg=0
wave=""
next=0
task_ids=()

die() { printf 'wm-dispatch: %s\n' "$*" >&2; exit 1; }

while [ $# -gt 0 ]; do
    case "$1" in
        --dry-run)   dry_run=1 ;;
        --backend)   backend="$2"; shift ;;
        --model)     model="$2"; shift ;;
        --keep)      keep=1 ;;
        --bg)        bg=1 ;;
        --wave)      wave="$2"; shift ;;
        --next)      next="${2:-1}"; shift ;;
        --help|-h)   sed -n '2,/^$/{ s/^# //; s/^#//; p; }' "$0"; exit 0 ;;
        -*)          die "unknown flag: $1" ;;
        *)           task_ids+=("$1") ;;
    esac
    shift
done

mkdir -p "$LOG_DIR"
touch "$DONE_FILE"

# Resolve task list from --wave or --next
if [ -n "$wave" ]; then
    while IFS= read -r tid; do
        [ "${TASK_WAVE[$tid]:-}" = "$wave" ] || continue
        task_is_done "$tid" "$DONE_FILE" && continue
        task_is_unblocked "$tid" "$DONE_FILE" || continue
        task_ids+=("$tid")
    done < <(task_all_ids)
    [ ${#task_ids[@]} -eq 0 ] && die "no unblocked tasks in wave $wave"
elif [ "$next" -gt 0 ]; then
    count=0
    while IFS= read -r tid; do
        task_is_done "$tid" "$DONE_FILE" && continue
        task_is_unblocked "$tid" "$DONE_FILE" || continue
        task_ids+=("$tid")
        (( ++count >= next )) && break
    done < <(task_all_ids)
    [ ${#task_ids[@]} -eq 0 ] && die "no unblocked tasks remaining"
fi

[ ${#task_ids[@]} -eq 0 ] && die "no task IDs specified. Use: wm-dispatch <task-id> or --wave N or --next N"

# Validate all task IDs
for tid in "${task_ids[@]}"; do
    [ -n "${TASK_TEMPLATE[$tid]:-}" ] || die "unknown task ID: $tid"
    task_is_done "$tid" "$DONE_FILE" && die "task $tid is already done"
    task_is_unblocked "$tid" "$DONE_FILE" || {
        blockers="${TASK_BLOCKERS[$tid]}"
        pending=""
        for dep in $blockers; do
            task_is_done "$dep" "$DONE_FILE" || pending="$pending $dep"
        done
        die "task $tid is blocked by:$pending"
    }
done

# ── Extract task block from ACTION_PLAN.md ──
# Finds the section for a given task ID (everything from its header to the next
# header of equal or higher level, or next --- separator).
extract_task_block() {
    local tid="$1"
    local plan="$ROOT/ACTION_PLAN.md"
    
    awk -v tid="$tid" '
        BEGIN { found=0; level=0 }
        /^#{1,6} / {
            if (found) {
                match($0, /^#+/)
                if (RLENGTH <= level) exit
            }
            if (index($0, tid) > 0) {
                match($0, /^#+/)
                level = RLENGTH
                found = 1
            }
        }
        /^---/ { if (found) exit }
        found { print }
    ' "$plan"
}

# ── Extract template block from ACTION_PLAN_PROMPTS.md ──
extract_template() {
    local tnum="$1"
    local prompts="$ROOT/ACTION_PLAN_PROMPTS.md"
    
    awk -v tnum="$tnum" '
        BEGIN { found=0; in_code=0 }
        /^## Template / {
            if (found && !in_code) exit
            if ($0 ~ "Template " tnum ":" || $0 ~ "Template " tnum " ") {
                found=1
                next
            }
        }
        /^## Template [0-9]/ { if (found) exit }
        /^---$/ { if (found && !in_code) exit }
        found { print }
    ' "$prompts"
}

# ── Extract reference tables ──
extract_reference_tables() {
    local prompts="$ROOT/ACTION_PLAN_PROMPTS.md"
    awk '
        /^## Reference Tables/,/^## Template 1/ {
            if (/^## Template 1/) exit
            print
        }
    ' "$prompts"
}

# ── Build the full prompt for a task ──
build_prompt() {
    local tid="$1"
    local tnum="${TASK_TEMPLATE[$tid]}"
    local tname="${TEMPLATE_NAME[$tnum]}"
    
    local task_block
    task_block=$(extract_task_block "$tid")
    [ -n "$task_block" ] || die "could not extract task block for $tid from ACTION_PLAN.md"
    
    local template
    template=$(extract_template "$tnum")
    
    local ref_tables
    ref_tables=$(extract_reference_tables)
    
    if [ "$tnum" -eq 9 ]; then
        # Verification tasks: read-only audit, report findings
        cat <<PROMPT
You are executing a verification task for the WindowMaker Wayland port.
This is a READ-ONLY audit. Do NOT modify any files. Do NOT create branches.

# Task: $tid

## Task Description (from ACTION_PLAN.md)

$task_block

## Procedure (Template $tnum)

$template

## Important Rules

1. Work in the git repository at $ROOT.
2. Run the verification checks described in the procedure.
3. Report findings using the REPORT FORMAT from the procedure.
4. End with exactly one of:
   - DONE: verified clean, no issues found.
   - STOP: found issues that need human decision. List each issue with file:line and a one-line description.
PROMPT
    else
        # Code modification tasks: branch, edit, compile
        cat <<PROMPT
You are executing a mechanical Wayland porting task for WindowMaker.

# Task: $tid ($tname)

## Task Description (from ACTION_PLAN.md)

$task_block

## Procedure (Template $tnum)

$template

$ref_tables

## Important Rules

1. Work in the git repository at $ROOT. Create a git branch named "port/$tid" before making changes.
2. Make exactly the changes described. No more, no less.
3. After making changes, verify with the grep commands in the template.
4. Attempt to compile with: cd $ROOT && make -j\$(nproc) 2>&1 | tail -30
5. If compilation fails, fix the errors. If you cannot fix them, revert and report.
6. If you hit a STOP condition (missing vtable slot, missing API), revert changes and report exactly what is missing.
7. When done, run: git add -A && git diff --cached --stat
8. Report the final status as one of:
   - DONE: task completed, compiles clean
   - STOP: blocked on <reason>
   - FAIL: could not complete because <reason>

Line numbers in ACTION_PLAN.md may have drifted. Use grep to find current line numbers before editing.
PROMPT
    fi
}

# ── Dispatch a single task ──
dispatch_one() {
    local tid="$1"
    local prompt
    prompt=$(build_prompt "$tid")
    
    if [ "$dry_run" -eq 1 ]; then
        echo "════════════════════════════════════════"
        echo "TASK: $tid  (Template ${TASK_TEMPLATE[$tid]}: ${TEMPLATE_NAME[${TASK_TEMPLATE[$tid]}]})"
        echo "════════════════════════════════════════"
        echo "$prompt"
        echo
        return 0
    fi
    
    local session_name="wm-port-${tid}"
    local session_path="$MOUNT/s/$session_name"
    local flags=(
        -name "$session_name"
        -cwd "$ROOT"
        -agent coding
        -backend "$backend"
        -model "$model"
        -keep
    )
    [ "$bg" -eq 1 ] && flags+=(-bg)
    
    printf '\033[1;36m▶ Dispatching %s\033[0m (%s)\n' \
        "$tid" "${TEMPLATE_NAME[${TASK_TEMPLATE[$tid]}]}" >&2
    
    if [ "$bg" -eq 1 ]; then
        local sp
        sp=$(printf '%s' "$prompt" | "$MOUNT/s/b" "${flags[@]}")
        printf '%s\t%s\n' "$tid" "$sp"
        printf '\033[1;33m  → %s\033[0m\n' "$sp" >&2
    else
        local result
        result=$(printf '%s' "$prompt" | "$MOUNT/s/b" "${flags[@]}" 2>/dev/null) || true
        
        # Save log
        printf '%s\n' "$result" > "$LOG_DIR/${tid}.log"
        
        # Parse result status — search broadly since agents format varies
        local status="UNKNOWN"
        local should_keep="$keep"
        if [ -z "$result" ] || echo "$result" | head -1 | grep -q '^user:'; then
            status="FAIL"
            should_keep=1
            printf '\033[1;31m✗ %s: FAIL (agent produced no response)\033[0m\n' "$tid" >&2
        elif echo "$result" | grep -qiE '\*\*DONE\*\*|^DONE:|^DONE\b|Status:.*DONE|DONE: task completed|DONE: verified'; then
            status="DONE"
            echo "$tid" >> "$DONE_FILE"
            printf '\033[1;32m✓ %s: DONE\033[0m\n' "$tid" >&2
        elif echo "$result" | grep -qiE '\*\*STOP\*\*|^STOP:|^STOP\b|Status:.*STOP|STOP: blocked'; then
            status="STOP"
            should_keep=1
            printf '\033[1;33m⚠ %s: STOP\033[0m\n' "$tid" >&2
            echo "$result" | grep -iE 'STOP' | head -3 | sed 's/^/  /' >&2
        elif echo "$result" | grep -qiE '\*\*FAIL\*\*|^FAIL:|^FAIL\b|Status:.*FAIL|FAIL: could not'; then
            status="FAIL"
            should_keep=1
            printf '\033[1;31m✗ %s: FAIL\033[0m\n' "$tid" >&2
            echo "$result" | grep -iE 'FAIL' | head -3 | sed 's/^/  /' >&2
        else
            if echo "$result" | grep -qiE 'compiles clean|no action needed'; then
                status="DONE"
                echo "$tid" >> "$DONE_FILE"
                printf '\033[1;32m✓ %s: DONE (inferred from output)\033[0m\n' "$tid" >&2
            else
                status="UNKNOWN"
                should_keep=1
                printf '\033[1;35m? %s: status unclear — review log\033[0m\n' "$tid" >&2
                echo "$result" | grep -v '^$' | tail -5 | sed 's/^/  /' >&2
            fi
        fi
        
        printf '  Log: %s\n' "$LOG_DIR/${tid}.log" >&2
        
        # Clean up session: keep on failure/unclear for inspection, kill on success
        if [ "$should_keep" -eq 1 ]; then
            printf '  Session: %s\n' "$session_path" >&2
        elif [ -d "$session_path" ]; then
            echo kill > "$session_path/ctl" 2>/dev/null || true
        fi
    fi
}

# ── Main ──
if [ ${#task_ids[@]} -eq 1 ]; then
    dispatch_one "${task_ids[0]}"
else
    # Multiple tasks: dispatch in parallel (background mode)
    printf '\033[1;36m▶ Dispatching %d tasks in parallel\033[0m\n' ${#task_ids[@]} >&2
    
    pids=()
    for tid in "${task_ids[@]}"; do
        dispatch_one "$tid" &
        pids+=($!)
    done
    
    # Wait for all
    rc=0
    for pid in "${pids[@]}"; do
        wait "$pid" || rc=1
    done
    exit $rc
fi
