import { GroqBuilder } from "../groq-builder";
import { Empty, IsAny, LiteralUnion, Simplify, SimplifyDeep, StringKeys, TypeMismatchError, UndefinedToNull, ValueOf } from "../types/utils";
import { FragmentInputTypeTag, IGroqBuilder, Parser, ParserWithWidenedInput } from "../types/public-types";
import { Path, PathEntries, PathValue } from "../types/path-types";
import { DeepRequired } from "../types/deep-required";
import { QueryConfig } from "../types/schema-types";
import { ConditionalKey, ExtractConditionalProjectionTypes } from "./conditional-types";
export type ProjectionKey<TResultItem> = IsAny<TResultItem> extends true ? string : ProjectionKeyImpl<Simplify<PathEntries<DeepRequired<TResultItem>>>>;
type ProjectionKeyImpl<Entries> = ValueOf<{
    [Key in keyof Entries]: Entries[Key] extends Array<any> ? `${StringKeys<Key>}[]` | Key : Key;
}>;
export type ProjectionKeyValue<TResultItem, TKey> = UndefinedToNull<PathValue<TResultItem, Extract<TKey extends `${infer TPath}[]` ? TPath : TKey, Path<TResultItem>>>>;
export type ProjectionMap<TResultItem> = {
    [P in LiteralUnion<keyof TResultItem, string>]?: ProjectionFieldConfig<TResultItem, P extends keyof TResultItem ? UndefinedToNull<TResultItem[P]> : any>;
} & {
    "..."?: true | Parser;
};
export type ProjectionMapOrCallback<TResultItem, TQueryConfig extends QueryConfig> = ProjectionMap<TResultItem> | ((q: GroqBuilder<TResultItem, TQueryConfig>) => ProjectionMap<TResultItem>);
export type ProjectionFieldConfig<TResultItem, TFieldType> = true | ProjectionKey<TResultItem> | ParserWithWidenedInput<TFieldType> | readonly [ProjectionKey<TResultItem>, ParserWithWidenedInput<TFieldType>] | IGroqBuilder;
export type ExtractProjectionResult<TResultItem, TProjectionMap> = (TProjectionMap extends {
    "...": true;
} ? TResultItem : Empty) & (TProjectionMap extends {
    "...": Parser<TResultItem, infer TOutput>;
} ? TOutput : Empty) & ExtractConditionalProjectionTypes<TProjectionMap> & ExtractProjectionResultFields<TResultItem, Omit<TProjectionMap, "..." | typeof FragmentInputTypeTag | ConditionalKey<string>>>;
type ExtractProjectionResultFields<TResultItem, TProjectionMap> = {
    [P in keyof TProjectionMap]: TProjectionMap[P] extends IGroqBuilder<infer TValue> ? TValue : TProjectionMap[P] extends boolean ? P extends keyof TResultItem ? UndefinedToNull<TResultItem[P]> : TypeMismatchError<{
        error: `⛔️ 'true' can only be used for known properties ⛔️`;
        expected: keyof TResultItem;
        actual: P;
    }> : TProjectionMap[P] extends string ? TProjectionMap[P] extends ProjectionKey<TResultItem> ? ProjectionKeyValue<TResultItem, TProjectionMap[P]> : TypeMismatchError<{
        error: `⛔️ Naked projections must be known properties ⛔️`;
        expected: SimplifyDeep<ProjectionKey<TResultItem>>;
        actual: TProjectionMap[P];
    }> : TProjectionMap[P] extends readonly [infer TKey, infer TParser] ? TKey extends ProjectionKey<TResultItem> ? TParser extends Parser<infer TParserInput, infer TParserOutput> ? ValidateParserInput<ProjectionKeyValue<TResultItem, TKey>, TParserInput, TParserOutput> : TypeMismatchError<{
        error: `⛔️ Naked projections must be known properties ⛔️`;
        expected: SimplifyDeep<ProjectionKey<TResultItem>>;
        actual: TKey;
    }> : TypeMismatchError<{
        error: `⛔️ Naked projections must be known properties ⛔️`;
        expected: SimplifyDeep<ProjectionKey<TResultItem>>;
        actual: TKey;
    }> : TProjectionMap[P] extends Parser<infer TParserInput, infer TParserOutput> ? P extends keyof TResultItem ? ValidateParserInput<UndefinedToNull<TResultItem[P]>, TParserInput, TParserOutput> : TypeMismatchError<{
        error: `⛔️ Parser can only be used with known properties ⛔️`;
        expected: keyof TResultItem;
        actual: P;
    }> : never;
};
export type ValidateParserInput<TIncomingValue, TParserInput, TParserOutput> = TIncomingValue extends TParserInput ? TParserOutput : IsAny<TIncomingValue> extends true ? TParserOutput : TypeMismatchError<{
    error: `⛔️ Parser expects a different input type ⛔️`;
    expected: TParserInput;
    actual: TIncomingValue;
}>;
export {};
