import { Node as YogaNode } from "../core/yoga.jsx";
import { createRenderer } from "./index.jsx";

/** Screen-space rectangle cached during paint for hit-testing. */

function createTermNode(type) {
  const yogaNode = type === "_text" || type === "_slot" ? null : new YogaNode();
  return {
    type,
    props: {},
    children: [],
    parent: null,
    yogaNode,
    screenRect: null,
    scrollTop: 0,
    dirty: true,
    _cachedText: null
  };
}
function markDirty(node) {
  node.dirty = true;
  node._cachedText = null;
  let current = node.parent;
  while (current && !current.dirty) {
    current.dirty = true;
    current._cachedText = null;
    current = current.parent;
  }
}
export const {
  render,
  effect,
  memo,
  createComponent,
  createElement,
  createTextNode,
  insert,
  insertNode,
  spread,
  setProp,
  mergeProps,
  ref
} = createRenderer({
  createElement(type) {
    return createTermNode(type);
  },
  createTextNode(value) {
    const node = createTermNode("_text");
    node.props.content = value;
    return node;
  },
  createSlotNode() {
    return createTermNode("_slot");
  },
  isTextNode(node) {
    return node.type === "_text";
  },
  replaceText(node, value) {
    node.props.content = value;
    // Walk up to the nearest ancestor with a measure function and mark its
    // yoga node dirty so layout re-measures the text height. Without this,
    // yoga caches the old measurement and content-driven scrolling breaks.
    let ancestor = node.parent;
    while (ancestor) {
      if (ancestor.yogaNode?.measureFunc) {
        ancestor.yogaNode.markDirty();
        break;
      }
      ancestor = ancestor.parent;
    }
    markDirty(node);
  },
  setProperty(node, key, value) {
    node.props[key] = value;
    // Mark yoga dirty so measure functions re-run (e.g. input value changes height)
    if (node.yogaNode?.measureFunc) {
      node.yogaNode.markDirty();
    }
    markDirty(node);
  },
  insertNode(parent, node, anchor) {
    if (anchor) {
      const idx = parent.children.indexOf(anchor);
      parent.children.splice(idx, 0, node);
    } else {
      parent.children.push(node);
    }
    node.parent = parent;

    // Attach yoga child if both have yoga nodes
    if (parent.yogaNode && node.yogaNode) {
      let yogaIndex = 0;
      for (const c of parent.children) {
        if (c === node) break;
        if (c.yogaNode) yogaIndex++;
      }
      parent.yogaNode.insertChild(node.yogaNode, yogaIndex);
    }
    markDirty(parent);
  },
  removeNode(parent, node) {
    const idx = parent.children.indexOf(node);
    if (idx >= 0) parent.children.splice(idx, 1);
    if (parent.yogaNode && node.yogaNode) {
      parent.yogaNode.removeChild(node.yogaNode);
    }
    node.parent = null;
    markDirty(parent);
  },
  getParentNode(node) {
    return node.parent ?? undefined;
  },
  getFirstChild(node) {
    return node.children[0];
  },
  getNextSibling(node) {
    if (!node.parent) return undefined;
    const idx = node.parent.children.indexOf(node);
    return node.parent.children[idx + 1];
  }
});
//# sourceMappingURL=term-node.jsx.map
