import {
  isCodeFile,
  validateAutomatedTestRequirement
} from "./chunk-U7I7FS7T.js";
import {
  parseYAML
} from "./chunk-NRIZR3A7.js";
import {
  DIRECTORIES
} from "./chunk-DWMLTXKQ.js";
import {
  GIT_DIRECTORY_NAME,
  WU_STATUS
} from "./chunk-V6OJGLBA.js";
import {
  ErrorCodes,
  createError,
  getErrorMessage
} from "./chunk-RXRKBBSM.js";

// ../core/dist/invariants-runner.js
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
import path2 from "path";
import { globSync } from "glob";

// ../core/dist/invariants/check-automated-tests.js
import { existsSync, readdirSync, readFileSync } from "fs";
import path from "path";
var INVARIANT_ID = "INV-AUTOMATED-TESTS-FOR-CODE";
var INVARIANT_TYPE = "wu-automated-tests";
var ACTIVE_STATUSES = Object.freeze([WU_STATUS.IN_PROGRESS, WU_STATUS.BLOCKED]);
var WU_YAML_PATH = DIRECTORIES.WU_DIR;
function checkWUFile(filePath, options = {}) {
  const { skipStatusCheck = false } = options;
  try {
    const content = readFileSync(filePath, "utf-8");
    const doc = parseYAML(content);
    if (!doc) {
      return { valid: true, wuId: null, error: null };
    }
    const wuId = doc.id || path.basename(filePath, ".yaml");
    const status = doc.status || "";
    if (!skipStatusCheck && !ACTIVE_STATUSES.includes(status)) {
      return { valid: true, wuId, error: null };
    }
    const result = validateAutomatedTestRequirement(doc);
    if (!result.valid) {
      return {
        valid: false,
        wuId,
        error: result.errors.join("\n"),
        codeFiles: getCodeFilesFromPaths(doc.code_paths || [])
      };
    }
    return { valid: true, wuId, error: null };
  } catch {
    return { valid: true, wuId: null, error: null };
  }
}
function getCodeFilesFromPaths(codePaths) {
  if (!codePaths || !Array.isArray(codePaths)) {
    return [];
  }
  return codePaths.filter((p) => isCodeFile(p));
}
function checkAutomatedTestsInvariant(options = {}) {
  const { baseDir = process.cwd(), wuId } = options;
  const wuDir = path.join(baseDir, WU_YAML_PATH);
  const violations = [];
  if (!existsSync(wuDir)) {
    return { valid: true, violations: [] };
  }
  if (wuId) {
    const filePath = path.join(wuDir, `${wuId}.yaml`);
    if (!existsSync(filePath)) {
      return { valid: true, violations: [] };
    }
    const result = checkWUFile(filePath, { skipStatusCheck: true });
    if (!result.valid) {
      violations.push({
        id: INVARIANT_ID,
        type: INVARIANT_TYPE,
        wuId: result.wuId,
        description: `WU ${result.wuId} has code files but no automated tests`,
        message: result.error,
        codeFiles: result.codeFiles
      });
    }
    return {
      valid: violations.length === 0,
      violations
    };
  }
  let files;
  try {
    files = readdirSync(wuDir).filter((f) => f.startsWith("WU-") && (f.endsWith(".yaml") || f.endsWith(".yml")));
  } catch {
    return { valid: true, violations: [] };
  }
  for (const file of files) {
    const filePath = path.join(wuDir, file);
    const result = checkWUFile(filePath);
    if (!result.valid) {
      violations.push({
        id: INVARIANT_ID,
        type: INVARIANT_TYPE,
        wuId: result.wuId,
        description: `WU ${result.wuId} has code files but no automated tests`,
        message: result.error,
        codeFiles: result.codeFiles
      });
    }
  }
  return {
    valid: violations.length === 0,
    violations
  };
}

