import { clone, getValueByPath, setValueByPath, setValuesAlongPath } from "@grozav/utils";
import { computed, inject, ref, unref, watch } from "vue";
import { FormKey } from "@inkline/inkline/components/IForm";
import { FormGroupKey } from "@inkline/inkline/components/IFormGroup";
import { validate } from "@inkline/inkline/validation";
import { useInkline } from "@inkline/inkline/composables/useInkline";
export function useValidation(options) {
  const inkline = useInkline();
  const form = inject(FormKey, null);
  const formGroup = inject(FormGroupKey, null);
  const schema = form ? computed(
    () => form.schema && options.validate?.value && getValueByPath(form.schema.value, options.name.value)
  ) : ref(options.schema?.value || null);
  if (!form && options.schema?.value) {
    watch(
      () => options.schema?.value,
      (value) => {
        schema.value = value;
      }
    );
  }
  function shouldValidate(schema2, eventName) {
    if (!options.validate?.value) {
      return;
    }
    const events = schema2.validateOn ? [].concat(schema2.validateOn) : inkline?.options?.validateOn;
    return events.includes(eventName);
  }
  function setValue(name, value) {
    if (!options.validate?.value) {
      return;
    }
    let clonedSchema = clone(schema.value);
    const targetSchema = getValueByPath(clonedSchema, name);
    if (!targetSchema) {
      throw new Error(
        'Schema to be validated not found. Did you forget to match the schema key to the input "name" prop?'
      );
    }
    clonedSchema = setValueByPath(clonedSchema, `${name}.value`, value);
    clonedSchema = setValuesAlongPath(clonedSchema, name, {
      pristine: false,
      dirty: true
    });
    if (shouldValidate(targetSchema, "input")) {
      clonedSchema = validate(clonedSchema);
    }
    schema.value = clonedSchema;
    options.onUpdate?.(clonedSchema);
  }
  function setTouched(name, event) {
    if (!options.validate?.value) {
      return;
    }
    let clonedSchema = clone(schema.value);
    const targetSchema = getValueByPath(clonedSchema, name);
    if (!targetSchema) {
      throw new Error(
        'Schema to be validated not found. Did you forget to match the schema key to the input "name" prop?'
      );
    }
    clonedSchema = setValuesAlongPath(clonedSchema, name, {
      untouched: false,
      touched: true
    });
    if (shouldValidate(targetSchema, event.type)) {
      clonedSchema = validate(clonedSchema);
    }
    schema.value = clonedSchema;
    options.onUpdate?.(clonedSchema);
  }
  function onSubmit(event) {
    if (!options.validate?.value) {
      return;
    }
    let clonedSchema = clone(schema.value);
    clonedSchema = setValuesAlongPath(validate(clonedSchema), "", {
      untouched: false,
      touched: true
    });
    if (clonedSchema.valid) {
      options.onSubmit?.(event);
    }
    schema.value = clonedSchema;
    options.onUpdate?.(clonedSchema);
  }
  function onInput(nameRef, value) {
    const name = unref(nameRef);
    if (!options.validate?.value) {
      return;
    }
    if (formGroup) {
      formGroup.onInput(name, value);
    } else if (form) {
      form.onInput(name, value);
    } else if (options.schema?.value) {
      setValue(name, value);
    }
  }
  function onBlur(nameRef, event) {
    const name = unref(nameRef);
    if (!options.validate?.value) {
      return;
    }
    if (formGroup) {
      formGroup.onBlur(name, event);
    } else if (form) {
      form.onBlur(name, event);
    } else if (options.schema?.value) {
      setTouched(name, event);
    }
  }
  return { schema, onSubmit, onInput, onBlur };
}
export function useFormValidationError(options) {
  const hasError = computed(() => {
    if (typeof options.error.value === "boolean") {
      return options.error.value;
    } else if (options.schema.value && options.error.value) {
      let visible = true;
      [].concat(options.error.value).forEach((status) => {
        visible = visible && options.schema.value[status];
      });
      return visible;
    }
    return false;
  });
  return { hasError };
}
