import {
  resolveConfig
} from "./chunk-PW3U4YJV.js";
import {
  init_dist
} from "./chunk-4DWOMGUM.js";
import {
  Ok
} from "./chunk-RL4VMEXL.js";
import {
  logger
} from "./chunk-EBJQ6N4M.js";
import {
  ExitCode
} from "./chunk-3WGJMBKH.js";

// src/commands/check-phase-gate.ts
init_dist();
import { Command } from "commander";
import * as path from "path";
import * as fs from "fs";

// src/utils/files.ts
import { glob } from "glob";
async function findFiles(pattern, cwd = process.cwd()) {
  return glob(pattern, { cwd, absolute: true });
}

// src/output/formatter.ts
import chalk from "chalk";
var OutputMode = {
  /** Output as formatted JSON */
  JSON: "json",
  /** Output as human-readable text */
  TEXT: "text",
  /** Minimal output, only errors and successes */
  QUIET: "quiet",
  /** Full output with detailed context and suggestions */
  VERBOSE: "verbose"
};
function appendIssueLines(lines, issue, mode) {
  const location = issue.file ? issue.line ? `${issue.file}:${issue.line}` : issue.file : "unknown";
  lines.push(`  ${chalk.yellow("*")} ${chalk.dim(location)}`);
  lines.push(`    ${issue.message}`);
  if (issue.suggestion && mode === OutputMode.VERBOSE) {
    lines.push(`    ${chalk.dim("->")} ${issue.suggestion}`);
  }
}
var OutputFormatter = class {
  /**
   * Creates a new OutputFormatter.
   *
   * @param mode - The output mode to use. Defaults to TEXT.
   */
  constructor(mode = OutputMode.TEXT) {
    this.mode = mode;
  }
  mode;
  /**
   * Formats raw data for output.
   *
   * @param data - The data to format.
   * @returns A string representation of the data based on the current mode.
   */
  format(data) {
    if (this.mode === OutputMode.JSON) {
      return JSON.stringify(data, null, 2);
    }
    return String(data);
  }
  /**
   * Formats a validation result into a user-friendly string.
   *
   * @param result - The validation result to format.
   * @returns A formatted string containing the validation status and any issues.
   */
  formatValidation(result) {
    if (this.mode === OutputMode.JSON) {
      return JSON.stringify(result, null, 2);
    }
    if (this.mode === OutputMode.QUIET) {
      if (result.valid) return "";
      return result.issues.map((i) => `${i.file ?? ""}: ${i.message}`).join("\n");
    }
    const lines = [];
    if (result.valid) {
      lines.push(chalk.green("v validation passed"));
    } else {
      lines.push(chalk.red(`x Validation failed (${result.issues.length} issues)`));
      lines.push("");
      for (const issue of result.issues) {
        appendIssueLines(lines, issue, this.mode);
      }
    }
    return lines.join("\n");
  }
  /**
   * Formats a summary line with a success/failure icon and label.
   *
   * @param label - The name of the field to summarize.
   * @param value - The value to display.
   * @param success - Whether the summary represents a success or failure state.
   * @returns A formatted summary string, or an empty string in JSON or QUIET modes.
   */
  formatSummary(label, value, success) {
    if (this.mode === OutputMode.JSON || this.mode === OutputMode.QUIET) {
      return "";
    }
    const icon = success ? chalk.green("v") : chalk.red("x");
    return `${icon} ${label}: ${value}`;
  }
};

