import { computed, onMounted, ref, watch } from "vue";
import { useDebounceFn } from "@vueuse/core";
import ls from "localstorage-slim";
function isEmptyValue(v) {
  if (v == null) return true;
  if (Array.isArray(v)) return v.length === 0;
  return false;
}
export function useLocalStorageModel(model, props, options) {
  const isHydrated = ref(false);
  const storageKey = computed(() => {
    if (!props.persist) return "";
    const key = props.persistKey?.trim();
    if (!key) return "";
    const prefix = (props.persistPrefix ?? "").trim();
    return prefix ? `${prefix}:${key}` : key;
  });
  const isEmpty = options?.isEmpty ?? isEmptyValue;
  const serializer = options?.serializer ?? ((v) => v);
  const deserializer = options?.deserializer ?? ((raw) => raw);
  function read() {
    if (!storageKey.value) return void 0;
    try {
      const opts = {
        decrypt: !!props.persistEncrypt
      };
      if (props.persistSecret !== void 0) opts.secret = props.persistSecret;
      return ls.get(storageKey.value, opts);
    } catch {
      return void 0;
    }
  }
  function write(val) {
    if (!storageKey.value) return;
    try {
      const opts = {
        ttl: props.persistTtl,
        // seconds
        encrypt: !!props.persistEncrypt
      };
      if (props.persistSecret !== void 0) opts.secret = props.persistSecret;
      ls.set(storageKey.value, serializer(val), opts);
    } catch {
    }
  }
  function remove() {
    if (!storageKey.value) return;
    try {
      ls.remove(storageKey.value);
    } catch {
    }
  }
  onMounted(() => {
    if (!props.persist) {
      isHydrated.value = true;
      return;
    }
    const stored = read();
    const shouldHydrate = props.persistAlwaysHydrate || isEmpty(model.value);
    if (stored !== void 0 && shouldHydrate) {
      try {
        model.value = deserializer(stored);
      } catch {
      }
    }
    isHydrated.value = true;
  });
  const persistNow = () => {
    if (!props.persist || !storageKey.value) return;
    const clearOnEmpty = props.persistClearOnEmpty ?? true;
    const val = model.value;
    if (clearOnEmpty && isEmpty(val)) remove();
    else write(val);
  };
  const persistDebounced = useDebounceFn(persistNow, () => props.persistDebounce ?? 200);
  watch(
    model,
    () => {
      persistDebounced();
    },
    { deep: true }
  );
  return {
    isHydrated,
    storageKey,
    remove,
    read,
    write
  };
}
