import type { Rule, RuleItem, Rules } from "async-validator";
import type { FormInstance, FormProps } from "../form/Form.vue";
import type { FieldProps } from "../form/Field.vue";
import type { ColProps } from "../layout/grid/Col.vue";
import type { RowProps } from "../layout/grid/Row.vue";

export interface IDynamicFormOptions {
  /**
   * 表单额外属性
   */
  formAdditionaProps?: Omit<FormProps, 'model'>;  
  /**
   * 表单校验规则
   */
  formRules?: Rules;
  /**
   * 子条目定义
   */
  formItems: IDynamicFormItem[];
  /**
   * 是否在根级别抑制错误提示
   */
  suppressRootError?: boolean;
  /**
   * 空文本
   */
  emptyText?: string;
  /**
   * 是否禁用表单
   */
  disabled?: boolean;
  /**
   * 是否只读表单
   */
  readonly?: boolean;
  /**
   * 是否屏蔽所有子条目空错误。默认否
   * @default false
   */
  suppressEmptyError?: boolean,
  /**
   * 当显示嵌套的表单对象条目时是否在前部显示缩进，
   * 缩进大小可使用 CSS 变量 `--dynamic-form-item-nest-margin` 自定义。默认是 20px
   * @default true
   */
  nestObjectMargin?: boolean,
}

/**
 * 表单动态属性定义
 */
export declare type IDynamicFormItemCallback<T> = {
  /**
   * 预留，暂未使用
   */
  type?: string;
  /**
   * @param model 当前表单条目的值
   * @param rawModel 整个 form 的值 （最常用，当两个关联组件距离较远时，可以从顶层的 rawModel 里获取）
   * @param parentModel 父表单元素的值 （上一级的值，只在列表场景的使用，例如列表某个元素的父级就是整个 item）
   * @param item 当前表单条目信息
   */
  callback: (model: any, rawModel: any, parentModel: any, params: { 
    /**
     * 当前表单条目
     */
    item: IDynamicFormItem, 
    /**
     * 当前表单条目的父级，为空时表示当前条目为根级别。
     */
    parent?: IDynamicFormItem,
    /**
     * 当前表单组件实例
     */
    form: IDynamicFormRef,
    /**
     * 全局参数。由表单组件顶层添加额外的参数。
     */
    formGlobalParams: IDynamicFormObject, 
    /**
     * 当前条目校验数据
     */
    formRules?: Record<string, Rule>,
    /**
     * 是否是所在层级的第一个表单项
     */
    isFirst: boolean,
    /**
     * 是否是所在层级的最后一个表单项
     */
    isLast: boolean,
  }) => T;
};
export type IDynamicFormItemCallbackAdditionalProps<T> = { [P in keyof T]?: T[P]|IDynamicFormItemCallback<T[P]> }

export type DynamicFormNestNameGenerateType = 'dot'|'array'

/**
 * 表单事件中心消息名称
 */
/**
 * 重新加载表单项目。由条目自由处理。
 */
export const MESSAGE_RELOAD = 'reload';

export type IDynamicFormObject = Record<string, any>

/**
 * 表单动态组件属性定义
 */
export interface IDynamicFormComponentAdditionalDefine {
  /**
   * 组件名称
   */
  name: string,
  /**
   * 是否需要显示右侧箭头
   */
  needArrow?: boolean,
  /**
   * 传递给表单条目的参数
   */
  itemProps?: FieldProps,
  /**
   * 传递给组件的参数
   */
  props?: Record<string, unknown>|unknown,
}

export interface IDynamicFormItem {
  /**
   * 表单项显示标签
   */
  label?: string|IDynamicFormItemCallback<string>;
  /**
   * 属性名称
   */
  name: string;
  /**
   * 表单项组件类型
   */
  type?: string;
  /**
   * 传递给条目组件的参数。（允许动态回调）
   */
  additionalProps?: Record<string, unknown|IDynamicFormItemCallback<unknown>>|unknown;
  /**
   * 传递给FormItem组件的参数
   */
  formProps?: FieldProps;
  /**
   * 默认值，用于默认数据生成
   */
  defaultValue?: any;
  /**
   * 是否屏蔽空错误。默认否
   * @default false
   */
  suppressEmptyError?: boolean,
  /**
   * 当前条目的校验规则
   */
  rules?: RuleItem[],
  /**
   * 子条目，在对象中为对象子属性，在数组中为数组条目(单条目按单项控制，多条目按对象看待控制)
   */
  children?: IDynamicFormItem[],

  /**
   * 是否显示。当为undefined时，默认显示。
   */
  show?: boolean|IDynamicFormItemCallback<boolean>|undefined,
  /**
   * 是否禁用当前表单项
   */
  disabled?: boolean|IDynamicFormItemCallback<boolean>;

