import { Contract } from '@withease/contracts';
import { Event as Event_2 } from 'effector';
import { EventCallable } from 'effector';
import { Json } from 'effector';
import { Store } from 'effector';
import { StoreValue } from 'effector';

export declare type AnyFieldApi = (PrimitiveFieldApi<PrimitiveValue> & {
    type: PrimitiveFieldSymbolType;
    $value: Store<PrimitiveValue>;
    $error: Store<FieldError>;
    $isDirty: Store<boolean>;
    $isValid: Store<boolean>;
}) | (ArrayFieldApi<any, any> & {
    type: ArrayFieldSymbolType;
    $values: Store<FormFields[]>;
    $error: Store<FieldError>;
    $isDirty: Store<boolean>;
    $isValid: Store<boolean>;
});

export declare interface AnySchema extends RawFieldsGroupSchema {
}

export declare interface ArrayField<T extends ArrayFieldItemType, Meta extends object = any, U = UserFormSchema<T>> extends ArrayFieldApi<T, U, Meta> {
    '@@type': ArrayFieldSymbolType;
    $meta: Store<Meta>;
    $values: Store<U[]>;
    $error: Store<FieldError>;
    $isValid: Store<boolean>;
    copyOnCreateForm: boolean;
    sid?: string | null;
    '@@unitShape': () => {
        values: Store<U[]>;
        error: Store<FieldError>;
        meta: Store<Meta>;
        isValid: Store<boolean>;
        changeMeta: EventCallable<Meta>;
        reset: EventCallable<void>;
        clear: EventCallable<void>;
        change: EventCallable<T[]>;
        changeError: EventCallable<FieldError>;
        push: EventCallable<PushPayload<T>>;
        swap: EventCallable<SwapPayload>;
        move: EventCallable<MovePayload>;
        insert: EventCallable<InsertOrReplacePayload<T>>;
        unshift: EventCallable<UnshiftPayload<T>>;
        remove: EventCallable<RemovePayload>;
        pop: EventCallable<void>;
        replace: EventCallable<InsertOrReplacePayload<T>>;
    };
}

export declare interface ArrayFieldApi<T extends ArrayFieldItemType, U, Meta extends object = any> {
    changeError: EventCallable<FieldError>;
    change: EventCallable<T[]>;
    push: EventCallable<PushPayload<T>>;
    swap: EventCallable<SwapPayload>;
    move: EventCallable<MovePayload>;
    insert: EventCallable<InsertOrReplacePayload<T>>;
    unshift: EventCallable<UnshiftPayload<T>>;
    remove: EventCallable<RemovePayload>;
    pop: EventCallable<void>;
    replace: EventCallable<InsertOrReplacePayload<T>>;
    reset: EventCallable<void>;
    clear: EventCallable<void>;
    changeMeta: EventCallable<Meta>;
    metaChanged: Event_2<Meta>;
    changed: Event_2<U[]>;
    cleared: EventCallable<void>;
    resetCompleted: EventCallable<{
        values: U[];
        error: FieldError;
    }>;
    errorChanged: Event_2<FieldError>;
    pushed: Event_2<{
        params: PushPayload<T>;
        result: U[];
    }>;
    swapped: Event_2<{
        params: SwapPayload;
        result: U[];
    }>;
    moved: Event_2<{
        params: MovePayload;
        result: U[];
    }>;
    inserted: Event_2<{
        params: InsertOrReplacePayload<T>;
        result: U[];
    }>;
    unshifted: Event_2<{
        params: UnshiftPayload<T>;
        result: U[];
    }>;
    removed: Event_2<{
        params: RemovePayload;
        result: U[];
    }>;
    popped: Event_2<U[]>;
    replaced: Event_2<{
        params: InsertOrReplacePayload<T>;
        result: U[];
    }>;
}

export declare type ArrayFieldItemType = AnySchema | PrimitiveValue;

export declare type ArrayFieldPathApi = {
    type: 'array-field';
    isValid: boolean;
    clearValuesMemory: () => void;
    clearMemory: (withField?: boolean) => void;
    batchedClear: (info: FieldBatchedPayload) => void;
} & BasePathApi;

