#!/usr/bin/env bash
# dev-orchestrator — OpenSpec + OpenCode dev→QA loop with git worktrees
# Zero dependencies beyond git, opencode, openspec. No heavy binaries.
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO="${DEV_FLOW_REPO:-$(pwd)}"
WORKTREE_ROOT="$REPO/../.worktrees"

# ── helpers ──────────────────────────────────────────────────────

_wt_path()  { echo "$WORKTREE_ROOT/$1"; }
_wt_branch(){ echo "dev-flow/$1"; }

_die() { echo "✗ $*" >&2; exit 1; }
_ok()  { echo "✓ $*"; }

# Ensure we're inside a git repo with openspec
_guard() {
    cd "$REPO"
    git rev-parse --show-toplevel >/dev/null 2>&1 || _die "not a git repo: $REPO"
    [ -d openspec ] || _die "openspec not initialized. Run: dev-orchestrator init"
}

# ── commands ─────────────────────────────────────────────────────

cmd_init() {
    cd "$REPO"
    git rev-parse --show-toplevel >/dev/null 2>&1 || _die "not a git repo"

    mkdir -p "$WORKTREE_ROOT"
    [ -d openspec ] && _ok "openspec already initialized" || {
        openspec init --tools opencode --force
        _ok "openspec initialized"
    }

    grep -qxF '.worktrees/' .gitignore 2>/dev/null || {
        echo '.worktrees/' >> .gitignore
        _ok "added .worktrees/ to .gitignore"
    }

    echo ""
    echo "Repo ready. Next: dev-orchestrator spec <feature-name>"
}

cmd_spec() {
    local name="$1"
    _guard

    # ── validate name (kebab-case) ──
    [[ "$name" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]] || _die "name must be kebab-case: add-oauth, fix-login"

    # ── create OpenSpec change ──
    echo "── Creating OpenSpec change: $name ──"
    openspec new change "$name" --json 2>/dev/null || {
        _die "openspec new change failed. Already exists? Run: dev-orchestrator status"
    }

    # ── create worktree ──
    local branch="$(_wt_branch "$name")"
    local wt="$(_wt_path "$name")"
    echo "── Creating worktree: $wt [$branch] ──"
    git worktree add -b "$branch" "$wt" HEAD

    # ── install deps in worktree (fully isolated, no symlinks) ──
    if [ -f "$wt/package.json" ]; then
        echo "── Installing dependencies ──"
        (cd "$wt" && npm install --silent 2>&1 | tail -1) || true
    fi
    if [ -f "$wt/pyproject.toml" ] || [ -f "$wt/setup.py" ]; then
        (cd "$wt" && [ -d .venv ] || python3 -m venv .venv && . .venv/bin/activate && pip install -e . -q 2>&1 | tail -1) || true
    fi

    # ── orchestrator fills the spec ──
    echo "── Orchestrator filling spec ──"
    opencode run \
        "You are filling an OpenSpec change for feature: $name.

         STEPS:
         1. Read the codebase structure first (scan src/, lib/, or equivalent).
         2. Read openspec/changes/$name/ — note the template files created.
         3. Read openspec/specs/ for existing specs to avoid conflicts.
         4. For each template file in the change directory, fill it with:
            - Clear requirements and acceptance criteria
            - Files that need to change
            - Dependencies on other modules
            - Test plan
         5. Run: openspec validate $name --strict
         6. Fix any validation errors, re-run until clean.
         7. Output a summary: spec files created, key decisions, estimated scope." \
        --workdir "$REPO"

    echo ""
    _ok "Spec '$name' ready at openspec/changes/$name/"
    echo "   Worktree: $wt"
    echo "   Review the spec, then: dev-orchestrator build $name"
}

