import type { ComputedRef, Ref } from 'vue';
import { toRaw, unref } from 'vue';
import { isObject } from '@vueuse/core';
import { isArray, isFunction } from '@/utils/zt/is';
import { deepMerge } from '@/utils/zt';
import { cloneDeep } from '@/utils/zt/lodashChunk';
import type { FormActionType, FormProps, FormSchema } from '../types/form';

// 定义事件类型枚举
type FormEvents = 'registerForm' | 'reset' | 'submit';

// 修改 EmitType 类型
declare type EmitType = (event: FormEvents, ...args: any[]) => void;

interface UseFormActionContext {
  emit: EmitType;
  getProps: ComputedRef<FormProps>;
  getSchema: ComputedRef<FormSchema[]>;
  formModel: Recordable;
  formElRef: Ref<FormActionType>;
  defaultFormModel: Recordable;
  loadingSub: Ref<boolean>;
  schemaRef: Ref<FormSchema[]>;
  handleFormValues: (values: Recordable) => Recordable;
}

export function useFormEvents({
  emit,
  getProps,
  formModel,
  getSchema,
  formElRef,
  defaultFormModel,
  loadingSub,
  schemaRef,
  handleFormValues
}: UseFormActionContext) {
  // 验证
  async function validate() {
    return unref(formElRef)?.validate();
  }

  // 提交
  async function handleSubmit(e?: Event): Promise<object | boolean> {
    if (e) e.preventDefault();
    loadingSub.value = true;
    const { submitFunc } = unref(getProps);
    if (submitFunc && isFunction(submitFunc)) {
      await submitFunc();
      loadingSub.value = false;
      return false;
    }
    const formEl = unref(formElRef);
    if (!formEl) return false;
    try {
      await validate();
      const values = getFieldsValue();
      loadingSub.value = false;
      emit('submit', values);
      return values;
    } catch (error: any) {
      emit('submit', false);
      loadingSub.value = false;
      console.error(error);
      return false;
    }
  }

  // 清空校验
  async function clearValidate() {
    await unref(formElRef)?.restoreValidation();
  }

  // 重置
  async function resetFields(): Promise<void> {
    const { resetFunc, submitOnReset } = unref(getProps);
    if (resetFunc && isFunction(resetFunc)) {
      await resetFunc();
    }

    const formEl = unref(formElRef);
    if (!formEl) return;
    Object.keys(formModel).forEach(key => {
      formModel[key] = unref(defaultFormModel)[key] || null;
    });
    await clearValidate();
    const fromValues = handleFormValues(toRaw(unref(formModel)));
    emit('reset', fromValues);
    if (submitOnReset) {
      await handleSubmit();
    }
  }

  // 获取表单值
  function getFieldsValue(): Recordable {
    const formEl = unref(formElRef);
    if (!formEl) return {};
    return handleFormValues(toRaw(unref(formModel)));
  }

  // 设置表单字段值
  async function setFieldsValue(values: Recordable): Promise<void> {
    const fields = unref(getSchema)
      .map(item => item.field)
      .filter(Boolean);

    Object.keys(values).forEach(key => {
      const value = values[key];
      if (fields.includes(key)) {
        formModel[key] = value;
      }
    });
  }
  function updateSchema(data: Partial<FormSchema> | Partial<FormSchema>[]) {
    let updateData: Partial<FormSchema>[] = [];
    if (isObject(data)) {
      updateData.push(data as FormSchema);
    }
    if (isArray(data)) {
      updateData = [...data];
    }

    const hasField = updateData.every(item => Reflect.has(item, 'field') && item.field);

    if (!hasField) {
      console.error('All children of the form Schema array that need to be updated must contain the  field');
      return;
    }

    // 只更新传入的字段，其余保持不变
    const schema: FormSchema[] = cloneDeep(unref(getSchema));
    const updatedFields: string[] = [];

    updateData.forEach(item => {
      if (item.field) {
        const index = schema.findIndex(val => val.field === item.field);
        if (index !== -1) {
          schema[index] = deepMerge(schema[index], item) as FormSchema;
          updatedFields.push(item.field);
        }
      }
    });
    schemaRef.value = schema;
  }

  function setLoading(value: boolean): void {
    loadingSub.value = value;
  }

  return {
    handleSubmit,
    validate,
    resetFields,
    getFieldsValue,
    clearValidate,
    setFieldsValue,
    setLoading,
    updateSchema
  };
}