// ../core/dist/invariants-runner.js
var INVARIANT_TYPES = {
  REQUIRED_FILE: "required-file",
  FORBIDDEN_FILE: "forbidden-file",
  MUTUAL_EXCLUSIVITY: "mutual-exclusivity",
  FORBIDDEN_PATTERN: "forbidden-pattern",
  // WU-2254: New invariant types
  REQUIRED_PATTERN: "required-pattern",
  FORBIDDEN_IMPORT: "forbidden-import",
  // WU-2333: WU automated tests invariant
  WU_AUTOMATED_TESTS: "wu-automated-tests"
};
var EXCLUDED_DIRS = ["node_modules", "worktrees", ".next", "dist", GIT_DIRECTORY_NAME];
var checkerRegistry = /* @__PURE__ */ new Map();
function registerInvariantChecker(type, checker) {
  checkerRegistry.set(type, checker);
}
function getInvariantChecker(type) {
  return checkerRegistry.get(type);
}
var RequiredFileChecker = class {
  validate(invariant, baseDir) {
    if (typeof invariant.path !== "string") {
      return {
        ...invariant,
        valid: false,
        path: invariant.path
      };
    }
    const fullPath = path2.join(baseDir, invariant.path);
    if (!existsSync2(fullPath)) {
      return {
        ...invariant,
        valid: false,
        path: invariant.path
      };
    }
    return null;
  }
};
var ForbiddenFileChecker = class {
  validate(invariant, baseDir) {
    if (typeof invariant.path !== "string") {
      return null;
    }
    const fullPath = path2.join(baseDir, invariant.path);
    if (existsSync2(fullPath)) {
      return {
        ...invariant,
        valid: false,
        path: invariant.path
      };
    }
    return null;
  }
};
var MutualExclusivityChecker = class {
  validate(invariant, baseDir) {
    const paths = Array.isArray(invariant.paths) ? invariant.paths : [];
    const existingPaths = paths.filter((p) => {
      const fullPath = path2.join(baseDir, p);
      return existsSync2(fullPath);
    });
    if (existingPaths.length > 1) {
      return {
        ...invariant,
        valid: false,
        existingPaths
      };
    }
    return null;
  }
};
var ForbiddenPatternChecker = class {
  validate(invariant, baseDir) {
    const { pattern, scope } = invariant;
    if (!pattern || !scope || !Array.isArray(scope)) {
      return null;
    }
    const ignorePatterns = EXCLUDED_DIRS.map((dir) => `**/${dir}/**`);
    const matchingFiles = [];
    for (const scopePattern of scope) {
      const files = globSync(scopePattern, {
        cwd: baseDir,
        ignore: ignorePatterns,
        nodir: true
      });
      const regex = new RegExp(pattern);
      for (const file of files) {
        const fullPath = path2.join(baseDir, file);
        try {
          const content = readFileSync2(fullPath, "utf-8");
          if (regex.test(content)) {
            matchingFiles.push(file);
          }
        } catch {
        }
      }
    }
    if (matchingFiles.length > 0) {
      return {
        ...invariant,
        valid: false,
        matchingFiles
      };
    }
    return null;
  }
};
var RequiredPatternChecker = class {
  validate(invariant, baseDir) {
    const { pattern, scope } = invariant;
    if (!pattern || !scope || !Array.isArray(scope)) {
      return null;
    }
    const ignorePatterns = EXCLUDED_DIRS.map((dir) => `**/${dir}/**`);
    const regex = new RegExp(pattern);
    for (const scopePattern of scope) {
      const files = globSync(scopePattern, {
        cwd: baseDir,
        ignore: ignorePatterns,
        nodir: true
      });
      for (const file of files) {
        const fullPath = path2.join(baseDir, file);
        try {
          const content = readFileSync2(fullPath, "utf-8");
          if (regex.test(content)) {
            return null;
          }
        } catch {
        }
      }
    }
    return {
      ...invariant,
      valid: false,
      patternNotFound: true
    };
  }
};
var ForbiddenImportChecker = class {
  validate(invariant, baseDir) {
    const { from, cannot_import } = invariant;
    if (!from || !cannot_import || !Array.isArray(cannot_import)) {
      return null;
    }
    const ignorePatterns = EXCLUDED_DIRS.map((dir) => `**/${dir}/**`);
    const files = globSync(from, {
      cwd: baseDir,
      ignore: ignorePatterns,
      nodir: true
    });
    const violatingFiles = [];
    const violatingImports = {};
    const forbiddenModulePatterns = cannot_import.map((mod) => {
      const escapedMod = mod.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
      return new RegExp(`(?:import\\s+[^;]*from\\s*['"]${escapedMod}['"]|export\\s+[^;]*from\\s*['"]${escapedMod}['"]|require\\s*\\(\\s*['"]${escapedMod}['"]\\s*\\)|import\\s*\\(\\s*['"]${escapedMod}['"]\\s*\\))`);
    });
    for (const file of files) {
      const fullPath = path2.join(baseDir, file);
      try {
        const content = readFileSync2(fullPath, "utf-8");
        for (let i = 0; i < forbiddenModulePatterns.length; i++) {
          const pattern = forbiddenModulePatterns[i];
          if (!pattern)
            continue;
          const moduleName = cannot_import[i] ?? "unknown-module";
          if (pattern.test(content)) {
            if (!violatingFiles.includes(file)) {
              violatingFiles.push(file);
            }
            violatingImports[moduleName] = (violatingImports[moduleName] || 0) + 1;
          }
        }
      } catch {
      }
    }
    if (violatingFiles.length > 0) {
      return {
        ...invariant,
        valid: false,
        violatingFiles,
        violatingImports
      };
    }
    return null;
  }
};
var WUAutomatedTestsChecker = class {
  validate(invariant, baseDir, context = {}) {
    const { wuId } = context;
    const result = checkAutomatedTestsInvariant({ baseDir, wuId });
    if (!result.valid && result.violations.length > 0) {
      return {
        ...invariant,
        valid: false,
        wuViolations: result.violations
      };
    }
    return null;
  }
};
registerInvariantChecker(INVARIANT_TYPES.REQUIRED_FILE, new RequiredFileChecker());
registerInvariantChecker(INVARIANT_TYPES.FORBIDDEN_FILE, new ForbiddenFileChecker());
registerInvariantChecker(INVARIANT_TYPES.MUTUAL_EXCLUSIVITY, new MutualExclusivityChecker());
registerInvariantChecker(INVARIANT_TYPES.FORBIDDEN_PATTERN, new ForbiddenPatternChecker());
registerInvariantChecker(INVARIANT_TYPES.REQUIRED_PATTERN, new RequiredPatternChecker());
registerInvariantChecker(INVARIANT_TYPES.FORBIDDEN_IMPORT, new ForbiddenImportChecker());
registerInvariantChecker(INVARIANT_TYPES.WU_AUTOMATED_TESTS, new WUAutomatedTestsChecker());
var InvariantError = class extends Error {
  /** The invariant ID */
  invariantId;
  /**
   * @param {string} invariantId - The invariant ID (e.g., 'INV-001')
   * @param {string} message - Error message
   */
  constructor(invariantId, message) {
    super(message);
    this.name = "InvariantError";
    this.invariantId = invariantId;
  }
};
function loadInvariants(filePath) {
  if (!existsSync2(filePath)) {
    throw createError(ErrorCodes.FILE_NOT_FOUND, `Invariants file not found: ${filePath}`);
  }
  const content = readFileSync2(filePath, "utf-8");
  let doc;
  try {
    doc = parseYAML(content);
  } catch (e) {
    throw createError(ErrorCodes.YAML_PARSE_ERROR, `Invalid YAML in ${filePath}: ${getErrorMessage(e)}`);
  }
  if (!doc || !Array.isArray(doc.invariants)) {
    throw createError(ErrorCodes.INVARIANT_ERROR, `Invalid invariants.yml: expected 'invariants' array at root`);
  }
  return doc.invariants;
}
function validateInvariants(invariants, options = {}) {
  const { baseDir = process.cwd(), wuId } = options;
  const violations = [];
  const context = { wuId };
  for (const invariant of invariants) {
    const checker = checkerRegistry.get(invariant.type);
    if (checker) {
      const violation = checker.validate(invariant, baseDir, context);
      if (violation) {
        violations.push(violation);
      }
    } else {
      console.warn(`[invariants] Unknown invariant type: ${invariant.type} (${invariant.id})`);
    }
  }
  return {
    valid: violations.length === 0,
    violations
  };
}
function formatFileViolationDetails(violation) {
  const lines = [];
  if (violation.path) {
    lines.push(`Path: ${violation.path}`);
  }
  if (violation.existingPaths) {
    lines.push(`Conflicting files: ${violation.existingPaths.join(", ")}`);
  }
  if (violation.matchingFiles) {
    lines.push(`Files with forbidden pattern: ${violation.matchingFiles.join(", ")}`);
  }
  return lines;
}
function formatImportViolationDetails(violation) {
  const lines = [];
  if (violation.from) {
    lines.push(`From: ${violation.from}`);
  }
  if (violation.cannot_import) {
    lines.push(`Cannot import: ${violation.cannot_import.join(", ")}`);
  }
  if (violation.violatingFiles) {
    lines.push(`Files with forbidden imports: ${violation.violatingFiles.join(", ")}`);
  }
  if (violation.violatingImports) {
    const imports = Object.entries(violation.violatingImports).map(([mod, count]) => `${mod} (${count} occurrence${count > 1 ? "s" : ""})`).join(", ");
    lines.push(`Forbidden imports found: ${imports}`);
  }
  return lines;
}
function formatPatternViolationDetails(violation) {
  const lines = [];
  if (violation.patternNotFound) {
    lines.push(`Required pattern not found: ${violation.pattern}`);
    if (violation.scope) {
      lines.push(`Searched in: ${violation.scope.join(", ")}`);
    }
  }
  return lines;
}
function formatWUAutomatedTestsViolationDetails(violation) {
  const lines = [];
  if (violation.wuViolations) {
    lines.push(`WUs missing automated tests:`);
    for (const wuViolation of violation.wuViolations) {
      lines.push(`  - ${wuViolation.wuId}`);
      if (wuViolation.codeFiles && wuViolation.codeFiles.length > 0) {
        lines.push(`    Code files: ${wuViolation.codeFiles.join(", ")}`);
      }
    }
  }
  return lines;
}
function formatViolationDetails(violation) {
  return [
    ...formatFileViolationDetails(violation),
    ...formatImportViolationDetails(violation),
    ...formatPatternViolationDetails(violation),
    ...formatWUAutomatedTestsViolationDetails(violation)
  ];
}
function formatInvariantError(violation) {
  const lines = [
    `INVARIANT VIOLATION: ${violation.id}`,
    `Type: ${violation.type}`,
    `Description: ${violation.description}`,
    ...formatViolationDetails(violation)
  ];
  if (violation.message) {
    lines.push("");
    lines.push(`Action: ${violation.message}`);
  }
  return lines.join("\n");
}
function runInvariants(options = {}) {
  const { configPath = "tools/invariants.yml", baseDir = process.cwd(), silent = false, wuId } = options;
  const fullConfigPath = path2.isAbsolute(configPath) ? configPath : path2.join(baseDir, configPath);
  if (!existsSync2(fullConfigPath)) {
    if (!silent) {
      console.log("[invariants] No tools/invariants.yml found - skipping");
    }
    return { success: true, violations: [], formatted: "" };
  }
  try {
    const invariants = loadInvariants(fullConfigPath);
    if (invariants.length === 0) {
      if (!silent) {
        console.log("[invariants] No invariants defined - skipping");
      }
      return { success: true, violations: [], formatted: "" };
    }
    const result = validateInvariants(invariants, { baseDir, wuId });
    if (result.valid) {
      if (!silent) {
        console.log(`[invariants] All ${invariants.length} invariants passed`);
      }
      return { success: true, violations: [], formatted: "" };
    }
    const formatted = result.violations.map(formatInvariantError).join("\n\n");
    if (!silent) {
      console.error("[invariants] FAILED - violations detected:");
      console.error("");
      console.error(formatted);
    }
    return {
      success: false,
      violations: result.violations,
      formatted
    };
  } catch (e) {
    const error = `[invariants] Error: ${getErrorMessage(e)}`;
    if (!silent) {
      console.error(error);
    }
    return {
      success: false,
      violations: [],
      formatted: error
    };
  }
}

export {
  INVARIANT_TYPES,
  registerInvariantChecker,
  getInvariantChecker,
  InvariantError,
  loadInvariants,
  validateInvariants,
  formatInvariantError,
  runInvariants
};