export declare const arrayFieldSymbol: unique symbol;

export declare type ArrayFieldSymbolType = typeof arrayFieldSymbol;

export declare type AsyncValidationFn<Schema extends AnySchema> = (values: FormValues<UserFormSchema<Schema>>) => Promise<ErrorsSchemaPayload | null>;

export declare type BasePathApi = {
    reset: () => void;
    clearInnerError: () => void;
    clearOuterError: () => void;
    setInnerError: (error: FieldError) => void;
    setOuterError: (error: FieldError) => void;
    setValue: <T>(value: T) => void;
    batchedSetValue: <T>(info: FieldBatchedSetter<T>) => void;
    batchedSetInnerError: (error: FieldBatchedSetter<FieldError>) => void;
    batchedSetOuterError: (error: FieldBatchedSetter<FieldError>) => void;
    batchedReset: (info: FieldBatchedPayload) => void;
};

export declare function copy<T extends PrimitiveField>(field: T): T;

export declare function copy<T extends ArrayField<any>>(field: T): T;

export declare function copyGroup<T extends ReadyFieldsGroupSchema>(group: T): T;

export declare function createArrayField<T extends PrimitiveValue | AnySchema, Meta extends object = any, Value = UserFormSchema<T>>(values: T[], overrides?: CreateArrayFieldOptions<Meta>): ArrayField<T, Meta, Value>;

export declare interface CreateArrayFieldOptions<Meta extends object = any> {
    error?: FieldError;
    meta?: Meta;
    copyOnCreateForm?: boolean;
    sid?: string | null;
}

export declare function createField<T extends PrimitiveValue | Json, Meta extends object = any>(defaultValue: T, overrides?: CreatePrimitiveFieldOptions<Meta>): PrimitiveField<T, Meta>;

export declare function createForm<T extends AnySchema>(options: CreateFormOptions<T>): FormType<UserFormSchema<T>, FormValues<UserFormSchema<T>>, FormErrors<UserFormSchema<T>>>;

export declare interface CreateFormOptions<T extends AnySchema> {
    schema: T;
    validation?: SyncValidationFn<T> | AsyncValidationFn<T> | Contract<unknown, FormValues<UserFormSchema<T>>>;
    validationStrategies?: ValidationStrategy[] | Store<ValidationStrategy[]>;
    clearOuterErrorsOnSubmit?: boolean;
}

export declare interface CreatePrimitiveFieldOptions<Meta extends object = any> {
    error?: FieldError;
    meta?: Meta;
    copyOnCreateForm?: boolean;
    sid?: string | null;
}

export declare type ErrorsSchemaPayload = Record<string, FieldError>;

export declare type FieldBatchedPayload = {
    '@@batchInfo': {
        id: string;
        fieldPath: string;
    };
};

export declare type FieldBatchedSetter<T> = {
    value: T;
} & FieldBatchedPayload;

export declare type FieldError = string | null;

declare type FieldInnerBatchSetters<T> = {
    batchedSetInnerError: EventCallable<FieldBatchedSetter<FieldError>>;
    batchedSetOuterError: EventCallable<FieldBatchedSetter<FieldError>>;
    batchedSetValue: EventCallable<FieldBatchedSetter<T>>;
    batchedReset: EventCallable<FieldBatchedPayload>;
};

export declare type FormApi = Record<string, PathApi>;

export declare type FormErrors<T extends ReadyFieldsGroupSchema | PrimitiveValue> = T extends ReadyFieldsGroupSchema ? {
    [K in keyof T]: T[K] extends PrimitiveField<any> ? FieldError : T[K] extends PrimitiveValue ? FieldError : T[K] extends ArrayField<any, infer Schema> ? {
        error: FieldError;
        errors: Schema extends ReadyFieldsGroupSchema ? FormErrors<Schema>[] : [];
    } : T[K] extends AnySchema ? FormErrors<T> : FieldError;
} : T;

