/**
 * Manifest-derived block content types — Phase 6 of the binding refactor.
 *
 * Today, every block declares two parallel artefacts:
 *
 *   1. A runtime manifest (`createBlockManifest({...})`) — drives editor UI,
 *      Zod validation, and the rendering pipeline.
 *   2. A hand-written `BlockContent` TypeScript type — used by the block's
 *      override component, by template type-checking, and by the rendering
 *      `BlockComponent` interface.
 *
 * Drift between the two is invariably possible: the runtime knows the field
 * is required and of type `text`, but the TS type might say `headline?: string`
 * or vice-versa. Phase 6 makes the manifest the single source of truth: the
 * TS type is *derived* from the manifest's `fields` array.
 *
 * This module is the manifest-derived content engine. It maps a block
 * manifest's preserved input config to the corresponding `BlockContent`
 * TypeScript type, making the manifest the source of truth for fields,
 * requiredness, variants, fragments, and auto-added style fields.
 *
 * Literal preservation: `ContentFromManifest<M>` produces the most precise
 * type that `M`'s static shape supports. The caller controls precision by
 * how `M` is typed at its declaration site:
 *
 *   - `const heroManifest = createBlockManifest({...})` — preserves the
 *     input config through `createBlockManifest`'s const-generic phantom.
 *   - `const heroManifest = createBlockManifest({...} as const)` — also
 *     precise, but usually unnecessary.
 *   - `export const heroManifest: BlockManifest = ...` — widens to the
 *     `BlockManifest` declared type entirely, losing all per-field literals.
 */
import type { Media } from '../../lib/media';
import type { BlockConfigInputOf } from '../defineBlock';
import type { FragmentConfigInputOf } from '../fragments';
import type { ContainerStylesContent, SectionStylesContent, CardStylesContent } from '../fields/boxStyles';
import type { LinkValue } from '../types/link';
import type { RichTextDoc } from './richTextSchema';
/**
 * Structural minimum a manifest field must satisfy for derivation. The full
 * runtime `FieldDefinition` has many more fields (label, description, ui,
 * etc.) but the derivation only cares about `id`, `type`, `required`, and —
 * for `select` and container kinds — the constraints/children.
 *
 * Defined as an interface so manifest-author code that uses the runtime
 * `FieldDefinition` type is structurally compatible without an explicit cast.
 */
export interface DerivableField {
    id: string;
    type: string;
    required?: boolean;
    /** Select fields: literal options drive the produced union type. */
    options?: ReadonlyArray<{
        value: string;
        label?: string;
    }>;
    /** Select fields with `multiple: true` produce an array value. */
    multiple?: boolean;
    /** Group/modal containers carry children under `schema.fields`. */
    schema?: {
        fields?: ReadonlyArray<DerivableField>;
    };
    /** TabGroup carries children under `tabs[].fields`. */
    tabs?: ReadonlyArray<{
        fields?: ReadonlyArray<DerivableField>;
    }>;
    /** Repeater item groups with this flag are flattened at runtime. */
    ui?: {
        flattenInRepeater?: boolean;
    };
    /** Phantom marker carried by style field factories. */
    readonly __boxStyleType?: 'section' | 'container' | 'card';
}
export interface DerivableManifest {
    name: string;
    fields?: ReadonlyArray<DerivableField>;
}
/**
 * Concrete content-value type for a field. Mirrors the runtime mapping in
 * `fieldValidation/index.ts:292` so the derived TS type matches what the Zod
 * validator would produce at runtime. Optionality is encoded externally
 * (the mapped type below uses `[F['id']]?` for non-required fields); this
 * mapping always produces the "present" type.
 *
 * Exhaustiveness gate: the fallback resolves to `never` so a future
 * `FieldDefinition['type']` value added in `packages/blocks/src/system/manifest/schema.ts`
 * fails to compile here until a branch is added — preventing the "silently
 * mapped to unknown" drift the Phase 4 review flagged.
 *
 * Branches deliberately producing `unknown`:
 *   - `presetOrCustom`, `contentTypeSelect`, `entryPicker` — passthrough
 *     widgets whose runtime plan kind is `passthrough` with `valueKind: 'unknown'`.
 *     Bindings don't constrain these.
 */
type FieldToValue<F extends DerivableField> = F extends {
    readonly __boxStyleType?: 'section';
} ? SectionStylesContent : F extends {
    readonly __boxStyleType?: 'container';
} ? ContainerStylesContent : F extends {
    readonly __boxStyleType?: 'card';
} ? CardStylesContent : F['type'] extends 'text' | 'slug' | 'url' | 'reference' | 'date' | 'time' | 'datetime' ? string : F['type'] extends 'number' ? number : F['type'] extends 'boolean' ? boolean : F['type'] extends 'richText' ? RichTextDoc : F['type'] extends 'media' ? Media : F['type'] extends 'link' ? LinkValue : F['type'] extends 'select' ? SelectValue<F> : F['type'] extends 'group' | 'modal' | 'tabGroup' ? CompositeValue<F> : F['type'] extends 'repeater' ? ReadonlyArray<RepeaterItemValue<F>> : F['type'] extends 'presetOrCustom' | 'contentTypeSelect' | 'entryPicker' ? unknown : never;
/**
 * Select-field value type.
 *
 * Honors the `multiple` flag — when `true`, the field's value at runtime is
 * `string[]` (or `V[]` for an option-typed select), matching the runtime's
 * array shape. When omitted or `false`, a scalar literal value.
 */
