import { ComputedRef, MaybeRefOrGetter, Ref } from "vue";
import { ZodFormattedError } from "zod";

//#region src/types/utils.type.d.ts
declare const $NestedValue: unique symbol;
type NestedValue<TValue extends object = object> = {
  [$NestedValue]: never;
} & TValue;
interface File extends Blob {
  readonly name: string;
  readonly lastModified: number;
}
interface FileList {
  [index: number]: File;
  item: (index: number) => File | null;
  readonly length: number;
}
type Primitive = bigint | boolean | number | string | symbol | null | undefined;
type BrowserNativeObject = Date | File | FileList;
type DeepPartial<T> = T extends BrowserNativeObject | NestedValue ? T : { [K in keyof T]?: DeepPartial<T[K]> };
/**
 * Checks whether the type is any
 * See {@link https://stackoverflow.com/a/49928360/3406963}
 * @typeParam T - type which may be any
 * ```
 * IsAny<any> = true
 * IsAny<string> = false
 * ```
 */
type IsAny<T> = 0 extends 1 & T ? true : false;
/**
 * Checks whether T1 can be exactly (mutually) assigned to T2
 * @typeParam T1 - type to check
 * @typeParam T2 - type to check against
 * ```
 * IsEqual<string, string> = true
 * IsEqual<'foo', 'foo'> = true
 * IsEqual<string, number> = false
 * IsEqual<string, number> = false
 * IsEqual<string, 'foo'> = false
 * IsEqual<'foo', string> = false
 * IsEqual<'foo' | 'bar', 'foo'> = boolean // 'foo' is assignable, but 'bar' is not (true | false) -> boolean
 * ```
 */
type IsEqual<T1, T2> = T1 extends T2 ? (<G>() => G extends T1 ? 1 : 2) extends (<G>() => G extends T2 ? 1 : 2) ? true : false : false;
type NestedNullableKeys<T> = { [K in keyof T]: T[K] extends object ? NestedNullableKeys<T[K]> | null : T[K] | null };
//#endregion
//#region src/types/common.type.d.ts
/**
 * Type to query whether an array type T is a tuple type.
 * @typeParam T - type which may be an array or tuple
 * @example
 * ```
 * IsTuple<[number]> = true
 * IsTuple<number[]> = false
 * ```
 */
type IsTuple<T extends readonly any[]> = number extends T['length'] ? false : true;
/**
 * Type which can be used to index an array or tuple type.
 */
type ArrayKey = number;
/**
 * Type which given a tuple type returns its own keys, i.e. only its indices.
 * @typeParam T - tuple type
 * @example
 * ```
 * TupleKeys<[number, string]> = '0' | '1'
 * ```
 */
type TupleKeys<T extends readonly any[]> = Exclude<keyof T, keyof any[]>;
//#endregion
//#region src/types/eager.type.d.ts
type FieldValues = Record<string, any>;
/**
 * Helper function to break apart T1 and check if any are equal to T2
 *
 * See {@link IsEqual}
 */
type AnyIsEqual<T1, T2> = T1 extends T2 ? IsEqual<T1, T2> extends true ? true : never : never;
/**
 * Helper type for recursively constructing paths through a type.
 * This actually constructs the strings and recurses into nested
 * object types.
 *
 * See {@link Path}
 */
type PathImpl<K$1 extends number | string, V$1, TraversedTypes> = V$1 extends BrowserNativeObject | Primitive ? `${K$1}` : true extends AnyIsEqual<TraversedTypes, V$1> ? `${K$1}` : `${K$1}.${PathInternal<V$1, TraversedTypes | V$1>}` | `${K$1}`;
/**
 * Helper type for recursively constructing paths through a type.
 * This obsucres the internal type param TraversedTypes from exported contract.
 *
 * See {@link Path}
 */
type PathInternal<T, TraversedTypes = T> = T extends ReadonlyArray<infer V> ? IsTuple<T> extends true ? { [K in TupleKeys<T>]-?: PathImpl<K & string, T[K], TraversedTypes> }[TupleKeys<T>] : PathImpl<ArrayKey, V, TraversedTypes> : { [K in keyof T]-?: PathImpl<K & string, T[K], TraversedTypes> }[keyof T];
/**
 * Type which eagerly collects all paths through a type
 * @typeParam T - type which should be introspected
 * @example
 * ```
 * Path<{foo: {bar: string}}> = 'foo' | 'foo.bar'
 * ```
 */