export declare type FormFields = {
    [k: string]: FormFields | AnyFieldApi;
};

export declare type FormType<Fields extends UserFormSchema<any>, Values extends FormValues<any>, Errors extends FormErrors<any>> = {
    fields: Fields;
    $values: Store<Values>;
    $errors: Store<Errors>;
    $snapshot: Store<Values>;
    $isChanged: Store<boolean>;
    $isValid: Store<boolean>;
    $isValidationPending: Store<boolean>;
    fill: EventCallable<{
        values?: PartialRecursive<Values>;
        errors?: ErrorsSchemaPayload;
    }>;
    filled: Event_2<void>;
    changed: EventCallable<Values>;
    errorsChanged: Event_2<Errors>;
    validate: EventCallable<void>;
    validated: Event_2<Values>;
    validatedAndSubmitted: Event_2<Values>;
    validationFailed: Event_2<Values>;
    submit: EventCallable<void>;
    submitted: Event_2<Values>;
    reset: EventCallable<void>;
    clearOuterErrors: EventCallable<void>;
    clearInnerErrors: EventCallable<void>;
    forceUpdateSnapshot: EventCallable<void>;
    snapshotUpdated: Event_2<void>;
    metaChanged: EventCallable<{
        fieldPath: string;
        meta: any;
    }>;
    '@@unitShape': () => {
        values: Store<Values>;
        errors: Store<Errors>;
        snapshot: Store<Values>;
        isChanged: Store<boolean>;
        isValid: Store<boolean>;
        isValidationPending: Store<boolean>;
        submit: EventCallable<void>;
        validate: EventCallable<void>;
        reset: EventCallable<void>;
        clearOuterErrors: EventCallable<void>;
        clearInnerErrors: EventCallable<void>;
        forceUpdateSnapshot: EventCallable<void>;
        fill: EventCallable<{
            values?: PartialRecursive<Values>;
            errors?: ErrorsSchemaPayload;
            triggerIsDirty?: boolean;
        }>;
    };
};

export declare type FormValues<T extends ReadyFieldsGroupSchema> = {
    [K in keyof T]: T[K] extends PrimitiveField<any> ? StoreValue<T[K]['$value']> : T[K] extends ArrayField<any, any, infer D> ? D extends ReadyFieldsGroupSchema ? FormValues<D>[] : D[] : T[K] extends ReadyFieldsGroupSchema ? FormValues<T[K]> : never;
};

export declare type InnerArrayFieldApi<T = any> = FieldInnerBatchSetters<T> & {
    $outerError: Store<string>;
    $innerError: Store<string>;
    setInnerError: EventCallable<FieldError>;
    batchedClear: EventCallable<FieldBatchedPayload>;
};

export declare type InnerFieldApi<T = any> = FieldInnerBatchSetters<T> & {
    $outerError: Store<string>;
    $innerError: Store<string>;
    setInnerError: EventCallable<FieldError>;
};

export declare type InsertOrReplacePayload<T extends ArrayFieldItemType> = {
    index: number;
    value: T | T[];
};

export declare function isArrayField(props: any): props is ArrayField<ReadyFieldsGroupSchema>;

export declare function isPrimitiveField(props: any): props is PrimitiveField;

export declare function isPrimitiveValue(props: any): props is PrimitiveValue;

declare interface Meta {
    path: string[];
    baseSid?: string | null;
}

export declare type MovePayload = {
    from: number;
    to: number;
};

declare type Node_2 = any;
export { Node_2 as Node }

export declare type PartialRecursive<T extends FormErrors<any> | FormValues<any>> = Partial<{
    [K in keyof T]: T[K] extends Array<any> ? Array<T[K][number] extends PrimitiveValue ? T[K][number] : PartialRecursive<T[K][number]>> : T[K] extends PrimitiveValue ? T[K] : T[K] extends object ? PartialRecursive<T[K]> : T[K];
}>;

export declare type PathApi = ArrayFieldPathApi | PrimitiveFieldPathApi;

export declare function prepareFieldsSchema<T extends AnySchema | PrimitiveValue, U = UserFormSchema<T>>(schema: T, meta?: Meta): U;

