/**
 * @fileoverview Factory para serviços de persistência no `localStorage`.
 *
 * Elimina a duplicação entre `blockstorage` e `codestorage` centralizando o
 * padrão: `safeLocalGet(validator)` + `debounce(save)`.
 *
 * @module services.createStorageService
 */

import debounce from "lodash.debounce";
import { safeLocalGet } from "../utils/localStorage";

/**
 * @typedef {Object} StorageService
 * @property {(key: string) => T | null} load            - Carrega e valida valor do localStorage
 * @property {(key: string, value: T) => void} save      - Persiste valor ou remove chave se inválido
 * @property {(delay?: number) => Function} createDebouncedSave - Retorna função de save com debounce
 * @property {(key: string) => void} clear               - Remove a chave do localStorage
 * @template T
 */

/**
 * Cria um serviço de armazenamento parametrizado por validador.
 *
 * @template T
 * @param {object} options
 * @param {(value: unknown) => boolean} options.validator
 *   Função que valida o valor lido do localStorage antes de o devolver.
 * @param {(value: T) => boolean} [options.isEmpty]
 *   Predicado que determina se um valor válido deve ser tratado como "vazio"
 *   e portanto removido em vez de salvo. Por padrão nenhum valor é considerado vazio.
 * @returns {StorageService<T>}
 *
 * @example
 * // Serviço para strings de código (remove se vazio)
 * const codeService = createStorageService({
 *   validator: (v) => typeof v === "string",
 *   isEmpty: (v) => v.trim() === "",
 * });
 *
 * @example
 * // Serviço para objectos workspace Blockly
 * const workspaceService = createStorageService({
 *   validator: (v) => v != null && Array.isArray(v?.blocks?.blocks),
 * });
 */
export function createStorageService({ validator, isEmpty = () => false }) {
  function load(key) {
    return safeLocalGet(key, validator);
  }

  function save(key, value) {
    if (!validator(value) || isEmpty(value)) {
      localStorage.removeItem(key);
      return;
    }
    localStorage.setItem(key, JSON.stringify(value));
  }

  function createDebouncedSave(delay = 1000) {
    return debounce(save, delay, { leading: false, trailing: true });
  }

  function clear(key) {
    localStorage.removeItem(key);
  }

  return { load, save, createDebouncedSave, clear };
}
