#!/usr/bin/env node
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import path from "node:path";

const argv = process.argv.slice(2);
const command = argv[0] || "";
const taskId = argv[1] || "";
const cwd = process.cwd();
const specPath = path.join(cwd, ".scafld", "specs", "drafts", `${taskId}.md`);

if (command === "--version" || command === "version") {
  process.stdout.write("scafld 2.4.0\n");
  process.exit(0);
}

switch (command) {
  case "init":
    mkdirSync(path.join(cwd, ".scafld", "specs", "drafts"), { recursive: true });
    emit({ ok: true, command, result: { Root: cwd, Created: [] } });
    break;
  case "plan":
    ensure(taskId, "task_id is required for plan");
    mkdirSync(path.dirname(specPath), { recursive: true });
    if (!existsSync(specPath)) {
      writeFileSync(specPath, renderSpec({ status: "draft" }));
    }
    emit({
      ok: true,
      command,
      result: {
        task_id: taskId,
        path: relativeToCwd(specPath),
        status: "draft",
      },
    });
    break;
  case "validate":
    ensure(taskId, "task_id is required for validate");
    validateSpec();
    emit({
      ok: true,
      command,
      result: {
        task_id: taskId,
        path: relativeToCwd(specPath),
        valid: true,
        errors: null,
      },
    });
    break;
  case "approve":
    ensure(taskId, "task_id is required for approve");
    ensure(existsSync(specPath), "draft spec missing");
    replaceStatus("approved");
    emit({
      ok: true,
      command,
      result: {
        task_id: taskId,
        status: "approved",
        path: relativeToCwd(specPath),
      },
    });
    break;
  case "build":
    ensure(taskId, "task_id is required for build");
    replaceStatus("review");
    emit({
      ok: true,
      command,
      result: {
        task_id: taskId,
        status: "review",
        passed: 1,
        failed: 0,
      },
    });
    break;
  case "status":
    ensure(taskId, "task_id is required for status");
    emit({
      ok: true,
      command,
      result: {
        task_id: taskId,
        status: currentStatus(),
        title: readTitle(),
        next: currentStatus() === "completed" ? "none" : "scafld review " + taskId,
        session_ok: true,
      },
    });
    break;
  case "review":
    ensure(taskId, "task_id is required for review");
    emit({
      ok: true,
      command,
      result: {
        task_id: taskId,
        verdict: "pass",
        findings: null,
      },
    });
    break;
  case "complete":
    ensure(taskId, "task_id is required for complete");
    replaceStatus("completed");
    emit({
      ok: true,
      command,
      result: {
        spec_version: "2.0",
        task_id: taskId,
        title: readTitle(),
        summary: "Harness summary",
        status: "completed",
        review: {
          status: "completed",
          verdict: "pass",
        },
      },
    });
    break;
  case "handoff":
    ensure(taskId, "task_id is required for handoff");
    process.stdout.write(`# Handoff: ${readTitle()}\n\nStatus: ${currentStatus()}\nNext: none\n`);
    break;
  default:
    process.stderr.write(`unsupported command: ${command}\n`);
    process.exit(1);
}

function ensure(value, message) {
  if (!value) {
    throw new Error(message);
  }
}

function emit(payload) {
  process.stdout.write(`${JSON.stringify(payload)}\n`);
}

function currentStatus() {
  if (!existsSync(specPath)) {
    return "draft";
  }
  const match = readFileSync(specPath, "utf8").match(/^status:\s*([^\n]+)$/m);
  return match?.[1]?.trim().replace(/^['"]|['"]$/g, "") || "draft";
}

function readTitle() {
  if (!existsSync(specPath)) {
    return "Harness Task";
  }
  const match = readFileSync(specPath, "utf8").match(/^#\s+(.+)$/m);
  return match?.[1]?.trim() || "Harness Task";
}

function replaceStatus(status) {
  const contents = existsSync(specPath) ? readFileSync(specPath, "utf8") : renderSpec({ status });
  writeFileSync(specPath, contents.replace(/^status:\s*.+$/m, `status: ${status}`));
}

function validateSpec() {
  const contents = existsSync(specPath) ? readFileSync(specPath, "utf8") : "";
  const errors = [];
  if (!/^#\s+\S+/m.test(contents)) {
    errors.push("title is required");
  }
  if (errors.length === 0) {
    return;
  }
  emit({
    ok: false,
    command,
    error: {
      code: "validation_failed",
      message: errors.join("; "),
      exit_code: 3,
    },
  });
  process.exit(3);
}

function renderSpec({ status }) {
  return `---
spec_version: '2.0'
task_id: ${taskId}
created: '2026-05-04T00:00:00Z'
updated: '2026-05-04T00:00:00Z'
status: ${status}
harden_status: not_run
size: micro
risk_level: low
---

# Harness Task

## Current State

Status: ${status}
Current phase: none
Next: none
Reason: none
Blockers: none
Allowed follow-up command: none
Latest runner update: none
Review gate: not_started

## Summary

Harness summary

## Context

CWD: \`. \`

Packages:
- fixture

Files impacted:
- \`README.md\`

Invariants:
- bounded_scope

Related docs:
- none

## Objectives

- Update README.md.

## Scope

- \`README.md\`

## Dependencies

- None.

## Assumptions

- None.

## Touchpoints

- README.md

## Risks

- None.

## Acceptance

Profile: standard

Definition of done:
- [ ] \`dod1\` README.md contains fixture guidance.

Validation:
- [ ] \`v1\` test - README contains fixture guidance.
  - Command: \`test -f README.md\`
  - Expected kind: \`exit_code_zero\`
  - Status: pending

## Phase 1: Update README

Goal: Update README.md.

Status: pending
Dependencies: none

Changes:
- \`README.md\` (all, exclusive) - Update README.md.

Acceptance:
- [ ] \`ac1_1\` test - README exists.
  - Command: \`test -f README.md\`
  - Expected kind: \`exit_code_zero\`
  - Status: pending

## Rollback

Strategy: per_phase

Commands:
- none

## Review

Status: not_started
Verdict: none

Findings:
- none

Passes:
- none

## Self Eval

Status: not_started

Notes:
none

Improvements:
- none

## Deviations

- none

## Metadata

Tags:
- fixture

## Origin

Source:
- harness

Repo:
- none

Git:
- none

Sync:
- none

Supersession:
- none

## Harden Rounds

- none

## Planning Log

- none
`;
}

function relativeToCwd(targetPath) {
  return path.relative(cwd, targetPath);
}