  /**
   * 当前条目组件加载时发生事件
   * @param nowModel 当前表单条目的值
   * @param rawModel 顶层数据对象
   * @param ref 组件实例
   * @returns 
   */
  mounted?: (nowModel: any, rawModel: any, ref: any) => void;
  /**
   * 当前条目组件卸载时发生事件
   * @param nowModel 当前表单条目的值
   * @param rawModel 顶层数据对象
   * @param ref 组件实例
   * @returns 
   */
  beforeUnmount?: (nowModel: any, rawModel: any, ref: any) => void;
  /**
   * 当前条目数据更改时发生事件
   * @param oldValue 旧值
   * @param newValue 新值
   * @param topModel 顶层数据对象
   * @param ref 组件实例
   * @returns 
   */
  watch?: (oldValue: any, newValue: any, rawModel: any, ref: any) => void;
  /**
   * 监听从外部或者其他表单发送过来的消息事件
   * @param messageName 消息名称
   * @param data 消息数据
   * @param getComponentRef 当前组件的实例
   * @returns 
   */
  message?: (messageName: string, data: unknown, getComponentRef: () => unknown) => void,
  /**
   * 当子对象为数组时，可设置这个自定义回调。用于添加按钮新建一个对象，如果这个函数为空，则没有添加按钮。
   */
  newChildrenObject?: (arrayNow: unknown[]) => unknown;
  /**
   * 当子对象为数组时，可设置这个自定义回调。删除按钮回调，可选，不提供时默认操作为将 item 从 array 中移除。
   */
  deleteChildrenCallback?: (arrayNow: unknown[], deleteObject: unknown) => unknown;
  /**
   * 子条目的 Col 配置属性(应用到当前条目的所有子条目上)。仅在 object 或者其他容器条目中有效。
   */
  childrenColProps?: ColProps,
  /**
   * 当前条目的 Col 配置属性(应用到当前条目上)。仅在 object 或者其他容器条目中有效。
   */
  colProps?: ColProps,
  /**
   * 当前条目的 Row 配置属性(应用到当前条目上)。仅在 object 或者其他容器条目中有效。
   */
  rowProps?: RowProps,
  /**
   * 当显示嵌套的表单对象条目时是否在前部显示缩进。默认是
   */
  nestObjectMargin?: boolean,

  
  //内部使用，不建议外部调用
  fullName?: string;
}
export interface IDynamicFormRef {
  /**
   * 获取表单组件的 Ref
   * @returns 
   */
  getFormRef: () => FormInstance;
  /**
   * 获取指定表单项组件的 Ref
   * @returns 
   */
  getFormItemControlRef: <T>(key: string) => T;
  /**
   * 获取指定类型的所有表单项组件的 Ref
   * @param type 组件类型
   * @returns 
   */
  getFormItemControlRefsByType: <T>(type: string) => T[];
  /**
   * 触发提交。同 getFormRef().submit() 。
   * @returns 
   */
  submit: () => void;
  /**
   * 验证当前表单数据是否有效。同 getFormRef().validate() 。
   * @returns 
   */
  validate: () => Promise<void>;
  /**
   * 外部修改指定单个 field 的数据
   * @param path 路径
   * @param value 值
   * @returns 
   */
  setValueByPath: (path: string|string[], value: unknown) => void,
  /**
   * 外部获取指定单个 field 的数据
   * @param path 路径
   * @returns 
   */
  getValueByPath: (path: string|string[]) => unknown,
  /**
   * 向所有或者指定的子组件分发消息事件。
   * @param messageName 消息名称。
   * @param data 可选参数。
   * @param receiveFilter 可选名称筛选正则，此正则通过名称的子组件会接受事件，其他则不会。
   * @returns 
   */
  dispatchMessage: (messageName: string, data?: unknown, receiveFilter?: RegExp) => void;
  /**
   * 向所有子组件分发重新加载消息事件。
   * @returns 
   */
  dispatchReload: () => void;
  /**
   * 获取当前表单中可见的所有字段名
   */
  getVisibleFormNames: () => string[];
  /**
   * 初始化表单默认值到模型中，对于已有数据非空的字段，不会覆盖已有的值。
   * @returns 
   */
  initDefaultValuesToModel: () => void;
}

/**
 * 默认的动态表单属性
 */
export let defaultDynamicFormOptions = {} as IDynamicFormOptions;

/**
 * 配置默认的动态表单属性，配置后将会对所有动态表单生效。
 * @param options 参数
 */
export function configDefaultDynamicFormOptions(options: Omit<IDynamicFormOptions, 'formItems'>) {
  defaultDynamicFormOptions = {
    ...defaultDynamicFormOptions,
    ...options,
  };
}

export type IEvaluateCallback = <T>(val: T | IDynamicFormItemCallback<T>) => T;
export type IDynamicFormMessageCenterCallback = (messageName: string, data: unknown) => void;

export type IDynamicFormWidgetRef = () => unknown;

export interface IDynamicFormMessageCenter {
  addInstance: (name: string, fn: IDynamicFormMessageCenterCallback) => void,
  addWidgetRef: (name: string, type: string, ref: IDynamicFormWidgetRef) => void,
  removeWidgetRef: (name: string, type: string, ref: IDynamicFormWidgetRef) => void,
  removeInstance: (name: string) => void,
}