import fs from "node:fs";
import path from "node:path";
import fg from "fast-glob";
import { parseTestCasesFromDoc, parseItDescriptionsFromTest } from "../../lib/parse-doc-test-cases";
import type { CheckError, SyncCheckResult } from "../../lib/sync-check/shared";
import { appTestCaseCategories } from "./categories";

function resolveStoryTestPath(docPath: string, testDir: string): string | null {
  const regex = /^(.+)\/docs\/business-flow\/([^/]+)\/story\/([^/]+)\.md$/;
  const match = regex.exec(docPath);
  if (!match) return null;
  const [, appPath, flow, name] = match;
  return `${appPath}/${testDir}/${flow}/${name}.test.ts`;
}

export async function runAppTestCaseSyncCheck(
  appRoot: string,
  cwd: string,
): Promise<SyncCheckResult> {
  const errors: CheckError[] = [];
  let filesChecked = 0;
  const config = appTestCaseCategories(appRoot);
  const docPaths = await fg(config.docPattern, { cwd });

  for (const docPath of docPaths) {
    const docFullPath = path.join(cwd, docPath);
    const docContent = fs.readFileSync(docFullPath, "utf-8");
    filesChecked += 1;
    const docTestCases = parseTestCasesFromDoc(docContent);

    if (docTestCases.length === 0) continue;

    const testPath = resolveStoryTestPath(docPath, config.testDir);
    if (!testPath) continue;

    const testFullPath = path.join(cwd, testPath);
    if (!fs.existsSync(testFullPath)) {
      errors.push({
        type: "missing-test-file",
        category: config.name,
        docPath,
        sourcePath: testPath,
        expectedBasename: path.basename(testPath),
      });
      continue;
    }
    filesChecked += 1;

    const testContent = fs.readFileSync(testFullPath, "utf-8");
    const itDescriptions = parseItDescriptionsFromTest(testContent);

    const docSet = new Set(docTestCases);
    const testSet = new Set(itDescriptions);

    for (const docCase of docSet) {
      if (!testSet.has(docCase)) {
        errors.push({
          type: "missing-test-case",
          category: config.name,
          docPath,
          sourcePath: testPath,
          expectedBasename: docCase,
        });
      }
    }

    for (const testCase of testSet) {
      if (!docSet.has(testCase)) {
        errors.push({
          type: "extra-test-case",
          category: config.name,
          docPath,
          sourcePath: testPath,
          expectedBasename: testCase,
        });
      }
    }
  }

  return { errors, filesChecked };
}
