/**
 * Compile-time helpers that keep the zod schemas in lock-step with the engine's type contract.
 * Internal to the package (not re-exported): only used in type positions.
 */
import type { z } from 'zod';

/**
 * Recursively flattens intersections (`A & B` → one object) so that a schema's inferred output and the
 * engine's hand-written type compare equal when they describe the same structure. Optional modifiers are
 * preserved by the homomorphic mapped type, so a missing optional key is still a difference.
 */
export type Normalize<T> = T extends (...args: never[]) => unknown
  ? T
  : T extends readonly (infer U)[]
    ? Normalize<U>[]
    : T extends object
      ? { [K in keyof T]: Normalize<T[K]> }
      : T;

/**
 * Exact type identity. Unlike mutual assignability it distinguishes `{a?: X}` from `{}`,
 * `X | null` from `X`, and extra optional keys, which is exactly the drift strict schemas care about.
 */
export type Equal<A, B> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? true : false;

/** Fails to compile unless `T` is `true`. */
export type Expect<T extends true> = T;

/** `true` when the schema's parsed output is structurally identical to `T`. */
export type SchemaMatches<S extends z.ZodType, T> = Equal<Normalize<z.output<S>>, Normalize<T>>;
