import { realpathSync, statSync } from "node:fs";
import { isAbsolute, resolve } from "node:path";

export interface MandatoryExtensionPolicy {
  /** Exact, bundle-owned extension entry paths that an agent cannot disable. */
  mandatoryExtensionPaths?: readonly string[];
}

function canonicalExistingPath(path: string): string {
  if (!isAbsolute(path)) {
    throw new Error(`Mandatory extension path must be absolute: ${path}`);
  }
  let canonical: string;
  try {
    canonical = realpathSync.native(path);
  } catch (error) {
    const message = error instanceof Error ? error.message : String(error);
    throw new Error(`Mandatory extension path is unavailable: ${path} (${message})`);
  }
  const stat = statSync(canonical);
  if (!stat.isFile() && !stat.isDirectory()) {
    throw new Error(`Mandatory extension path is not a file or directory: ${path}`);
  }
  return canonical;
}

/** Validate, canonicalize, and deduplicate bundle-owned extension entry paths. */
export function normalizeMandatoryExtensionPaths(paths: readonly string[] | undefined): readonly string[] {
  if (!paths?.length) return [];
  return Object.freeze([...new Set(paths.map(canonicalExistingPath))]);
}

/**
 * Compare loader-reported paths to a canonical mandatory entry. Loader paths
 * normally exist, but resolve-only fallback keeps diagnostics deterministic if
 * an extension disappears between reload and verification.
 */
export function extensionPathMatches(actualPath: string, canonicalExpectedPath: string): boolean {
  let actual: string;
  try {
    actual = realpathSync.native(actualPath);
  } catch {
    actual = resolve(actualPath);
  }
  return actual === canonicalExpectedPath;
}

export function isMandatoryExtensionPath(
  extensionPath: string,
  mandatoryExtensionPaths: readonly string[],
): boolean {
  return mandatoryExtensionPaths.some((path) => extensionPathMatches(extensionPath, path));
}

/** Mandatory infrastructure is useful only if the exact trusted entry survived reload. */
export function assertMandatoryExtensionsLoaded(
  loadedExtensionPaths: readonly string[],
  mandatoryExtensionPaths: readonly string[],
): void {
  for (const mandatoryPath of mandatoryExtensionPaths) {
    if (!loadedExtensionPaths.some((loadedPath) => extensionPathMatches(loadedPath, mandatoryPath))) {
      throw new Error(`Mandatory extension failed to load: ${mandatoryPath}`);
    }
  }
}
