'use strict';

const index = require('../../../../../../node_modules/.pnpm/zustand@4.5.5_@types_react@19.2.6_immer@11.1.3_react@19.2.0/node_modules/zustand/esm/index.cjs');
const middleware = require('../../../../../../node_modules/.pnpm/zustand@4.5.5_@types_react@19.2.6_immer@11.1.3_react@19.2.0/node_modules/zustand/esm/middleware.cjs');
const immer = require('../../../../../../node_modules/.pnpm/immer@11.1.3/node_modules/immer/dist/immer.cjs');
const index$1 = require('../../../../../../node_modules/.pnpm/zundo@2.3.0_zustand@4.5.5_@types_react@19.2.6_immer@11.1.3_react@19.2.0_/node_modules/zundo/dist/index.cjs');
const index$2 = require('../../../../../../_virtual/index.cjs');
const layerUtils = require('./layer-utils.cjs');
const schemaUtils = require('./schema-utils.cjs');
const editorStore = require('./editor-store.cjs');
const types = require('../../../components/ui-builder/types.cjs');

const DEFAULT_PAGE_PROPS = {
  className: "h-screen p-4 flex flex-col gap-2 bg-background overflow-y-scroll"
};
const store = (set, get) => ({
  // Default to a single empty page
  pages: [
    {
      id: "1",
      type: "div",
      name: "Page 1",
      props: DEFAULT_PAGE_PROPS,
      children: []
    }
  ],
  // Variables available for binding
  variables: [],
  // Track immutable bindings: layerId -> propName -> isImmutable
  immutableBindings: {},
  selectedLayerId: null,
  selectedPageId: "1",
  initialize: (pages, selectedPageId, selectedLayerId, variables) => {
    set(immer.produce((state) => {
      state.pages = pages;
      state.selectedPageId = selectedPageId || (pages.length > 0 && pages[0] ? pages[0].id : "");
      state.selectedLayerId = selectedLayerId || null;
      state.variables = variables || [];
      const { registry } = editorStore.useEditorStore.getState();
      const setupImmutableBindings = (layer) => {
        const componentDef = registry[layer.type];
        const defaultVariableBindings = componentDef?.defaultVariableBindings || [];
        for (const binding of defaultVariableBindings) {
          const propValue = layer.props[binding.propName];
          if (types.isVariableReference(propValue) && propValue.__variableRef === binding.variableId) {
            if (binding.immutable) {
              if (!state.immutableBindings[layer.id]) {
                state.immutableBindings[layer.id] = {};
              }
              const bindings = state.immutableBindings[layer.id];
              if (bindings) {
                bindings[binding.propName] = true;
              }
            }
          }
        }
        return layer;
      };
      state.pages = state.pages.map(
        (page) => layerUtils.visitLayer(page, null, setupImmutableBindings)
      );
    }));
  },
  findLayerById: (layerId) => {
    const { selectedPageId, findLayersForPageId, pages } = get();
    if (!layerId) return void 0;
    if (layerId === selectedPageId) {
      return pages.find((page) => page.id === selectedPageId);
    }
    const layers = findLayersForPageId(selectedPageId);
    if (!layers) return void 0;
    return layerUtils.findLayerRecursive(layers, layerId);
  },
  findLayersForPageId: (pageId) => {
    const { pages } = get();
    const page = pages.find((page2) => page2.id === pageId);
    if (page && layerUtils.hasLayerChildren(page)) {
      return page?.children || [];
    }
    return [];
  },
  isLayerAPage: (layerId) => {
    const { pages } = get();
    return pages.some((page) => page.id === layerId);
  },
  addComponentLayer: (layerType, parentId, parentPosition) => set(immer.produce((state) => {
    const { registry } = editorStore.useEditorStore.getState();
    const newLayer = layerUtils.createComponentLayer(layerType, registry, {
      applyVariableBindings: true,
      variables: state.variables
    });
    const registryEntry = registry[layerType];
    const defaultVariableBindings = registryEntry?.defaultVariableBindings || [];
    for (const binding of defaultVariableBindings) {
      const variable = state.variables.find((v) => v.id === binding.variableId);
      if (variable && binding.immutable) {
        if (!state.immutableBindings[newLayer.id]) {
          state.immutableBindings[newLayer.id] = {};
        }
        const bindings = state.immutableBindings[newLayer.id];
        if (bindings) {
          bindings[binding.propName] = true;
        }
      }
    }
    const updatedPages = layerUtils.addLayer(state.pages, newLayer, parentId, parentPosition);
    state.pages = updatedPages;
    state.selectedLayerId = newLayer.id;
  })),
  addLayerDirect: (layer, parentId, parentPosition) => set(immer.produce((state) => {
    const updatedPages = layerUtils.addLayer(state.pages, layer, parentId, parentPosition);
    state.pages = updatedPages;
    state.selectedLayerId = layer.id;
  })),
  addPageLayer: (pageName) => set(immer.produce((state) => {
    const newPage = {
      id: layerUtils.createId(),
      type: "div",
      name: pageName,
      props: DEFAULT_PAGE_PROPS,
      children: []
    };
    return {
      pages: [...state.pages, newPage],
      selectedPageId: newPage.id,
      selectedLayerId: newPage.id
    };
  })),
  duplicateLayer: (layerId) => set(immer.produce((state) => {
    let layerToDuplicate;
    let parentId;
    let parentPosition;
    state.pages.forEach(
      (page) => layerUtils.visitLayer(page, null, (layer, parent) => {
        if (layer.id === layerId) {
          layerToDuplicate = layer;
          parentId = parent?.id;
          if (parent && layerUtils.hasLayerChildren(parent)) {
            parentPosition = parent.children.indexOf(layer) + 1;
          }
        }
        return layer;
      })
    );
    if (!layerToDuplicate) {
      console.warn(`Layer with ID ${layerId} not found.`);
      return;
    }
    const isNewLayerAPage = state.pages.some((page) => page.id === layerId);
    const newLayer = layerUtils.duplicateWithNewIdsAndName(layerToDuplicate, true);
    if (isNewLayerAPage) {
      return {
        ...state,
        pages: [...state.pages, newLayer],
        selectedPageId: newLayer.id
      };
    }
    const updatedPages = layerUtils.addLayer(state.pages, newLayer, parentId, parentPosition);
    return {
      ...state,
      pages: updatedPages
    };
  })),
  removeLayer: (layerId) => set(immer.produce((state) => {
    const { selectedLayerId, pages } = get();
    let newSelectedLayerId = selectedLayerId;
    const isPage = state.pages.some((page) => page.id === layerId);
    if (isPage && pages.length > 1) {
      const newPages = state.pages.filter((page) => page.id !== layerId);
      const firstPage = newPages[0];
      return {
        ...state,
        pages: newPages,
        selectedPageId: firstPage ? firstPage.id : ""
      };
    }
    const updatedPages = pages.map(
      (page) => layerUtils.visitLayer(page, null, (layer) => {
        if (layerUtils.hasLayerChildren(layer)) {
          const updatedChildren = layer.children.filter((child) => child.id !== layerId);
          return { ...layer, children: updatedChildren };
        }
        return layer;
      })
    );
    if (selectedLayerId === layerId) {
      newSelectedLayerId = null;
    }
    return {
      ...state,
      selectedLayerId: newSelectedLayerId,
      pages: updatedPages
    };
  })),
  updateLayer: (layerId, newProps, layerRest) => set(
    immer.produce((state) => {
      const { selectedPageId, findLayersForPageId, pages } = get();
      const pageExists = pages.some((page) => page.id === selectedPageId);
      if (!pageExists) {
        console.warn(`No layers found for page ID: ${selectedPageId}`);
        return state;
      }
      if (layerId === selectedPageId) {
        const updatedPages2 = pages.map(
          (page) => page.id === selectedPageId ? { ...page, props: { ...page.props, ...newProps }, ...layerRest || {} } : page
        );
        return { ...state, pages: updatedPages2 };
      }
      const layers = findLayersForPageId(selectedPageId);
      const visitor = (layer) => {
        if (layer.id === layerId) {
          return {
            ...layer,
            ...layerRest || {},
            props: { ...layer.props, ...newProps }
          };
        }
        return layer;
      };
      const updatedLayers = layers.map((layer) => layerUtils.visitLayer(layer, null, visitor));
      const isUnchanged = updatedLayers.every((layer, index) => layer === layers[index]);
      if (isUnchanged) {
        console.warn(`Layer with ID ${layerId} was not found.`);
        return state;
      }
      const updatedPages = state.pages.map(
        (page) => page.id === selectedPageId ? { ...page, children: updatedLayers } : page
      );
      return { ...state, pages: updatedPages };
    })
  ),
  selectLayer: (layerId) => set(immer.produce((state) => {
    const { selectedPageId, findLayersForPageId } = get();
    const layers = findLayersForPageId(selectedPageId);
    if (selectedPageId === layerId) {
      return {
        selectedLayerId: layerId
      };
    }
    if (!layers) return state;
    const layer = layerUtils.findLayerRecursive(layers, layerId);
    if (layer) {
      return {
        selectedLayerId: layer.id
      };
    }
    return {};
  })),
  selectPage: (pageId) => set(immer.produce((state) => {
    const page = state.pages.find((page2) => page2.id === pageId);
    if (!page) return state;
    return {
      selectedPageId: pageId
    };
  })),
  // Add a new variable
  addVariable: (name, type, defaultValue) => set(immer.produce((state) => {
    state.variables.push({ id: layerUtils.createId(), name, type, defaultValue });
  })),
  // Update an existing variable
  updateVariable: (variableId, updates) => set(immer.produce((state) => {
    const v = state.variables.find((v2) => v2.id === variableId);
    if (v) Object.assign(v, updates);
  })),
  // Remove a variable
  removeVariable: (variableId) => set(immer.produce((state) => {
    state.variables = state.variables.filter((v) => v.id !== variableId);
    const { registry } = editorStore.useEditorStore.getState();
    const cleanVariableReferences = (layer) => {
      const updatedProps = { ...layer.props };
      let hasChanges = false;
      let updatedChildren = layer.children;
      Object.entries(updatedProps).forEach(([propName, propValue]) => {
        if (types.isVariableReference(propValue) && propValue.__variableRef === variableId) {
          const layerSchema = registry[layer.type]?.schema;
          if (layerSchema && "shape" in layerSchema && layerSchema.shape && layerSchema.shape[propName]) {
            const defaultProps = schemaUtils.getDefaultProps(layerSchema);
            updatedProps[propName] = defaultProps[propName];
            hasChanges = true;
          } else {
            delete updatedProps[propName];
            hasChanges = true;
          }
        }
      });
      if (types.isVariableReference(layer.children) && layer.children.__variableRef === variableId) {
        updatedChildren = "";
        hasChanges = true;
      }
      if (hasChanges) {
        return { ...layer, props: updatedProps, children: updatedChildren };
      }
      return layer;
    };
    state.pages = state.pages.map(
      (page) => layerUtils.visitLayer(page, null, cleanVariableReferences)
    );
  })),
  // Bind a component prop to a variable reference
  bindPropToVariable: (layerId, propName, variableId) => {
    get().updateLayer(layerId, { [propName]: { __variableRef: variableId } });
  },
  // Unbind a component prop from a variable reference and set default value from schema
  unbindPropFromVariable: (layerId, propName) => {
    if (get().isBindingImmutable(layerId, propName)) {
      console.warn(`Cannot unbind immutable variable binding for ${propName} on layer ${layerId}`);
      return;
    }
    const { registry } = editorStore.useEditorStore.getState();
    const layer = get().findLayerById(layerId);
    if (!layer) {
      console.warn(`Layer with ID ${layerId} not found.`);
      return;
    }
    const layerSchema = registry[layer.type]?.schema;
    let defaultValue = void 0;
    if (layerSchema && "shape" in layerSchema && layerSchema.shape && layerSchema.shape[propName]) {
      const defaultProps = schemaUtils.getDefaultProps(layerSchema);
      defaultValue = defaultProps[propName];
    }
    if (defaultValue === void 0) {
      defaultValue = "";
    }
    get().updateLayer(layerId, { [propName]: defaultValue });
  },
  // Bind layer children to a variable reference
  bindChildrenToVariable: (layerId, variableId) => {
    get().updateLayer(layerId, {}, { children: { __variableRef: variableId } });
  },
  // Unbind layer children from a variable reference and reset to empty string
  unbindChildrenFromVariable: (layerId) => {
    if (get().isChildrenBindingImmutable(layerId)) {
      console.warn(`Cannot unbind immutable children variable binding on layer ${layerId}`);
      return;
    }
    const layer = get().findLayerById(layerId);
    if (!layer) {
      console.warn(`Layer with ID ${layerId} not found.`);
      return;
    }
    get().updateLayer(layerId, {}, { children: "" });
  },
  // Check if a binding is immutable
  isBindingImmutable: (layerId, propName) => {
    const { immutableBindings } = get();
    return immutableBindings[layerId]?.[propName] === true;
  },
  // Check if children binding is immutable (uses special key '__children__')
  isChildrenBindingImmutable: (layerId) => {
    const { immutableBindings } = get();
    return immutableBindings[layerId]?.["__children__"] === true;
  },
  // Test helper
  setImmutableBinding: (layerId, propName, isImmutable) => {
    set(immer.produce((state) => {
      if (!state.immutableBindings[layerId]) {
        state.immutableBindings[layerId] = {};
      }
      const bindings = state.immutableBindings[layerId];
      if (bindings) {
        bindings[propName] = isImmutable;
      }
    }));
  },
  moveLayer: (sourceLayerId, targetParentId, targetPosition) => {
    set(immer.produce((state) => {
      const updatedPages = layerUtils.moveLayer(state.pages, sourceLayerId, targetParentId, targetPosition);
      state.pages = updatedPages;
    }));
  }
});
const conditionalLocalStorage = {
  getItem: (name) => {
    const { persistLayerStoreConfig } = editorStore.useEditorStore.getState();
    if (!persistLayerStoreConfig) {
      return Promise.resolve(null);
    }
    const value = localStorage.getItem(name);
    return Promise.resolve(value);
  },
  setItem: (name, value) => {
    const { persistLayerStoreConfig } = editorStore.useEditorStore.getState();
    if (!persistLayerStoreConfig) {
      return Promise.resolve();
    }
    localStorage.setItem(name, value);
    return Promise.resolve();
  },
  removeItem: (name) => {
    const { persistLayerStoreConfig } = editorStore.useEditorStore.getState();
    if (!persistLayerStoreConfig) {
      return Promise.resolve();
    }
    localStorage.removeItem(name);
    return Promise.resolve();
  }
};
const useLayerStore = index.create(middleware.persist(index$1.temporal(
  store,
  {
    equality: (pastState, currentState) => index$2(pastState, currentState)
  }
), {
  name: "layer-store",
  version: 6,
  storage: middleware.createJSONStorage(() => conditionalLocalStorage),
  migrate: (persistedState, version) => {
    let state = persistedState;
    if (version < 2) {
      state = layerUtils.migrateV1ToV2(state);
    }
    if (version < 3) {
      state = layerUtils.migrateV2ToV3(state);
    }
    if (version < 4) {
      state = { ...state, variables: [], immutableBindings: {} };
    }
    if (version < 5) {
      state = { ...state, immutableBindings: {} };
    }
    if (version < 6) {
      state = layerUtils.migrateV5ToV6(state);
    }
    return state;
  }
}));

exports.countLayers = layerUtils.countLayers;
exports.findAllParentLayersRecursive = layerUtils.findAllParentLayersRecursive;
exports.useLayerStore = useLayerStore;