type Path<T> = T extends any ? PathInternal<T> : never;
/**
 * See {@link Path}
 */
type FieldPath<TFieldValues> = Path<TFieldValues>;
/**
 * Helper type for recursively constructing paths through a type.
 * This actually constructs the strings and recurses into nested
 * object types.
 *
 * See {@link ArrayPath}
 */
type ArrayPathImpl<K$1 extends number | string, V$1, TraversedTypes> = V$1 extends BrowserNativeObject | Primitive ? IsAny<V$1> extends true ? string : never : V$1 extends ReadonlyArray<infer U> ? U extends BrowserNativeObject | Primitive ? IsAny<V$1> extends true ? string : never : true extends AnyIsEqual<TraversedTypes, V$1> ? never : `${K$1}.${ArrayPathInternal<V$1, TraversedTypes | V$1>}` | `${K$1}` : true extends AnyIsEqual<TraversedTypes, V$1> ? never : `${K$1}.${ArrayPathInternal<V$1, TraversedTypes | V$1>}`;
/**
 * Helper type for recursively constructing paths through a type.
 * This obsucres the internal type param TraversedTypes from exported contract.
 *
 * See {@link ArrayPath}
 */
type ArrayPathInternal<T, TraversedTypes = T> = T extends ReadonlyArray<infer V> ? IsTuple<T> extends true ? { [K in TupleKeys<T>]-?: ArrayPathImpl<K & string, T[K], TraversedTypes> }[TupleKeys<T>] : ArrayPathImpl<ArrayKey, V, TraversedTypes> : { [K in keyof T]-?: ArrayPathImpl<K & string, T[K], TraversedTypes> }[keyof T];
/**
 * Type which eagerly collects all paths through a type which point to an array
 * type.
 * @typeParam T - type which should be introspected.
 * @example
 * ```
 * Path<{foo: {bar: string[], baz: number[]}}> = 'foo.bar' | 'foo.baz'
 * ```
 */
type ArrayPath<T> = T extends any ? ArrayPathInternal<T> : never;
/**
 * Type to evaluate the type which the given path points to.
 * @typeParam T - deeply nested type which is indexed by the path
 * @typeParam P - path into the deeply nested type
 * @example
 * ```
 * PathValue<{foo: {bar: string}}, 'foo.bar'> = string
 * PathValue<[number, string], '1'> = string
 * ```
 */
type PathValue<T, P extends ArrayPath<T> | Path<T>> = T extends any ? P extends `${infer K}.${infer R}` ? K extends keyof T ? R extends Path<T[K]> ? PathValue<T[K], R> : never : K extends `${ArrayKey}` ? T extends ReadonlyArray<infer V> ? PathValue<V, R & Path<V>> : never : never : P extends keyof T ? T[P] : P extends `${ArrayKey}` ? T extends ReadonlyArray<infer V> ? V : never : never : never;
/**
 * See {@link PathValue}
 */
type FieldPathValue<TFieldValues, TFieldPath extends FieldPath<TFieldValues>> = PathValue<TFieldValues, TFieldPath>;
//#endregion
//#region src/types/standardSpec.type.d.ts
/**
 * The Standard Schema interface.
 */
