#!/usr/bin/env ts-node
import * as path from 'path';
import { promises as fs } from 'fs';
import { SequentialOrchestrator } from '../src/backend/services/SequentialOrchestrator.ts';
import type { WorkflowStage, WorkflowContext } from '../src/backend/services/SequentialOrchestrator.ts';
import { WorkflowStatusManager } from '../src/backend/services/WorkflowStatusManager.ts';

type RunWorkflowOptions = {
  mode?: 'start' | 'resume' | 'restart';
  checkpointPath?: string;
  statusPath?: string;
  progressLogPath?: string;
  maxRetriesPerPhase?: number;
  now?: Date;
};

type CliArgs = {
  mode: 'start' | 'resume' | 'restart';
  checkpointPath?: string;
  statusPath?: string;
  progressLogPath?: string;
  maxRetriesPerPhase?: number;
};

const DEFAULT_CHECKPOINT_PATH = path.join(process.cwd(), 'status', 'workflow-checkpoint.json');
const DEFAULT_STATUS_PATH = path.join(process.cwd(), 'status', 'workflow-status.json');
const DEFAULT_PROGRESS_LOG_PATH = path.join(process.cwd(), 'status', 'workflow-progress.jsonl');

function parseCliArgs(argv: string[]): CliArgs {
  const out: CliArgs = { mode: 'resume' };

  for (let i = 0; i < argv.length; i += 1) {
    const arg = argv[i];
    const next = argv[i + 1];

    if (arg === '--mode' && next) {
      if (next === 'start' || next === 'resume' || next === 'restart') {
        out.mode = next;
        i += 1;
      }
      continue;
    }

    if (arg === '--checkpoint' && next) {
      out.checkpointPath = next;
      i += 1;
      continue;
    }

    if (arg === '--status' && next) {
      out.statusPath = next;
      i += 1;
      continue;
    }

    if (arg === '--progress-log' && next) {
      out.progressLogPath = next;
      i += 1;
      continue;
    }

    if (arg === '--max-retries' && next) {
      const parsed = Number.parseInt(next, 10);
      if (Number.isFinite(parsed) && parsed >= 0) {
        out.maxRetriesPerPhase = parsed;
      }
      i += 1;
      continue;
    }
  }

  return out;
}

function createTimestampedSummary(label: string, now: Date): string {
  return `${label} @ ${now.toISOString()}`;
}

function createStages(now: Date): WorkflowStage[] {
  return [
    {
      id: 'review-plan',
      name: 'Review TODO and roadmap',
      execute: async (_context: WorkflowContext) => {
        const todoPath = path.join(process.cwd(), 'TODO.md');
        const roadmapPath = path.join(process.cwd(), 'ROADMAP.md');
        const todo = await fs.readFile(todoPath, 'utf8');
        const roadmap = await fs.readFile(roadmapPath, 'utf8');
        const todoLines = todo.split(/\r?\n/).length;
        const roadmapLines = roadmap.split(/\r?\n/).length;
        return {
          summary: createTimestampedSummary(`Loaded planning docs (TODO: ${todoLines} lines, ROADMAP: ${roadmapLines} lines)`, now),
          metadata: { todoLines, roadmapLines },
          nextAction: 'Proceed to implementation stage.',
        };
      },
    },
    {
      id: 'verify-build',
      name: 'Verify TypeScript build',
      execute: async (_context: WorkflowContext) => {
        // Lightweight validation step to keep workflow deterministic in tests.
        const packageJsonPath = path.join(process.cwd(), 'package.json');
        const pkgRaw = await fs.readFile(packageJsonPath, 'utf8');
        const pkg = JSON.parse(pkgRaw) as { scripts?: Record<string, string> };
        const hasBuildScript = Boolean(pkg.scripts?.build);

        if (!hasBuildScript) {
          throw new Error('Missing required npm script: build');
        }

        return {
          summary: createTimestampedSummary('Validated project scripts and build entrypoint', now),
          metadata: { hasBuildScript },
          nextAction: 'Proceed to tests stage.',
        };
      },
    },
    {
      id: 'verify-tests',
      name: 'Verify test command availability',
      execute: async (_context: WorkflowContext) => {
        const packageJsonPath = path.join(process.cwd(), 'package.json');
        const pkgRaw = await fs.readFile(packageJsonPath, 'utf8');
        const pkg = JSON.parse(pkgRaw) as { scripts?: Record<string, string> };
        const hasTestScript = Boolean(pkg.scripts?.test);

        if (!hasTestScript) {
          throw new Error('Missing required npm script: test');
        }

        return {
          summary: createTimestampedSummary('Validated test script presence', now),
          metadata: { hasTestScript },
          nextAction: 'Workflow checks complete.',
        };
      },
    },
  ];
}

export async function runWorkflow(options: RunWorkflowOptions = {}): Promise<void> {
  const checkpointPath = options.checkpointPath ?? DEFAULT_CHECKPOINT_PATH;
  const statusPath = options.statusPath ?? DEFAULT_STATUS_PATH;
  const progressLogPath = options.progressLogPath ?? DEFAULT_PROGRESS_LOG_PATH;
  const mode = options.mode ?? 'resume';
  const maxRetriesPerPhase = options.maxRetriesPerPhase ?? 1;
  const now = options.now ?? new Date();

  const workflow = new SequentialOrchestrator({
    checkpointPath,
    maxRetriesPerPhase,
    statusManager: new WorkflowStatusManager(statusPath),
    progressLogPath,
  });

  const initialContext: WorkflowContext = {
    runId: `workflow-${now.toISOString()}`,
    startedAt: now.toISOString(),
    metadata: {
      initiatedBy: 'scripts/run-workflow.ts',
      mode,
    },
  };

  const stages = createStages(now);

  if (mode === 'restart' || mode === 'start') {
    await workflow.start(stages, initialContext);
    return;
  }

  await workflow.resume(stages, initialContext);
}

if (import.meta.url === `file://${process.argv[1]}`) {
  const args = parseCliArgs(process.argv.slice(2));

  runWorkflow({
    mode: args.mode,
    checkpointPath: args.checkpointPath,
    statusPath: args.statusPath,
    progressLogPath: args.progressLogPath,
    maxRetriesPerPhase: args.maxRetriesPerPhase,
  }).catch((error) => {
    const message = error instanceof Error ? error.message : String(error);
    console.error(`[workflow:run] failed: ${message}`);
    process.exitCode = 1;
  });
}
