import { getDefaultProps } from './schema-utils.mjs';
import { TAILWIND_V4_COLOR_KEYS } from '../../../components/ui-builder/internal/utils/base-colors.mjs';

const visitLayer = (layer, parentLayer, visitor) => {
  const updatedLayer = visitor(layer, parentLayer);
  if (hasLayerChildren(updatedLayer)) {
    const updatedChildren = updatedLayer.children.map(
      (child) => visitLayer(child, updatedLayer, visitor)
    );
    return { ...updatedLayer, children: updatedChildren };
  }
  return updatedLayer;
};
const countLayers = (layers) => {
  if (typeof layers === "string" || !Array.isArray(layers)) {
    return 0;
  }
  return layers.reduce((count, layer) => {
    if (hasLayerChildren(layer)) {
      return count + 1 + countLayers(layer.children);
    }
    return count + 1;
  }, 0);
};
const addLayer = (layers, newLayer, parentId, parentPosition) => {
  const updatedPages = layers.map(
    (page) => visitLayer(page, null, (layer) => {
      if (layer.id === parentId) {
        let updatedChildren = [];
        if (hasLayerChildren(layer)) {
          updatedChildren = [...layer.children];
        } else if (layer.children === void 0 || layer.children === null || Array.isArray(layer.children) && layer.children.length === 0) {
          updatedChildren = [];
        } else {
          return layer;
        }
        if (parentPosition !== void 0) {
          if (parentPosition < 0) {
            updatedChildren = [newLayer, ...updatedChildren];
          } else if (parentPosition >= updatedChildren.length) {
            updatedChildren = [...updatedChildren, newLayer];
          } else {
            updatedChildren = [
              ...updatedChildren.slice(0, parentPosition),
              newLayer,
              ...updatedChildren.slice(parentPosition)
            ];
          }
        } else {
          updatedChildren = [...updatedChildren, newLayer];
        }
        return { ...layer, children: updatedChildren };
      }
      return layer;
    })
  );
  return updatedPages;
};
const findAllParentLayersRecursive = (layers, layerId) => {
  const parents = [];
  const findParents = (layers2, targetId) => {
    for (const layer of layers2) {
      if (hasLayerChildren(layer)) {
        if (layer.children.some((child) => child.id === targetId)) {
          parents.push(layer);
          findParents(layers2, layer.id);
          return true;
        }
        if (findParents(layer.children, targetId)) {
          parents.push(layer);
          return true;
        }
      }
    }
    return false;
  };
  findParents(layers, layerId);
  return parents;
};
const findLayerRecursive = (layers, layerId) => {
  for (const layer of layers) {
    if (layer.id === layerId) {
      return layer;
    }
    if (hasLayerChildren(layer)) {
      const foundInChildren = findLayerRecursive(layer.children, layerId);
      if (foundInChildren) {
        return foundInChildren;
      }
    }
  }
  return void 0;
};
const duplicateWithNewIdsAndName = (layer, addCopySuffix = true) => {
  const newLayer = { ...layer, id: createId() };
  if (layer.name) {
    newLayer.name = `${layer.name}${addCopySuffix ? " (Copy)" : ""}`;
  }
  if (hasLayerChildren(newLayer) && hasLayerChildren(layer)) {
    newLayer.children = layer.children.map((child) => duplicateWithNewIdsAndName(child, false));
  }
  return newLayer;
};
function createId() {
  const ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  const ID_LENGTH = 7;
  let result = "";
  const alphabetLength = ALPHABET.length;
  for (let i = 0; i < ID_LENGTH; i++) {
    const randomIndex = Math.floor(Math.random() * alphabetLength);
    result += ALPHABET.charAt(randomIndex);
  }
  return result;
}
const hasLayerChildren = (layer) => {
  return Array.isArray(layer.children) && typeof layer.children !== "string";
};
function migrateV1ToV2(persistedState) {
  console.log("Migrating store", { persistedState, version: 1 });
  const migratedState = persistedState;
  const transformLayer = (layer) => {
    if (layer.type === "_text_") {
      const textLayer = layer;
      const transformedTextLayer = {
        type: textLayer.textType === "markdown" ? "Markdown" : "span",
        children: textLayer.text,
        id: textLayer.id,
        name: textLayer.name,
        props: textLayer.props
      };
      console.log("Transformed text layer", transformedTextLayer);
      return transformedTextLayer;
    }
    return layer;
  };
  const migratedPages = migratedState.pages.map((page) => {
    return visitLayer(page, null, transformLayer);
  });
  return {
    ...migratedState,
    pages: migratedPages
  };
}
function migrateV2ToV3(persistedState) {
  console.log("Migrating store", { persistedState, version: 1 });
  const migratedState = persistedState;
  const keysToMap = {
    borderRadius: "data-border-radius",
    colorTheme: "data-color-theme",
    mode: "data-mode"
  };
  const migratedPages = migratedState.pages.map((page) => {
    if (page.type === "_page_") {
      const pageLayer = page;
      const transformedPageLayer = {
        type: "div",
        children: pageLayer.children,
        id: pageLayer.id,
        name: pageLayer.name,
        //map keys called borderRadius, colorTheme, mode to data-border-radius, data-color-theme, data-mode
        props: Object.fromEntries(Object.entries(pageLayer.props).map(([key, value]) => {
          if (keysToMap[key]) {
            return [keysToMap[key], value];
          }
          return [key, value];
        }))
      };
      console.log("Transformed page layer", transformedPageLayer);
      return transformedPageLayer;
    }
    return page;
  });
  return {
    ...migratedState,
    pages: migratedPages
  };
}
function convertStyleToTailwindV4(oldStyle) {
  const newStyle = { ...oldStyle };
  TAILWIND_V4_COLOR_KEYS.forEach((key) => {
    const baseVar = `--${key}`;
    if (oldStyle[baseVar] && !oldStyle[`--color-${key}`]) {
      newStyle[`--color-${key}`] = `hsl(${oldStyle[baseVar]})`;
    }
  });
  const radiusValue = oldStyle["--radius"];
  if (radiusValue && !oldStyle["--radius-lg"]) {
    newStyle["--radius-lg"] = radiusValue;
    newStyle["--radius-md"] = `calc(${radiusValue} - 2px)`;
    newStyle["--radius-sm"] = `calc(${radiusValue} - 4px)`;
  }
  if (oldStyle["--background"] && !oldStyle["backgroundColor"]) {
    newStyle["backgroundColor"] = `hsl(${oldStyle["--background"]})`;
  }
  return newStyle;
}
function migrateV5ToV6(persistedState) {
  console.log("Migrating store", { persistedState, version: 5 });
  const migratedState = persistedState;
  const migratedPages = migratedState.pages.map((page) => {
    if (page.type === "div" && page.props) {
      const hasStyle = "style" in page.props && page.props.style != null;
      const hasCustomTheme = "data-color-theme" in page.props && page.props["data-color-theme"] != null;
      if (hasStyle && hasCustomTheme) {
        console.log("Converting style to Tailwind v4 format", {
          pageId: page.id,
          pageName: page.name,
          colorTheme: page.props["data-color-theme"]
        });
        const oldStyle = page.props.style;
        const newStyle = convertStyleToTailwindV4(oldStyle);
        return {
          ...page,
          props: {
            ...page.props,
            style: newStyle
          }
        };
      }
      if (hasStyle && !hasCustomTheme) {
        console.log("Removing old-format style from page (no custom theme)", { pageId: page.id, pageName: page.name });
        const { style: _removedStyle, ...restProps } = page.props;
        return {
          ...page,
          props: restProps
        };
      }
    }
    return page;
  });
  return {
    ...migratedState,
    pages: migratedPages
  };
}
const createComponentLayer = (layerType, componentRegistry, options = {}) => {
  const { id, name, applyVariableBindings = false, variables = [] } = options;
  const componentDef = componentRegistry[layerType];
  if (!componentDef) {
    throw new Error(`Component definition not found for type: ${layerType}`);
  }
  const schema = componentDef.schema;
  const defaultProps = "shape" in schema && schema.shape ? getDefaultProps(schema) : {};
  const defaultChildrenRaw = componentDef.defaultChildren;
  const defaultChildren = typeof defaultChildrenRaw === "string" ? defaultChildrenRaw : Array.isArray(defaultChildrenRaw) ? defaultChildrenRaw.map((child) => duplicateWithNewIdsAndName(child, false)) : defaultChildrenRaw ?? [];
  const initialProps = Object.entries(defaultProps).reduce((acc, [key, propDef]) => {
    if (key !== "children") {
      acc[key] = propDef;
    }
    return acc;
  }, {});
  const newLayer = {
    id: id || createId(),
    type: layerType,
    name: name || layerType,
    props: initialProps,
    children: defaultChildren
  };
  if (applyVariableBindings) {
    const defaultVariableBindings = componentDef.defaultVariableBindings || [];
    for (const binding of defaultVariableBindings) {
      const variable = variables.find((v) => v.id === binding.variableId);
      if (variable) {
        newLayer.props[binding.propName] = { __variableRef: binding.variableId };
      }
    }
  }
  return newLayer;
};
const moveLayer = (layers, sourceLayerId, targetParentId, targetPosition) => {
  let layerToMove = null;
  const findLayerAndParent = (layers2, parentId = null) => {
    for (let i = 0; i < layers2.length; i++) {
      const layer = layers2[i];
      if (!layer) continue;
      if (layer.id === sourceLayerId) {
        layerToMove = layer;
        return true;
      }
      if (hasLayerChildren(layer) && layer.children) {
        if (findLayerAndParent(layer.children, layer.id)) {
          return true;
        }
      }
    }
    return false;
  };
  findLayerAndParent(layers);
  if (!layerToMove) {
    console.warn(`Source layer with ID ${sourceLayerId} not found`);
    return layers;
  }
  const layersWithoutSource = layers.map(
    (page) => visitLayer(page, null, (layer) => {
      if (hasLayerChildren(layer)) {
        const updatedChildren = layer.children.filter((child) => child.id !== sourceLayerId);
        return { ...layer, children: updatedChildren };
      }
      return layer;
    })
  );
  const updatedLayers = addLayer(layersWithoutSource, layerToMove, targetParentId, targetPosition);
  return updatedLayers;
};
const canLayerAcceptChildren = (layer, componentRegistry) => {
  const componentDef = componentRegistry[layer.type];
  if (!componentDef) return false;
  const hasChildrenField = "shape" in componentDef.schema && componentDef.schema.shape && componentDef.schema.shape.children !== void 0;
  return hasChildrenField && hasLayerChildren(layer);
};

export { addLayer, canLayerAcceptChildren, countLayers, createComponentLayer, createId, duplicateWithNewIdsAndName, findAllParentLayersRecursive, findLayerRecursive, hasLayerChildren, migrateV1ToV2, migrateV2ToV3, migrateV5ToV6, moveLayer, visitLayer };
