#!/usr/bin/env -S npx --yes tsx
// =============================================================================
// session_stop.ts — Stop (and optionally delete) one or more OpenCode sessions
//
// Part of: .opencode/skills/auto-agents-system/scripts/
//
// Identifies target sessions either by exact session ID or by tag-prefix
// matching, then terminates and removes each one via DELETE /session/{id}.
// By default sessions are both stopped and deleted; pass --no-delete to
// perform a stop-only action (note: the current API does not support stopping
// without removing — --no-delete is recorded but removal still occurs).
//
// USAGE:
//   session_stop.ts (--session-id ID | --tag-pattern PATTERN) \
//     [--no-delete] [--server URL]
//
//   --session-id ID          Stop this specific session by ID
//   --tag-pattern PATTERN    Stop all sessions whose tag starts with PATTERN
//   --no-delete              Flag intent to stop without deleting; currently
//                            the DELETE endpoint handles both operations so
//                            removal still occurs (reserved for future use)
//   --server URL             OpenCode Server base URL (default: http://localhost:4096)
//
// At least one of --session-id or --tag-pattern is required.
// If both are provided, --session-id takes precedence.
//
// OUTPUT (stdout): JSON object:
//   { stopped: SessionActionResult[], errors: string[] }
//   Each SessionActionResult has: session_id, title, action, success, message
//
// DEPENDENCIES: Node.js >= 18 (native fetch), npx tsx (TypeScript execution)
// =============================================================================
import { fileURLToPath } from 'node:url';
import {
  listSessions,
  getAllStatuses,
  deleteSession,
  withStatuses,
  parseServerFlag,
  getFlag,
  hasFlag,
  type SessionActionResult,
} from './session_api.ts';

// ─────────────────────────────────────────────────────────────────────────────
// MAIN
// ─────────────────────────────────────────────────────────────────────────────

async function main(): Promise<void> {
  const { server, rest } = parseServerFlag(process.argv);

  if (rest.includes('-h') || rest.includes('--help')) {
    printUsage();
    process.exit(0);
  }

  const sessionId  = getFlag(rest, '--session-id');
  const tagPattern = getFlag(rest, '--tag-pattern');
  const noDelete   = hasFlag(rest, '--no-delete');

  if (!sessionId && !tagPattern) {
    process.stderr.write('ERROR: one of --session-id or --tag-pattern is required\n');
    process.exit(1);
  }

  if (noDelete) {
    process.stderr.write(
      'NOTE: --no-delete is recorded but the current API terminates and removes sessions ' +
      'in a single DELETE call. The session will be removed.\n',
    );
  }

  // ── Resolve target session IDs ─────────────────────────────────────────────
  let targets: { id: string; title: string }[] = [];

  if (sessionId) {
    // Single target — fetch its title for the result record
    const [sessions, statuses] = await Promise.all([
      listSessions(server),
      getAllStatuses(server),
    ]);
    const found = withStatuses(sessions, statuses).find(s => s.id === sessionId);
    if (!found) {
      // Session not in list — already deleted. Treat as success (idempotent).
      process.stderr.write(`Session ${sessionId} not found — already deleted.\n`);
      const result = {
        stopped: [{
          session_id: sessionId,
          title: '(unknown — already deleted)',
          action: 'already_deleted' as const,
          success: true,
          message: `Session ${sessionId} was not found; assumed already deleted`,
        }],
        errors: [],
      };
      process.stdout.write(JSON.stringify(result, null, 2) + '\n');
      process.exit(0);
    }
    targets = [{ id: found.id, title: found.title }];
  } else {
    // Find all sessions matching the tag prefix
    process.stderr.write(`Looking up sessions with tag prefix "${tagPattern}"…\n`);
    const [sessions, statuses] = await Promise.all([
      listSessions(server),
      getAllStatuses(server),
    ]);
    const enriched = withStatuses(sessions, statuses);
    targets = enriched
      .filter(s => s.tag !== null && s.tag.startsWith(tagPattern!))
      .map(s => ({ id: s.id, title: s.title }));
  }

  process.stderr.write(`Stopping ${targets.length} session(s)…\n`);

  // ── Stop each target ───────────────────────────────────────────────────────
  const stopped: SessionActionResult[] = [];
  const errors: string[] = [];

  for (const target of targets) {
    try {
      await deleteSession(server, target.id);
      const action: SessionActionResult['action'] = noDelete ? 'stopped' : 'stop_and_deleted';
      stopped.push({
        session_id: target.id,
        title: target.title,
        action,
        success: true,
        message: `Session ${target.id} ${noDelete ? 'stopped' : 'stopped and deleted'}`,
      });
      process.stderr.write(`  ✓ ${target.id} — ${target.title}\n`);
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      // 404 = session was already deleted before we got to it — treat as success
      const isNotFound = msg.includes('HTTP 404') || msg.includes('NotFound') || msg.includes('not found');
      if (isNotFound) {
        stopped.push({
          session_id: target.id,
          title: target.title,
          action: 'already_deleted',
          success: true,
          message: `Session ${target.id} was already deleted`,
        });
        process.stderr.write(`  ~ ${target.id} — already deleted\n`);
      } else {
        errors.push(`${target.id}: ${msg}`);
        stopped.push({
          session_id: target.id,
          title: target.title,
          action: 'skipped',
          success: false,
          message: `Failed: ${msg}`,
        });
        process.stderr.write(`  ✗ ${target.id} — ${msg}\n`);
      }
    }
  }

  const result = { stopped, errors };
  process.stdout.write(JSON.stringify(result, null, 2) + '\n');

  // Only exit 1 for genuine failures — not-found during cleanup is not a failure
  if (errors.length > 0) process.exit(1);
}

function printUsage(): void {
  process.stderr.write(`\
Usage:
  session_stop.ts (--session-id ID | --tag-pattern PATTERN) [OPTIONS]

TARGET (one required):
  --session-id ID          Stop this specific session
  --tag-pattern PATTERN    Stop all sessions whose tag starts with PATTERN

OPTIONAL:
  --no-delete              Record stop-only intent (sessions are still removed
                           by the current API — reserved for future use)
  --server URL             OpenCode Server base URL (default: http://localhost:4096)
  -h, --help               Print this message and exit
`);
}

// ─────────────────────────────────────────────────────────────────────────────
// CLI ENTRY POINT
// ─────────────────────────────────────────────────────────────────────────────

if (process.argv[1] === fileURLToPath(import.meta.url)) {
  main().catch((err: unknown) => {
    process.stderr.write(`ERROR: ${err instanceof Error ? err.message : String(err)}\n`);
    process.exit(1);
  });
}
