import { NonNegativeInteger } from 'type-fest';

export declare function buildSchema<TSchema extends IndexedKeysMessageSchema<TSchemaInner>, TSchemaInner>(schema: TSchema): ToValidIndexedKeysMessageSchema<TSchema>;

declare const fieldType: unique symbol;

export declare function get<const TField>(message: readonly unknown[], schemaField: ValidSchemaLeaf<TField>): TField;

declare type IndexedKeysMessageSchema<TSchema> = {
    [K in keyof TSchema]: TSchema[K] extends SchemaLeaf<infer TField> ? SchemaLeaf<TField> : IndexedKeysMessageSchema<TSchema[K]>;
};

declare type IndexesPath = number[];

declare const indexesPathReversed: unique symbol;

declare type Invalid<T extends string> = {
    [invalid]: T;
};

declare const invalid: unique symbol;

export declare class InvalidSchemaError extends Error {
    constructor();
}

declare const isSchemaLeafTag: unique symbol;

declare const isValidSchemaLeafTag: unique symbol;

declare type PlainObjectOfSchema<TSchema> = TSchema extends ValidIndexedKeysMessageSchema<unknown> ? {
    [K in keyof TSchema]: TSchema[K] extends ValidSchemaLeaf<infer TField> ? TField : TSchema[K] extends SchemaLeaf<unknown> ? Invalid<"Schema needs to be validated before you use it!"> : PlainObjectOfSchema<TSchema[K]>;
} : never;

declare type ReturnedSchemaNode<TField, TNestedSchema> = TNestedSchema extends undefined ? SchemaLeaf<TField> : TNestedSchema;

declare type SchemaLeaf<TField> = {
    [indexesPathReversed]: IndexesPath;
    [fieldType]: TField;
    [isSchemaLeafTag]: true;
};

export declare function set<const TField>(targetMessage: unknown[], schemaField: ValidSchemaLeaf<TField>, value: TField): void;

export declare function toIndexedKeysMessage<TSchema extends ValidIndexedKeysMessageSchema<TSchemaInner>, TSchemaInner>(plainObject: PlainObjectOfSchema<TSchema>, schema: TSchema): unknown[];

export declare function toPlainObject<TSchema extends ValidIndexedKeysMessageSchema<TSchemaInner>, TSchemaInner>(message: readonly unknown[], schema: TSchema): PlainObjectOfSchema<TSchema>;

declare type ToValidIndexedKeysMessageSchema<TSchema> = {
    [K in keyof TSchema]: TSchema[K] extends SchemaLeaf<infer TField> ? ValidSchemaLeaf<TField> : ToValidIndexedKeysMessageSchema<TSchema[K]>;
};

export declare type ValidIndexedKeysMessageSchema<TSchema> = {
    [K in keyof TSchema]: TSchema[K] extends ValidSchemaLeaf<infer TField> ? ValidSchemaLeaf<TField> : TSchema[K] extends SchemaLeaf<unknown> ? Invalid<"Schema needs to be built before you use it, did you forget to call buildSchema()?"> : ToValidIndexedKeysMessageSchema<TSchema[K]>;
};

declare type ValidSchemaLeaf<TField> = SchemaLeaf<TField> & {
    [isValidSchemaLeafTag]: true;
    get: (message: unknown[]) => TField;
    set: (message: unknown[], value: TField) => void;
};

export declare function withIndex<const TIndex extends number>(index: NonNegativeInteger<TIndex>): <const TField = undefined, TNestedSchema extends IndexedKeysMessageSchema<TNestedSchema> | undefined = undefined>(nestedSchema?: TNestedSchema) => ReturnedSchemaNode<TField, TNestedSchema>;

export { }