type SelectValue<F extends DerivableField> = F extends {
    options: ReadonlyArray<{
        value: infer V;
    }>;
} ? F extends {
    multiple: true;
} ? V[] : V : F extends {
    multiple: true;
} ? string[] : string;
/**
 * Composite (group/modal/tabGroup) value type.
 *
 * `group` and `modal` carry children under `schema.fields`. `tabGroup`
 * carries them under `tabs[].fields` — the runtime validator flattens those
 * into one virtual field list, so we mirror it here.
 */
type CompositeValue<F extends DerivableField> = F extends {
    schema: {
        fields: ReadonlyArray<DerivableField>;
    };
} ? ContentFromFields<F['schema']['fields']> : F extends {
    tabs: ReadonlyArray<{
        fields?: ReadonlyArray<DerivableField>;
    }>;
} ? ContentFromFields<TabFields<F>> : Record<string, unknown>;
type TabFields<F> = F extends {
    tabs: ReadonlyArray<{
        fields?: infer Fs extends ReadonlyArray<DerivableField>;
    }>;
} ? Fs : never;
/**
 * Repeater item value type.
 *
 * Monomorphic repeaters carry an item shape under `schema.fields`; bound
 * children flow through `ContentFromFields`. Polymorphic repeaters use
 * `itemTypes` and bound children would be a discriminated union — Phase 6b
 * may tighten this, but for now polymorphic items widen to a generic record.
 */
type RepeaterItemValue<F extends DerivableField> = F extends {
    schema: {
        fields: ReadonlyArray<DerivableField>;
    };
} ? ContentFromFieldUnion<FlattenedRepeaterFieldUnion<F['schema']['fields']>> : Record<string, unknown>;
type FlattenedRepeaterFieldUnion<Fs extends ReadonlyArray<DerivableField>> = FlattenRepeaterField<Fs[number]>;
type FlattenRepeaterField<F extends DerivableField> = F extends {
    type: 'group';
    ui: {
        flattenInRepeater: true;
    };
    schema: {
        fields: ReadonlyArray<DerivableField>;
    };
} ? F['schema']['fields'][number] : F;
/**
 * Compute the record type produced by an array of fields. Required fields
 * become required keys; optional fields become optional keys.
 */
type ContentFromFields<Fs extends ReadonlyArray<DerivableField>> = ContentFromFieldUnion<Fs[number]>;
type ContentFromFieldUnion<F extends DerivableField> = OptionalKeysOf<F> extends never ? RequiredFieldsRecord<F> : RequiredFieldsRecord<F> & OptionalFieldsRecord<F>;
type RequiredFieldsRecord<F extends DerivableField> = {
    [Field in Extract<F, {
        required: true;
    }> as Field['id']]: FieldToValue<Field>;
};
type OptionalFieldsRecord<F extends DerivableField> = {
    [Field in Exclude<F, {
        required: true;
    }> as Field['id']]?: FieldToValue<Field>;
};
type OptionalKeysOf<F extends DerivableField> = F extends {
    required: true;
} ? never : F['id'];
type FieldsFromFragmentInstance<Instance> = Instance extends {
    fragment: infer Fragment;
    scope: infer Scope extends string;
} ? ScopeFields<FieldsFromFragment<Fragment>, Scope> : Instance extends {
    fragment: infer Fragment;
} ? FieldsFromFragment<Fragment> : never;
type FieldsFromFragment<Fragment> = FragmentConfigInputOf<Fragment> extends {
    fields?: infer Fs extends ReadonlyArray<DerivableField>;
} ? Fs[number] : Fragment extends {
    fields: infer Fs extends ReadonlyArray<DerivableField>;
} ? Fs[number] : never;
type ScopeFields<F extends DerivableField, Scope> = Scope extends string ? Scope extends '' ? F : Omit<F, 'id'> & {
    id: `${Scope}.${F['id']}`;
} : F;
type FieldsFromBlockConfig<C> = (C extends {
    fragments?: infer Fragments extends ReadonlyArray<unknown>;
} ? FieldsFromFragmentInstance<Fragments[number]> : never) | (C extends {
    additionalFields?: infer Fields extends ReadonlyArray<DerivableField>;
} ? Fields[number] : never) | SyntheticVariantField<C> | SyntheticContainerStylesField<C> | SyntheticSectionStylesField<C>;
type SyntheticVariantField<C> = C extends {
    variants: infer Variants extends Record<string, unknown>;
} ? {
    id: 'variant';
    type: 'select';
    options: ReadonlyArray<{
        value: Extract<keyof Variants, string>;
    }>;
} : never;
type SyntheticContainerStylesField<C> = C extends {
    includeContainerStyles: true;
} ? {
    id: '_containerStyles';
    type: 'modal';
    readonly __boxStyleType?: 'container';
} : never;
type SyntheticSectionStylesField<C> = C extends {
    skipSectionStyles: true;
} ? never : {
    id: '_sectionStyles';
    type: 'modal';
    readonly __boxStyleType?: 'section';
};
export type ContentFromBlockConfig<C> = [
    FieldsFromBlockConfig<C>
] extends [never] ? Record<string, never> : ContentFromFieldUnion<FieldsFromBlockConfig<C>>;
/**
 * The block content type for a manifest. Pre-existing field-only shape:
 *   `type HeroContent = ContentFromManifest<typeof heroManifest>`
 *
 * Compile-quality of the derived type depends on the manifest declaration.
 * The plain `createBlockManifest({...})` form keeps the input config in a
 * phantom type. A widening annotation like `: BlockManifest` erases that
 * phantom and falls back to the runtime `fields` shape.
 */
export type ContentFromManifest<M extends DerivableManifest> = [
    BlockConfigInputOf<M>
] extends [never] ? M extends {
    fields: infer Fs extends ReadonlyArray<DerivableField>;
} ? ContentFromFields<Fs> : Record<string, never> : ContentFromBlockConfig<BlockConfigInputOf<M>>;
export {};
