import chalk from "chalk";
import { APP_PATHS } from "../paths";
import type { CheckError, SyncCheckResult } from "./shared";

export function formatSyncCheckReport(result: SyncCheckResult): string {
  const lines: string[] = [];
  lines.push(chalk.bold("docs-sync-check: Checking source-documentation correspondence...\n"));
  const checked = result.filesChecked;

  if (result.errors.length > 0) {
    lines.push(chalk.red.bold("Errors:\n"));
    const byCategory = new Map<string, CheckError[]>();
    for (const error of result.errors) {
      const existing = byCategory.get(error.category) ?? [];
      existing.push(error);
      byCategory.set(error.category, existing);
    }
    for (const [category, categoryErrors] of byCategory) {
      lines.push(chalk.cyan(`  Category: ${category}\n`));
      for (const error of categoryErrors) {
        if (error.type === "missing-doc") {
          lines.push(`  ${chalk.red(error.sourcePath)}`);
          lines.push(`    ${chalk.yellow("Missing documentation for:")} ${error.expectedBasename}`);
        } else if (error.type === "orphaned-doc") {
          lines.push(`  ${chalk.red(error.docPath)}`);
          lines.push(
            `    ${chalk.yellow("Orphaned documentation:")} no source file for ${error.expectedBasename}`,
          );
        } else if (error.type === "missing-test-case") {
          lines.push(`  ${chalk.red(error.sourcePath)}`);
          lines.push(
            `    ${chalk.yellow("Missing test case:")} "${error.expectedBasename}" is in doc but not in test`,
          );
        } else if (error.type === "extra-test-case") {
          lines.push(`  ${chalk.red(error.sourcePath)}`);
          lines.push(
            `    ${chalk.yellow("Extra test case:")} "${error.expectedBasename}" is in test but not in doc`,
          );
        } else if (error.type === "missing-test-file") {
          lines.push(`  ${chalk.red(error.docPath)}`);
          lines.push(`    ${chalk.yellow("Missing test file:")} ${error.expectedBasename}`);
        } else if (error.type === "orphaned-spec") {
          lines.push(`  ${chalk.red(error.sourcePath)}`);
          lines.push(
            `    ${chalk.yellow("Orphaned spec file:")} no matching business flow for ${error.expectedBasename}`,
          );
        } else if (error.type === "missing-actor-doc") {
          lines.push(`  ${chalk.red(error.sourcePath)}`);
          lines.push(
            `    ${chalk.yellow("Missing actor doc:")} no ${APP_PATHS.docs.actor}/${error.expectedBasename} for fixture actor`,
          );
        } else if (error.type === "missing-actor-fixture") {
          lines.push(`  ${chalk.red(error.docPath)}`);
          lines.push(
            `    ${chalk.yellow("Missing actor fixture:")} no e2e fixture for actor "${error.expectedBasename}"`,
          );
        } else if (error.type === "missing-page-object") {
          lines.push(`  ${chalk.red(error.docPath)}`);
          lines.push(
            `    ${chalk.yellow("Missing page object:")} no e2e page object for ${error.expectedBasename}`,
          );
        } else if (error.type === "missing-spec-fixture") {
          lines.push(`  ${chalk.red(error.sourcePath)}`);
          lines.push(
            `    ${chalk.yellow("Missing spec fixture:")} no e2e/fixtures/${error.expectedBasename} for spec file`,
          );
        }
        lines.push("");
      }
    }
  } else if (checked === 0) {
    lines.push(chalk.yellow("No files were checked — verify the path.\n"));
  } else {
    lines.push(chalk.green("All source files have corresponding documentation.\n"));
  }

  lines.push(chalk.bold("Summary:"));
  lines.push(`  Files checked: ${checked}`);
  lines.push(`  Errors: ${result.errors.length}`);
  lines.push("");

  if (result.errors.length > 0) {
    lines.push(chalk.red.bold(`docs-sync-check failed with ${result.errors.length} error(s).`));
  } else if (checked === 0) {
    lines.push(chalk.red.bold("docs-sync-check failed: no files were checked."));
  } else {
    lines.push(chalk.green.bold("docs-sync-check passed."));
  }

  return lines.join("\n");
}