// src/commands/check-phase-gate.ts
function resolveSpecPath(implFile, implPattern, specPattern, cwd) {
  const relImpl = path.relative(cwd, implFile).replace(/\\/g, "/");
  const implBase = (implPattern.split("*")[0] ?? "").replace(/\/+$/, "");
  const afterBase = relImpl.startsWith(implBase + "/") ? relImpl.slice(implBase.length + 1) : relImpl;
  const segments = afterBase.split("/");
  const firstSegment = segments[0] ?? "";
  const feature = segments.length > 1 ? firstSegment : path.basename(firstSegment, path.extname(firstSegment));
  const specRelative = specPattern.replace("{feature}", feature);
  return path.resolve(cwd, specRelative);
}
function checkSpecContent(specPath, relImpl, relSpec, missingSpecs) {
  const content = fs.readFileSync(specPath, "utf-8");
  const sectionPattern = /^#+\s*(Observable Truths|Success Criteria|Acceptance Criteria)/im;
  const sectionMatch = sectionPattern.exec(content);
  if (!sectionMatch) {
    missingSpecs.push({
      implFile: relImpl,
      expectedSpec: `${relSpec} (missing requirements section: expected Observable Truths, Success Criteria, or Acceptance Criteria heading)`
    });
    return;
  }
  const sectionStart = sectionMatch.index + sectionMatch[0].length;
  const nextHeadingMatch = /^#+\s/m.exec(content.slice(sectionStart));
  const sectionContent = nextHeadingMatch ? content.slice(sectionStart, sectionStart + nextHeadingMatch.index) : content.slice(sectionStart);
  if (!/^\s*\d+\.\s+/m.test(sectionContent)) {
    missingSpecs.push({
      implFile: relImpl,
      expectedSpec: `${relSpec} (requirements section "${sectionMatch[1]}" has no numbered items)`
    });
  }
}
async function runCheckPhaseGate(options) {
  const configResult = resolveConfig(options.configPath);
  if (!configResult.ok) {
    return configResult;
  }
  const config = configResult.value;
  const cwd = options.cwd ?? (options.configPath ? path.dirname(path.resolve(options.configPath)) : process.cwd());
  if (!config.phaseGates?.enabled) {
    return Ok({
      pass: true,
      skipped: true,
      missingSpecs: [],
      checkedFiles: 0
    });
  }
  const phaseGates = config.phaseGates;
  const missingSpecs = [];
  let checkedFiles = 0;
  for (const mapping of phaseGates.mappings) {
    const implFiles = await findFiles(mapping.implPattern, cwd);
    for (const implFile of implFiles) {
      checkedFiles++;
      const expectedSpec = resolveSpecPath(implFile, mapping.implPattern, mapping.specPattern, cwd);
      const relImpl = path.relative(cwd, implFile).replace(/\\/g, "/");
      const relSpec = path.relative(cwd, expectedSpec).replace(/\\/g, "/");
      if (!fs.existsSync(expectedSpec)) {
        missingSpecs.push({ implFile: relImpl, expectedSpec: relSpec });
      } else if (mapping.contentValidation) {
        checkSpecContent(expectedSpec, relImpl, relSpec, missingSpecs);
      }
    }
  }
  const pass = missingSpecs.length === 0;
  return Ok({
    pass,
    skipped: false,
    severity: phaseGates.severity,
    missingSpecs,
    checkedFiles
  });
}
function resolvePhaseGateOutputMode(globalOpts) {
  if (globalOpts.json) return OutputMode.JSON;
  if (globalOpts.quiet) return OutputMode.QUIET;
  if (globalOpts.verbose) return OutputMode.VERBOSE;
  return OutputMode.TEXT;
}
function handlePhaseGateError(error, mode) {
  if (mode === OutputMode.JSON) {
    console.log(JSON.stringify({ error: error.message }));
  } else {
    logger.error(error.message);
  }
  process.exit(error.exitCode);
}
function handlePhaseGateSkipped(value, mode, formatter) {
  if (mode === OutputMode.JSON) {
    console.log(formatter.format(value));
  } else if (mode !== OutputMode.QUIET) {
    logger.dim("Phase gates not enabled, skipping.");
  }
  process.exit(ExitCode.SUCCESS);
}
function printPhaseGateResult(value, formatter) {
  const output = formatter.formatValidation({
    valid: value.pass,
    issues: value.missingSpecs.map((m) => ({
      file: m.implFile,
      message: `Missing spec: ${m.expectedSpec}`
    }))
  });
  if (output) console.log(output);
  const summary = formatter.formatSummary(
    "Phase gate check",
    `${value.checkedFiles} files checked, ${value.missingSpecs.length} missing specs`,
    value.pass
  );
  if (summary) console.log(summary);
}
function createCheckPhaseGateCommand() {
  const command = new Command("check-phase-gate").description("Verify that implementation files have matching spec documents").action(async (_opts, cmd) => {
    const globalOpts = cmd.optsWithGlobals();
    const mode = resolvePhaseGateOutputMode(globalOpts);
    const formatter = new OutputFormatter(mode);
    const result = await runCheckPhaseGate({
      configPath: globalOpts.config,
      json: globalOpts.json,
      verbose: globalOpts.verbose,
      quiet: globalOpts.quiet
    });
    if (!result.ok) handlePhaseGateError(result.error, mode);
    const value = result.value;
    if (value.skipped) handlePhaseGateSkipped(value, mode, formatter);
    printPhaseGateResult(value, formatter);
    if (!value.pass && value.severity === "error") {
      process.exit(ExitCode.VALIDATION_FAILED);
    }
    process.exit(ExitCode.SUCCESS);
  });
  return command;
}

export {
  OutputMode,
  OutputFormatter,
  findFiles,
  runCheckPhaseGate,
  createCheckPhaseGateCommand
};
