/**
 * Quality Gate — runs configurable pre-completion checks (lint, typecheck, test)
 * in a session's working directory and reports results.
 */

import { createLogger } from "./logger.js";

const log = createLogger("quality-gate");

// ─── Types ────────────────────────────────────────────────────────────────────

export interface QualityGateCheck {
  name: string;
  command: string;
  enabled: boolean;
  timeoutSeconds: number;
}

export interface QualityGateConfig {
  enabled: boolean;
  checks: QualityGateCheck[];
}

export interface QualityGateCheckResult {
  name: string;
  command: string;
  passed: boolean;
  output: string;
  durationMs: number;
}

export interface QualityGateResult {
  checks: QualityGateCheckResult[];
  allPassed: boolean;
}

// ─── Defaults ─────────────────────────────────────────────────────────────────

const DEFAULT_TIMEOUT_SECONDS = 120;
const MAX_OUTPUT_LENGTH = 50_000;

export const DEFAULT_QUALITY_GATE_CONFIG: QualityGateConfig = {
  enabled: false,
  checks: [
    { name: "Lint", command: "npm run lint", enabled: true, timeoutSeconds: DEFAULT_TIMEOUT_SECONDS },
    { name: "Type Check", command: "npx tsc --noEmit", enabled: true, timeoutSeconds: DEFAULT_TIMEOUT_SECONDS },
    { name: "Tests", command: "npm test", enabled: true, timeoutSeconds: DEFAULT_TIMEOUT_SECONDS },
  ],
};

// ─── Runner ───────────────────────────────────────────────────────────────────

/**
 * Run a single quality gate check in the given working directory.
 * Returns the result including pass/fail, captured output, and duration.
 */
async function runCheck(
  check: QualityGateCheck,
  workDir: string,
): Promise<QualityGateCheckResult> {
  const startTime = Date.now();

  try {
    const proc = Bun.spawn(["sh", "-c", check.command], {
      cwd: workDir,
      env: { ...process.env, CI: "true", FORCE_COLOR: "0" },
      stdout: "pipe",
      stderr: "pipe",
    });

    // Set up timeout
    const timeoutMs = check.timeoutSeconds * 1000;
    const timeoutPromise = new Promise<"timeout">((resolve) =>
      setTimeout(() => resolve("timeout"), timeoutMs),
    );

    const exitPromise = proc.exited;
    const race = await Promise.race([exitPromise, timeoutPromise]);

    if (race === "timeout") {
      proc.kill();
      const durationMs = Date.now() - startTime;
      log.warn({ name: check.name, command: check.command, timeoutMs }, "Quality gate check timed out");
      return {
        name: check.name,
        command: check.command,
        passed: false,
        output: `Check timed out after ${check.timeoutSeconds}s`,
        durationMs,
      };
    }

    const exitCode = race;
    const stdout = await new Response(proc.stdout).text();
    const stderr = await new Response(proc.stderr).text();
    const combinedOutput = [stdout, stderr].filter(Boolean).join("\n").slice(0, MAX_OUTPUT_LENGTH);
    const durationMs = Date.now() - startTime;

    return {
      name: check.name,
      command: check.command,
      passed: exitCode === 0,
      output: combinedOutput || (exitCode === 0 ? "Check passed" : `Exited with code ${exitCode}`),
      durationMs,
    };
  } catch (err) {
    const durationMs = Date.now() - startTime;
    const message = err instanceof Error ? err.message : String(err);
    log.error({ name: check.name, command: check.command, err: message }, "Quality gate check failed to execute");
    return {
      name: check.name,
      command: check.command,
      passed: false,
      output: `Failed to execute: ${message}`,
      durationMs,
    };
  }
}

/**
 * Run all enabled quality gate checks sequentially in the given working directory.
 */
export async function runQualityGate(
  workDir: string,
  config: QualityGateConfig,
): Promise<QualityGateResult> {
  const enabledChecks = config.checks.filter((c) => c.enabled);

  if (enabledChecks.length === 0) {
    log.info("No quality gate checks enabled, skipping");
    return { checks: [], allPassed: true };
  }

  log.info({ workDir, checkCount: enabledChecks.length }, "Running quality gate checks");

  const results: QualityGateCheckResult[] = [];

  for (const check of enabledChecks) {
    log.info({ name: check.name, command: check.command }, "Running quality gate check");
    const result = await runCheck(check, workDir);
    results.push(result);
    log.info(
      { name: result.name, passed: result.passed, durationMs: result.durationMs },
      "Quality gate check completed",
    );
  }

  const allPassed = results.every((r) => r.passed);
  log.info({ allPassed, total: results.length, passed: results.filter((r) => r.passed).length }, "Quality gate completed");

  return { checks: results, allPassed };
}