interface StandardSchemaV1<Input = unknown, Output = Input> {
  /**
   * The Standard Schema properties.
   */
  readonly '~standard': StandardSchemaV1.Props<Input, Output>;
}
declare namespace StandardSchemaV1 {
  /**
   * The Standard Schema properties interface.
   */
  export interface Props<Input = unknown, Output = Input> {
    /**
     * Inferred types associated with the schema.
     */
    readonly types?: Types<Input, Output> | undefined;
    /**
     * Validates unknown input values.
     */
    readonly validate: (value: unknown) => Promise<Result<Output>> | Result<Output>;
    /**
     * The vendor name of the schema library.
     */
    readonly vendor: string;
    /**
     * The version number of the standard.
     */
    readonly version: 1;
  }
  /**
   * The result interface of the validate function.
   */
  export type Result<Output> = FailureResult | SuccessResult<Output>;
  /**
   * The result interface if validation succeeds.
   */
  export interface SuccessResult<Output> {
    /**
     * The non-existent issues.
     */
    readonly issues?: undefined;
    /**
     * The typed output value.
     */
    readonly value: Output;
  }
  /**
   * The result interface if validation fails.
   */
  export interface FailureResult {
    /**
     * The issues of failed validation.
     */
    readonly issues: ReadonlyArray<Issue>;
  }
  /**
   * The issue interface of the failure output.
   */
  export interface Issue {
    /**
     * The error message of the issue.
     */
    readonly message: string;
    /**
     * The path of the issue, if any.
     */
    readonly path?: ReadonlyArray<PathSegment | PropertyKey> | undefined;
  }
  /**
   * The path segment interface of the issue.
   */
  export interface PathSegment {
    /**
     * The key representing a path segment.
     */
    readonly key: PropertyKey;
  }
  /**
   * The Standard Schema types interface.
   */
  export interface Types<Input = unknown, Output = Input> {
    /**
     * The input type of the schema.
     */
    readonly input: Input;
    /**
     * The output type of the schema.
     */
    readonly output: Output;
  }
  /**
   * Infers the input type of a Standard Schema.
   */
  export type InferInput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['input'];
  /**
   * Infers the output type of a Standard Schema.
   */
  export type InferOutput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['output'];
  export {};
}
//#endregion
//#region src/types/form.type.d.ts
/**
 * Represents a form field.
 *
 * @typeparam TValue The type of the field value.
 * @typeparam TDefaultValue The type of the field default value.
 */
interface Field<TValue, TDefaultValue = undefined> {
  /**
   * The unique id of the field.
   */
  '_id': string;
  /**
   * Indicates whether the field has been changed.
   * This flag will remain `true` even if the field value is set back to its initial value.
   */
  'isChanged': Ref<boolean>;
  /**
   * Indicates whether the field value is different from its initial value.
   */
  'isDirty': ComputedRef<boolean>;
  /**
   * Indicates whether the field has been touched (blurred).
   */
  'isTouched': ComputedRef<boolean>;
  /**
   * Indicates whether the field has any errors.
   */
  'isValid': ComputedRef<boolean>;
  /**
   * Internal flag to track if the field has been touched (blurred).
   */
  '_isTouched': Ref<boolean>;
  /**
   * The current path of the field. This can change if fields are unregistered.
   */
  '_path': ComputedRef<string | null>;
  /**
   * Blur the field and all it's children.
   */
  'blurAll': () => void;
  /**
   * The errors associated with the field and its children.
   */
  'errors': ComputedRef<FormattedError<TValue>[]>;
  /**
   * The current value of the field.
   */
  'modelValue': ComputedRef<TDefaultValue extends undefined ? TValue | null : TValue>;
  /**
   * The raw errors associated with the field and its children.
   */
  'rawErrors': ComputedRef<StandardSchemaV1.Issue[]>;
  'register': <TValueAsFieldValues extends (TValue extends FieldValues ? TValue : never), TChildPath extends FieldPath<TValueAsFieldValues>, TChildDefaultValue extends FieldPathValue<TValueAsFieldValues, TChildPath> | undefined>(path: TChildPath, defaultValue?: TChildDefaultValue) => Field<FieldPathValue<TValueAsFieldValues, TChildPath>, TChildDefaultValue>;
  'registerArray': <TPath extends (TValue extends FieldValues ? FieldPath<TValue> : never), TChildDefaultValue extends (TValue extends FieldValues ? FieldPathValue<TValue, TPath> | undefined : never)>(path: TPath, defaultValue?: TChildDefaultValue) => FieldArray<FieldPathValue<TValue, TPath> extends Array<any> ? FieldPathValue<TValue, TPath>[number] : never>;
  /**
   * Sets the current value of the field.
   *
   * This is an alias of `onUpdate:modelValue`.
   *
   * @param value The new value of the field.
   */
  'setValue': (value: TValue | null) => void;
  /**
   * The current value of the field.
   *
   * This is an alias of `attrs.modelValue`.
   */
  'value': ComputedRef<TDefaultValue extends undefined ? TValue | null : TValue>;
  /**
   * Called when the field input is blurred.
   */
  'onBlur': () => void;
  /**
   * Called when the field input value is changed.
   */
  'onChange': () => void;
  /**
   * Updates the current value of the field.
   *
   * @param value The new value of the field.
   */
  'onUpdate:modelValue': (value: TValue | null) => void;
}
/**
 * Represents a form field array.
 *
 * @typeparam T The type of the form schema.
 */