cmd_build() {
    local name="$1"
    _guard

    local wt="$(_wt_path "$name")"
    [ -d "$wt" ] || _die "worktree not found: $wt. Run: dev-orchestrator spec $name"

    local branch="$(_wt_branch "$name")"
    local max_retries=3

    for attempt in $(seq 1 $max_retries); do
        echo ""
        echo "══════════════════════════════════════════════════"
        echo "  $name — Dev Phase (attempt $attempt/$max_retries)"
        echo "══════════════════════════════════════════════════"

        opencode run \
            "IMPLEMENT the spec at openspec/changes/$name/.
             
             RULES:
             - Read openspec instructions --change $name first
             - Implement ALL requirements from the spec
             - Write tests for every new code path
             - Run the test suite and ensure it passes
             - If tests fail, fix them before considering work done
             - Commit with message: '$name: implement feature (attempt $attempt)'
             - Do NOT modify openspec/ files — only source code and tests" \
            --workdir "$wt" || {
            echo "⚠ Dev phase had errors, proceeding to QA anyway..."
        }

        # ── QA phase ──
        echo ""
        echo "──────────────────────────────────────────────────"
        echo "  $name — QA Review"
        echo "──────────────────────────────────────────────────"

        local qa_file="/tmp/dev-orchestrator-qa-$$.txt"
        opencode run \
            "QA REVIEW for $name.

             CHECKLIST (answer each with PASS or FAIL):
             1. SPEC COMPLIANCE — Does the code implement everything in openspec/changes/$name/?
             2. TESTS — Do all tests pass? Run them now.
             3. REGRESSIONS — Does any existing test break? Check git diff vs main.
             4. EDGE CASES — Are errors handled? Null/empty inputs? Timeouts?
             5. CODE QUALITY — Clear naming? No debug leftovers? No commented-out code?

             OUTPUT FORMAT (exactly these 2 lines, nothing else):
             VERDICT: PASS|FAIL
             REASON: <one-sentence summary>" \
            --workdir "$wt" > "$qa_file" 2>&1

        local verdict
        verdict=$(grep '^VERDICT:' "$qa_file" | head -1 | awk -F': ' '{print $2}')
        local reason
        reason=$(grep '^REASON:' "$qa_file" | head -1 | cut -d' ' -f2-)

        if [ "$verdict" = "PASS" ]; then
            echo ""
            _ok "QA PASSED — $reason"

            # ── archive + merge ──
            cd "$REPO"
            echo "── Archiving spec ──"
            openspec archive "$name" --yes 2>/dev/null || true

            echo "── Merging to main ──"
            local current_branch=$(git branch --show-current)
            git merge "$branch" -m "dev-flow: merge $name" 2>/dev/null || {
                echo "⚠ Merge conflict. Resolve manually in $wt then run:"
                echo "   cd $wt && git checkout main && git merge $branch"
                return 1
            }

            echo "── Cleaning up worktree ──"
            git worktree remove "$wt" 2>/dev/null || true
            git branch -d "$branch" 2>/dev/null || true

            echo ""
            _ok "$name — BUILD COMPLETE ✓"
            rm "$qa_file"
            return 0
        fi

        echo ""
        echo "✗ QA FAILED — ${reason:-see $qa_file}"
        rm "$qa_file"

        if [ "$attempt" -eq "$max_retries" ]; then
            _die "$name FAILED after $max_retries attempts. Worktree kept at $wt for manual fix."
        fi
        echo "↻ Sending back to dev with QA feedback..."
    done
}

cmd_status() {
    _guard 2>/dev/null || true

    echo ""
    printf "%-4s %-30s %-10s %-10s %-15s\n" "#" "FEATURE" "COMMITS" "SPEC" "WORKTREE"
    printf "%-4s %-30s %-10s %-10s %-15s\n" "───" "──────────────────────────────" "──────────" "──────────" "──────────────"

    local n=0
    for wt in "$WORKTREE_ROOT"/*/; do
        [ -d "$wt" ] || continue
        local name=$(basename "$wt")
        local branch="$(_wt_branch "$name")"
        local commits="?"
        [ -d "$wt/.git" ] && commits=$(cd "$wt" && git rev-list --count "$branch" -- 2>/dev/null || echo "?")
        commits="${commits:-0}"

        # spec status
        local spec="?"
        [ -d "$REPO/openspec/changes/$name" ] && {
            spec=$(cd "$REPO" && openspec status --change "$name" --json 2>/dev/null | \
                python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('artifacts_completed','?'),'/',d.get('artifacts_total','?'),sep='')" 2>/dev/null || echo "active")
        }

        n=$((n+1))
        printf "%-4s %-30s %-10s %-10s %-15s\n" \
            "$n." "$name" "$commits" "${spec:-active}" "$wt"
    done

    if [ "$n" -eq 0 ]; then
        echo "  (no active features)"
    fi
    echo ""
}

cmd_clean() {
    local name="$1"
    cd "$REPO"
    local wt="$(_wt_path "$name")"
    local branch="$(_wt_branch "$name")"

    git worktree remove "$wt" 2>/dev/null || true
    git branch -D "$branch" 2>/dev/null || true
    [ ! -d "$wt" ] && _ok "cleaned $name" || _die "could not remove $wt"
}

# ── dispatch ─────────────────────────────────────────────────────

case "${1:-}" in
    init)
        cmd_init
        ;;
    spec)
        [ $# -ge 2 ] || _die "usage: dev-orchestrator spec <feature-name>"
        cmd_spec "$2"
        ;;
    build)
        [ $# -ge 2 ] || _die "usage: dev-orchestrator build <feature-name>"
        cmd_build "$2"
        ;;
    status)
        cmd_status
        ;;
    clean)
        [ $# -ge 2 ] || _die "usage: dev-orchestrator clean <feature-name>"
        cmd_clean "$2"
        ;;
    *)
        echo "dev-orchestrator — OpenSpec + OpenCode dev→QA loop"
        echo ""
        echo "commands:"
        echo "  init                       Set up repo (run once per project)"
        echo "  spec   <feature-name>      Create OpenSpec + worktree + fill spec"
        echo "  build  <feature-name>      Dev→QA loop in isolated worktree"
        echo "  status                     Kanban view of features in flight"
        echo "  clean  <feature-name>      Remove worktree + branch"
        echo ""
        echo "flow: init → spec → [review] → build → [loop until QA passes]"
        echo ""
        echo "worktrees live at: ../.worktrees/<feature>/"
        echo "branches named:    dev-flow/<feature>"
        exit 1
        ;;
esac