import { RecipeVariantRecord, RecipeConfig, Pretty, RecipeCompoundVariant, RecipeCompoundSelection, RecipeSelection, DistributiveOmit, SlotRecipeVariantRecord, SlotRecipeConfig } from '@pandacss/types';
export { RecipeCompoundSelection, RecipeCompoundVariant, RecipeConfig, RecipeSelection, RecipeVariantRecord, SlotRecipeConfig, SlotRecipeVariantRecord } from '@pandacss/types';

type Pick_<T, K> = Pick<T, Extract<keyof T, K>>;
type DistributivePick<T, K> = T extends unknown ? keyof Pick_<T, K> extends never ? never : {
    [P in keyof Pick_<T, K>]: Pick_<T, K>[P];
} : never;

interface RecipeBuilder<T extends RecipeVariantRecord> extends RecipeConfig<T> {
    extend: <TVariants extends RecipeVariantRecord>(variants: TVariants) => RecipeBuilder<Pretty<T & TVariants>>;
    merge: <TVariants extends RecipeVariantRecord, MergedVariants extends Pretty<TVariants & T> = Pretty<TVariants & T>>(extension: Partial<Omit<RecipeConfig<any>, 'variants' | 'compoundVariants' | 'defaultVariants'>> & {
        variants?: TVariants;
        compoundVariants?: Array<Pretty<RecipeCompoundVariant<RecipeCompoundSelection<MergedVariants>>>>;
        defaultVariants?: RecipeSelection<MergedVariants>;
    }) => RecipeBuilder<MergedVariants>;
    pick: <TKeys extends keyof T>(...keys: TKeys[]) => RecipeBuilder<DistributivePick<T, TKeys>>;
    omit: <TKeys extends keyof T>(...keys: TKeys[]) => RecipeBuilder<DistributiveOmit<T, TKeys>>;
    cast: () => RecipeConfig<RecipeVariantRecord>;
}
type PickSlots<S extends string, T extends SlotRecipeVariantRecord<S>, TKeys extends S> = Pretty<{
    [VName in keyof T]: {
        [VKey in keyof T[VName]]: {
            [VSlot in Extract<keyof T[VName][VKey], TKeys>]: T[VName][VKey][VSlot];
        };
    };
}>;
type OmitSlots<S extends string, T extends SlotRecipeVariantRecord<S>, TKeys extends S> = Pretty<{
    [VName in keyof T]: {
        [VKey in keyof T[VName]]: {
            [VSlot in Exclude<keyof T[VName][VKey], TKeys>]: T[VName][VKey][VSlot];
        };
    };
}>;
interface SlotExtensionFns<S extends string, T extends SlotRecipeVariantRecord<S>> {
    add: <TSlots extends string>(...slots: TSlots[]) => SlotRecipeBuilder<S | TSlots, T extends SlotRecipeVariantRecord<S | TSlots> ? T : never>;
    pick: <TKeys extends S>(...keys: TKeys[]) => SlotRecipeBuilder<Extract<S, TKeys>, PickSlots<S, T, TKeys>>;
    omit: <TKeys extends S>(...keys: TKeys[]) => SlotRecipeBuilder<Exclude<S, TKeys>, OmitSlots<S, T, TKeys>>;
    /** Assign simple recipe to slot */
    assignTo: <TSlot extends S, TRecipe extends RecipeConfig, TVariants extends NonNullable<TRecipe['variants']> = NonNullable<TRecipe['variants']>>(slot: TSlot, recipe: TRecipe) => SlotRecipeBuilder<S, {
        [VName in keyof T]: {
            [VKey in keyof T[VName]]: {
                [VSlot in keyof T[VName][VKey]]: VSlot extends TSlot ? {
                    [VRecipeVariant in keyof TVariants]: VRecipeVariant extends VName ? VKey extends keyof TVariants[VRecipeVariant] ? TVariants[VRecipeVariant][VKey] : T[VName][VKey][VSlot] : T[VName][VKey][VSlot];
                }[keyof TVariants] : T[VName][VKey][VSlot];
            };
        };
    }>;
}
interface SlotRecipeBuilder<S extends string, T extends SlotRecipeVariantRecord<S>> extends SlotRecipeConfig<S, T> {
    extend: <TVariants extends SlotRecipeVariantRecord<S>>(variants: TVariants) => SlotRecipeBuilder<S, Pretty<T & TVariants>>;
    merge: <TVariants extends SlotRecipeVariantRecord<S>, MergedVariants extends Pretty<TVariants & T> = Pretty<TVariants & T>>(extension: Partial<Omit<SlotRecipeConfig<any>, 'slots' | 'variants' | 'compoundVariants' | 'defaultVariants'>> & {
        slots?: S[];
        variants?: TVariants extends unknown ? SlotRecipeVariantRecord<S> : TVariants;
        compoundVariants?: Array<Pretty<RecipeCompoundVariant<RecipeCompoundSelection<MergedVariants>>>>;
        defaultVariants?: RecipeSelection<MergedVariants>;
    }) => SlotRecipeBuilder<S, MergedVariants>;
    pick: <TKeys extends keyof T>(...keys: TKeys[]) => SlotRecipeBuilder<S, DistributivePick<T, TKeys>>;
    omit: <TKeys extends keyof T>(...keys: TKeys[]) => SlotRecipeBuilder<S, DistributiveOmit<T, TKeys>>;
    cast: () => SlotRecipeConfig<S, SlotRecipeVariantRecord<S>>;
    /** Add slots, pick or omit some or assign a config recipe to a slot */
    slot: SlotExtensionFns<S, T>;
}

declare function defineRecipe<T extends RecipeVariantRecord>(config: RecipeConfig<T>): RecipeBuilder<T>;

declare function defineSlotRecipe<S extends string, T extends SlotRecipeVariantRecord<S>>(config: SlotRecipeConfig<S, T>): SlotRecipeBuilder<S, T>;

export { type RecipeBuilder, type SlotExtensionFns, type SlotRecipeBuilder, defineRecipe, defineSlotRecipe };
