import type { WrnDiagnostic } from "./diagnostics.ts";

/** Current stable syntax contract. Bump only when parsers/codegen need migration. */
export const WRN_SYNTAX_VERSION = "0.4" as const;

export type WrnSyntaxFeature =
  | "typed-declarations"
  | "layouts"
  | "server-client-blocks"
  | "effects"
  | "watch"
  | "lifecycle"
  | "embedded-api"
  | "realtime"
  | "runtime-markers";

export const WRN_SYNTAX_FEATURES: Readonly<Record<WrnSyntaxFeature, boolean>> = Object.freeze({
  "typed-declarations": true,
  layouts: true,
  "server-client-blocks": true,
  effects: true,
  watch: true,
  lifecycle: true,
  "embedded-api": true,
  realtime: true,
  "runtime-markers": true,
});

export interface SourceRange {
  start: number;
  end: number;
}

export function createSourceRange(start: number, end: number): SourceRange {
  if (!Number.isInteger(start) || !Number.isInteger(end) || start < 0 || end < start) {
    throw new RangeError(`Invalid source range ${start}..${end}`);
  }
  return { start, end };
}

export function sliceSource(source: string, range: SourceRange): string {
  return source.slice(range.start, range.end);
}

export function diagnosticSummary(diagnostics: readonly WrnDiagnostic[]): {
  errors: number;
  warnings: number;
  info: number;
  codes: Record<string, number>;
} {
  const summary = { errors: 0, warnings: 0, info: 0, codes: {} as Record<string, number> };
  for (const diagnostic of diagnostics) {
    if (diagnostic.severity === "error") summary.errors++;
    else if (diagnostic.severity === "warning") summary.warnings++;
    else summary.info++;
    summary.codes[diagnostic.code] = (summary.codes[diagnostic.code] ?? 0) + 1;
  }
  return summary;
}

export function supportsSyntaxFeature(feature: string): feature is WrnSyntaxFeature {
  return Object.prototype.hasOwnProperty.call(WRN_SYNTAX_FEATURES, feature);
}
