"use client";
import {
  createCollectionStore
} from "../__chunks/N5XGANPW.js";
import "../__chunks/3DNM6L6E.js";
import {
  createStore,
  init,
  setup,
  sync,
  throwOnConflictingProps
} from "../__chunks/SXKM4CGU.js";
import {
  applyState,
  defaultValue,
  isInteger,
  isObject
} from "../__chunks/XMCVU3LR.js";

// src/form/form-store.ts
function nextFrame() {
  return new Promise((resolve) => requestAnimationFrame(() => resolve()));
}
function hasMessages(object) {
  return Object.keys(object).some((key) => {
    if (isObject(object[key])) {
      return hasMessages(object[key]);
    }
    return !!object[key];
  });
}
function get(values, path, defaultValue2) {
  var _a;
  const [key, ...rest] = Array.isArray(path) ? path : `${path}`.split(".");
  if (key == null || !values) {
    return defaultValue2;
  }
  if (!rest.length) {
    return (_a = values[key]) != null ? _a : defaultValue2;
  }
  return get(values[key], rest, defaultValue2);
}
function set(values, path, value) {
  const [k, ...rest] = Array.isArray(path) ? path : `${path}`.split(".");
  if (k == null) return values;
  const key = k;
  const isIntegerKey = isInteger(key);
  const nextValues = isIntegerKey ? values || [] : values || {};
  const nestedValues = nextValues[key];
  const result = rest.length && (Array.isArray(nestedValues) || isObject(nestedValues)) ? set(nestedValues, rest, value) : value;
  if (isIntegerKey) {
    const index = Number(key);
    if (values && Array.isArray(values)) {
      return [
        ...values.slice(0, index),
        result,
        ...values.slice(index + 1)
      ];
    }
    const nextValues2 = [];
    nextValues2[index] = result;
    return nextValues2;
  }
  return { ...values, [key]: result };
}
function setAll(values, value) {
  const result = {};
  const keys = Object.keys(values);
  for (const key of keys) {
    const currentValue = values[key];
    if (Array.isArray(currentValue)) {
      result[key] = currentValue.map((v) => {
        if (isObject(v)) {
          return setAll(v, value);
        }
        return value;
      });
    } else if (isObject(currentValue)) {
      result[key] = setAll(currentValue, value);
    } else {
      result[key] = value;
    }
  }
  return result;
}
function getNameHandler(cache, prevKeys = []) {
  const handler = {
    get(target, key) {
      if (["toString", "valueOf", Symbol.toPrimitive].includes(key)) {
        return () => prevKeys.join(".");
      }
      const nextKeys = [...prevKeys, key];
      const nextKey = nextKeys.join(".");
      if (cache[nextKey]) {
        return cache[nextKey];
      }
      const nextProxy = new Proxy(target, getNameHandler(cache, nextKeys));
      cache[nextKey] = nextProxy;
      return nextProxy;
    }
  };
  return handler;
}
function getStoreCallbacks(store) {
  return store == null ? void 0 : store.__unstableCallbacks;
}
function createNames() {
  const cache = /* @__PURE__ */ Object.create(null);
  return new Proxy(/* @__PURE__ */ Object.create(null), getNameHandler(cache));
}
function createFormStore(props = {}) {
  var _a;
  throwOnConflictingProps(props, props.store);
  const syncState = (_a = props.store) == null ? void 0 : _a.getState();
  const collection = createCollectionStore(props);
  const values = defaultValue(
    props.values,
    syncState == null ? void 0 : syncState.values,
    props.defaultValues,
    {}
  );
  const errors = defaultValue(
    props.errors,
    syncState == null ? void 0 : syncState.errors,
    props.defaultErrors,
    {}
  );
  const touched = defaultValue(
    props.touched,
    syncState == null ? void 0 : syncState.touched,
    props.defaultTouched,
    {}
  );
  const initialState = {
    ...collection.getState(),
    values,
    errors,
    touched,
    validating: defaultValue(syncState == null ? void 0 : syncState.validating, false),
    submitting: defaultValue(syncState == null ? void 0 : syncState.submitting, false),
    submitSucceed: defaultValue(syncState == null ? void 0 : syncState.submitSucceed, 0),
    submitFailed: defaultValue(syncState == null ? void 0 : syncState.submitFailed, 0),
    valid: !hasMessages(errors)
  };
  const form = createStore(initialState, collection, props.store);
  const syncCallbacks = getStoreCallbacks(props.store);
  const syncCallbacksState = syncCallbacks == null ? void 0 : syncCallbacks.getState();
  const callbacksInitialState = {
    validate: (syncCallbacksState == null ? void 0 : syncCallbacksState.validate) || [],
    submit: (syncCallbacksState == null ? void 0 : syncCallbacksState.submit) || []
  };
  const callbacks = createStore(callbacksInitialState, syncCallbacks);
  setup(form, () => init(callbacks));
  setup(
    form,
    () => sync(form, ["validating", "errors"], (state) => {
      if (state.validating) return;
      form.setState("valid", !hasMessages(state.errors));
    })
  );
  const validate = async () => {
    form.setState("validating", true);
    form.setState("errors", {});
    const validateCallbacks = callbacks.getState().validate;
    try {
      for (const callback of validateCallbacks) {
        await callback(form.getState());
      }
      await nextFrame();
      return !hasMessages(form.getState().errors);
    } finally {
      form.setState("validating", false);
    }
  };
  return {
    ...collection,
    ...form,
    names: createNames(),
    setValues: (values2) => form.setState("values", values2),
    getValue: (name) => get(form.getState().values, name),
    setValue: (name, value) => form.setState("values", (values2) => {
      const prevValue = get(values2, name);
      const nextValue = applyState(value, prevValue);
      if (nextValue === prevValue) return values2;
      return set(values2, name, nextValue);
    }),
    pushValue: (name, value) => form.setState("values", (values2) => {
      const array = get(values2, name, []);
      return set(values2, name, [...array, value]);
    }),
    removeValue: (name, index) => form.setState("values", (values2) => {
      const array = get(values2, name, []);
      return set(values2, name, [
        ...array.slice(0, index),
        null,
        ...array.slice(index + 1)
      ]);
    }),
    setErrors: (errors2) => form.setState("errors", errors2),
    getError: (name) => get(form.getState().errors, name),
    setError: (name, error) => form.setState("errors", (errors2) => {
      const prevError = get(errors2, name);
      const nextError = applyState(error, prevError);
      if (nextError === prevError) return errors2;
      return set(errors2, name, nextError);
    }),
    setTouched: (touched2) => form.setState("touched", touched2),
    getFieldTouched: (name) => !!get(form.getState().touched, name),
    setFieldTouched: (name, value) => form.setState("touched", (touched2) => {
      const prevValue = get(touched2, name);
      const nextValue = applyState(value, prevValue);
      if (nextValue === prevValue) return touched2;
      return set(touched2, name, nextValue);
    }),
    onValidate: (callback) => {
      callbacks.setState("validate", (callbacks2) => [...callbacks2, callback]);
      return () => {
        callbacks.setState(
          "validate",
          (callbacks2) => callbacks2.filter((c) => c !== callback)
        );
      };
    },
    validate,
    onSubmit: (callback) => {
      callbacks.setState("submit", (callbacks2) => [...callbacks2, callback]);
      return () => {
        callbacks.setState(
          "submit",
          (callbacks2) => callbacks2.filter((c) => c !== callback)
        );
      };
    },
    submit: async () => {
      form.setState("submitting", true);
      form.setState("touched", setAll(form.getState().values, true));
      try {
        if (await validate()) {
          const submitCallbacks = callbacks.getState().submit;
          for (const callback of submitCallbacks) {
            await callback(form.getState());
          }
          await nextFrame();
          if (!hasMessages(form.getState().errors)) {
            form.setState("submitSucceed", (count) => count + 1);
            return true;
          }
        }
        form.setState("submitFailed", (count) => count + 1);
        return false;
      } catch (error) {
        form.setState("submitFailed", (count) => count + 1);
        throw error;
      } finally {
        form.setState("submitting", false);
      }
    },
    reset: () => {
      form.setState("values", values);
      form.setState("errors", errors);
      form.setState("touched", touched);
      form.setState("validating", false);
      form.setState("submitting", false);
      form.setState("submitSucceed", 0);
      form.setState("submitFailed", 0);
      form.setState("valid", !hasMessages(errors));
    },
    // @ts-expect-error Internal
    __unstableCallbacks: callbacks
  };
}
export {
  createFormStore,
  get,
  hasMessages
};