interface FieldArray<TValue> {
  /**
   * The unique id of the field.
   */
  _id: string;
  /**
   * Indicates whether the field value is different from its initial value.
   */
  isDirty: ComputedRef<boolean>;
  /**
   * Indicates whether the field has been touched (blurred).
   */
  isTouched: ComputedRef<boolean>;
  /**
   * Indicates whether the field has any errors.
   */
  isValid: ComputedRef<boolean>;
  /**
   * The current path of the field. This can change if fields are unregistered.
   */
  _path: ComputedRef<string | null>;
  /**
   * Add a new field at the end of the array.
   */
  append: (value?: TValue) => void;
  blurAll: () => void;
  /**
   * Empty the array.
   */
  empty: () => void;
  /**
   * The errors associated with the field and its children.
   */
  errors: ComputedRef<FormattedError<TValue[]>[]>;
  /**
   * Blur the field and all it's children.
   */
  /**
   * Array of unique ids of the fields.
   */
  fields: Ref<string[]>;
  /**
   * Insert a new field at the given index.
   * @param index The index of the field to insert.
   */
  insert: (index: number, value?: TValue) => void;
  /**
   * The current value of the field.
   */
  modelValue: ComputedRef<TValue[]>;
  /**
   * Move a field from one index to another.
   */
  move: (from: number, to: number) => void;
  /**
   * Remove the last field of the array.
   */
  pop: () => void;
  /**
   * Add a new field at the beginning of the array.
   */
  prepend: (value?: TValue) => void;
  /**
   * The raw errors associated with the field and its children.
   */
  rawErrors: ComputedRef<StandardSchemaV1.Issue[]>;
  register: <TChildPath extends (TValue[] extends FieldValues ? FieldPath<TValue[]> : never), TChildDefaultValue extends (TValue[] extends FieldValues ? FieldPathValue<TValue[], TChildPath> | undefined : never)>(path: TChildPath, defaultValue?: TChildDefaultValue) => TValue[] extends FieldValues ? Field<FieldPathValue<TValue[], TChildPath>, any> : never;
  registerArray: <TPath extends (TValue[] extends FieldValues ? FieldPath<TValue[]> : never), TArrayValue extends FieldPathValue<TValue[], TPath>, TChildDefaultValue extends (TValue[] extends FieldValues ? FieldPathValue<TValue[], TPath> | undefined : never), TSingleValue extends (TArrayValue extends Array<any> ? TArrayValue[number] : never)>(path: TPath, defaultValue?: TChildDefaultValue) => FieldArray<TSingleValue>;
  /**
   * Remove a field at the given index.
   * @param index The index of the field to remove.
   */
  remove: (index: number) => void;
  /**
   * Set the current value of the field.
   */
  setValue: (value: TValue[]) => void;
  /**
   * Remove the first field of the array.
   */
  shift: () => void;
  /**
   * The current value of the field.
   *
   * This is an alias of `attrs.modelValue`.
   */
  value: ComputedRef<TValue[]>;
}
type Register<TSchema> = <TPath extends FieldPath<TSchema>, TValue extends FieldPathValue<TSchema, TPath>, TDefaultValue extends FieldPathValue<TSchema, TPath> | undefined>(field: TPath, defaultValue?: TDefaultValue) => Field<TValue, TDefaultValue>;
type RegisterArray<TSchema extends StandardSchemaV1> = <TPath extends FieldPath<StandardSchemaV1.InferOutput<TSchema>>, TValue extends FieldPathValue<StandardSchemaV1.InferOutput<TSchema>, TPath>, TSingleValue extends (TValue extends Array<any> ? TValue[number] : never), TDefaultValue extends FieldPathValue<StandardSchemaV1.InferOutput<TSchema>, TPath> | undefined>(field: TPath, defaultValue?: TDefaultValue) => FieldArray<TSingleValue>;
type Unregister<T extends StandardSchemaV1> = <P extends FieldPath<StandardSchemaV1.InferOutput<T>>>(field: P) => void;
interface Form<TSchema extends StandardSchemaV1> {
  /**
   * Internal id of the form, to track it in the devtools.
   */
  _id: string;
  /**
   * Indicates whether the form has been attempted to submit.
   */
  hasAttemptedToSubmit: ComputedRef<boolean>;
  /**
   * Indicates whether the form is dirty or not.
   *
   * A form is considered dirty if any of its fields have been changed.
   */
  isDirty: ComputedRef<boolean>;
  /**
   * Indicates whether the form is currently submitting or not.
   */
  isSubmitting: ComputedRef<boolean>;
  /**
   * Indicates whether the form is currently valid or not.
   *
   * A form is considered valid if all of its fields are valid.
   */
  isValid: ComputedRef<boolean>;
  /**
   * Sets errors in the form.
   *
   * @param errors The new errors for the form fields.
   */
  addErrors: (errors: FormattedError<StandardSchemaV1.InferOutput<TSchema>>[]) => void;
  /**
   * Blurs all inputs in the form.
   */
  blurAll: () => void;
  /**
   * The collection of all registered fields' errors.
   */
  errors: ComputedRef<FormattedError<StandardSchemaV1.InferOutput<TSchema>>[]>;
  /**
   * The raw errors associated with the field and its children.
   */
  rawErrors: ComputedRef<StandardSchemaV1.Issue[]>;
  /**
   * Registers a new form field.
   *
   * @returns A `Field` instance that can be used to interact with the field.
   */
  register: Register<StandardSchemaV1.InferOutput<TSchema>>;
  /**
   * Registers a new form field array.
   *
   * @returns A `FieldArray` instance that can be used to interact with the field array.
   */
  registerArray: RegisterArray<TSchema>;
  /**
   * Resets the form to the initial state.
   */
  reset: () => void;
  /**
   * Sets values in the form.
   *
   * @param values The new values for the form fields.
   */
  setValues: (values: DeepPartial<StandardSchemaV1.InferOutput<TSchema>>) => void;
  /**
   * The current state of the form.
   */
  state: ComputedRef<Readonly<DeepPartial<StandardSchemaV1.InferOutput<TSchema>>>>;
  /**
   * Submits the form.
   *
   * @returns A promise that resolves once the form has been successfully submitted.
   */
  submit: () => Promise<void>;
  /**
   * Unregisters a previously registered field.
   *
   * @param path The path of the field to unregister.
   */
  unregister: Unregister<TSchema>;
}
/**
 * Represents a form instance.
 *
 * @typeparam T The type of the form schema.
 */