export declare interface PrimitiveField<T extends PrimitiveValue | Json = any, Meta extends object = any> extends PrimitiveFieldApi<T, Meta> {
    '@@type': PrimitiveFieldSymbolType;
    $meta: Store<Meta>;
    $value: Store<T>;
    $error: Store<FieldError>;
    $isValid: Store<boolean>;
    $isFocused: Store<boolean>;
    reset: EventCallable<void>;
    resetCompleted: Event_2<{
        value: T;
        error: FieldError;
    }>;
    blur: EventCallable<void>;
    blurred: Event_2<void>;
    focus: EventCallable<void>;
    focused: Event_2<void>;
    copyOnCreateForm: boolean;
    sid?: string | null;
    '@@unitShape': () => {
        value: Store<T>;
        error: Store<FieldError>;
        meta: Store<Meta>;
        isValid: Store<boolean>;
        isFocused: Store<boolean>;
        changeMeta: EventCallable<Meta>;
        blur: EventCallable<void>;
        focus: EventCallable<void>;
        reset: EventCallable<void>;
        change: EventCallable<T>;
        changeError: EventCallable<FieldError>;
    };
}

export declare interface PrimitiveFieldApi<T extends PrimitiveValue, Meta extends object = any> {
    change: EventCallable<T>;
    changed: Event_2<T>;
    changeMeta: EventCallable<Meta>;
    metaChanged: EventCallable<Meta>;
    blur: EventCallable<void>;
    focus: EventCallable<void>;
    reset: EventCallable<void>;
    changeError: EventCallable<FieldError>;
    errorChanged: Event_2<FieldError>;
}

export declare type PrimitiveFieldPathApi = {
    type: 'primitive-field';
    isValid: boolean;
    clearMemory: (withField?: boolean) => void;
} & BasePathApi;

export declare const primitiveFieldSymbol: unique symbol;

export declare type PrimitiveFieldSymbolType = typeof primitiveFieldSymbol;

export declare type PrimitiveJsonValue = Date | null | undefined | boolean | string | number;

export declare type PrimitiveValue = bigint | PrimitiveJsonValue | Blob | ArrayBuffer | File | FileList;

export declare type PushPayload<T extends ArrayFieldItemType> = T | T[];

export declare interface RawFieldsGroupSchema {
    [key: string]: RawFieldsSchemaFieldType;
}

declare type RawFieldsSchemaFieldType = PrimitiveValue | RawFieldsSchemaFieldType[] | RawFieldsGroupSchema | ReadyFieldsSchemaFieldType;

export declare interface ReadyFieldsGroupSchema {
    [key: string]: ReadyFieldsSchemaFieldType;
}

declare type ReadyFieldsSchemaFieldType = PrimitiveField | ArrayField<any> | ReadyFieldsGroupSchema;

export declare type RemovePayload = {
    index: number;
};

export declare type SwapPayload = {
    indexA: number;
    indexB: number;
};

export declare type SyncValidationFn<Schema extends AnySchema> = (values: FormValues<UserFormSchema<Schema>>) => ErrorsSchemaPayload | null;

export declare type UnshiftPayload<T extends ArrayFieldItemType> = T | T[];

export declare type UserFormSchema<T extends AnySchema | PrimitiveValue> = T extends PrimitiveValue ? T : {
    [K in keyof T]: T[K] extends PrimitiveValue ? PrimitiveField<T[K]> : T[K] extends Array<any> ? ArrayField<T[K][number]> : T[K] extends PrimitiveField<any> ? T[K] : T[K] extends ArrayField<any> ? ArrayField<T[K] extends ArrayField<infer K, any, any> ? K : never, T[K] extends ArrayField<any, infer K, any> ? K : never, UserFormSchema<StoreValue<T[K]['$values']>[number]>> : T[K] extends AnySchema ? UserFormSchema<T[K]> : ReadyFieldsGroupSchema;
};

export declare type ValidationStrategy = 'blur' | 'focus' | 'change' | 'submit';

export { }
