import { Slot } from 'vue';
import { GenericObject } from 'vee-validate';

export type FormValue =
  | string
  | string[]
  | number
  | number[]
  | boolean
  | boolean[]
  | Record<string, unknown>
  | Record<string, unknown>[];

export type FormPayload<T = Record<string, FormValue>> = {
  stayAfterSubmit: boolean;
  formValues: T;
};

/**
 * Props for Form component
 */
export interface FormProps {
  /**
   * The number of columns per row.
   * @default 1;
   */
  columnPerRow?: number;
  /**
   * The template for form buttons.
   */
  buttonsTemplate?: (
    | 'clear'
    | 'reset'
    | 'submit'
    | 'save'
    | 'save-outlined'
    | 'cancel'
  )[];
  /**
   * Trigger form validated on button save clicked
   *
   * @default false
   */
  validateOnSave?: boolean;
  /**
   * Custom button submit label.
   */
  submitBtnLabel?: string;
  /**
   * Determines if the stay checkbox should be hidden.
   */
  hideStayCheckbox?: boolean;
  /**
   * Prevent form resets after submitted. Default is resetted.
   *
   * @default true
   */
  resetAfterSubmit?: boolean;
  /**
   * Determines if the buttons should be sticky.
   */
  stickyButtons?: boolean;
  hideFooter?: boolean;
  /**
   * Custom submit form validator message.
   */
  validatorMessage?: string;
  /**
   * Invalid form state.
   */
  invalid?: boolean;
}

/**
 * Slots for Form component
 */
export interface FormSlots {
  /**
   * The fields slot for the form. Here is where you can put your form fields.
   */
  fields: Slot<{ formValues: GenericObject; key?: number }>;
}

/**
 * Emits for Form component
 */
export type FormEmits = {
  submit: [values: FormPayload];
  save: [values: FormPayload];
  beforeSubmit: [];
  beforeSave: [];
  clear: [];
  cancel: [];
};

/**
 * **TSVue v2 - Form**
 *
 * _Form is a component for creating forms with validation on submit using vee-validate.
 * You need to install vee-validate while using this component._
 *
 * --- ---
 * ![TSVue](https://ik.imagekit.io/kurniadev/TS-HEAD-BLACK.png)
 *
 * @group components
 */
declare class Form extends ClassComponent<FormProps, FormSlots, FormEmits> {
  values: GenericObject;
  errors: ComputedRef<Partial<Record<string, string | undefined>>>;
  /**
   * Wether to keep the dialog remains visible or not after submit.
   */
  stayAfterSubmit: Ref<boolean>;
  /**
   * The ref of form element.
   */
  formElement: HTMLFormElement;
  submit: (e?: Event | undefined) => Promise<void | undefined>;
  /**
   * Clears the form fields.
   */
  clearField: () => void;
  /**
   * Sets the errors for the form fields.
   */
  setErrors: (errors: Partial<Record<string, string | undefined>>) => void;
  /**
   * Sets the error for a specific field.
   */
  setFieldError: (field: string, error: string | undefined) => void;
}

declare module '@vue/runtime-core' {
  interface GlobalComponents {
    Form: GlobalComponentConstructor<Form>;
  }
}

export default Form;