interface UseForm<T extends StandardSchemaV1> {
  /**
   * The form instance itself.
   */
  form: Form<T>;
  /**
   * Called when the form is valid and submitted.
   * @param cb - Callback invoked with the current form data when the form is valid and submitted.
   */
  onSubmitForm: (cb: (data: StandardSchemaV1.InferOutput<T>) => void) => void;
}
interface FormattedError<TType> {
  message: string;
  path: FieldPath<TType extends FieldValues ? TType : never>;
}
//#endregion
//#region src/lib/formatErrors.d.ts
type SomeIssues<TType> = FormattedError<TType>[] | readonly StandardSchemaV1.Issue[];
declare function formatErrorsToZodFormattedError<TType>(issues: SomeIssues<TType>): ZodFormattedError<TType>;
//#endregion
//#region src/lib/useForm.d.ts
interface UseFormOptions<TSchema extends StandardSchemaV1> {
  /**
   * The initial state of the form
   */
  initialState?: MaybeRefOrGetter<NestedNullableKeys<StandardSchemaV1.InferOutput<TSchema>> | null>;
  /**
   * The zod schema of the form.
   */
  schema: TSchema;
  /**
   * Called when the form is valid and submitted.
   * @param data The current form data.
   */
  onSubmit: (data: StandardSchemaV1.InferOutput<TSchema>) => void;
  /**
   * Called when the form is attempted to be submitted, but is invalid.
   * Only called for client-side validation.
   */
  onSubmitError?: ({
    data,
    errors
  }: {
    data: DeepPartial<NestedNullableKeys<StandardSchemaV1.InferOutput<TSchema>>>;
    errors: FormattedError<StandardSchemaV1.InferOutput<TSchema>>[];
  }) => void;
}
declare function useForm<TSchema extends StandardSchemaV1>({
  initialState,
  schema,
  onSubmit,
  onSubmitError
}: UseFormOptions<TSchema>): Form<TSchema>;
//#endregion
export { type Field, type FieldArray, type Form, type FormattedError, type UseForm, formatErrorsToZodFormattedError, useForm };