import _ from "lodash";
import { Node_Type } from "./../ricos-schema/legacy/wix/rich_content/v1/index.js";
import { logInvariant } from "./../_shared/log-invariant.js";
import { unreachable } from "./../_shared/uncreachable.js";
const parseChunk = (messages, chunk, doc) => {
  if (!("chunk" in chunk)) {
    logInvariant(new Error("Invalid chunk format"));
    return messages;
  }
  switch (chunk.chunk.type) {
    case "SUMMARY": {
      const lastMessage = messages[messages.length - 1];
      if (lastMessage && lastMessage.type === "text" && !lastMessage.completed) {
        return [
          ...messages.slice(0, -1),
          {
            ...lastMessage,
            text: lastMessage.text + `${chunk.chunk.summaryOptions.text}`
          }
        ];
      }
      return [
        ...messages,
        {
          type: "text",
          text: chunk.chunk.summaryOptions.text,
          completed: false,
          subtype: "summary"
        }
      ];
    }
    case "EXPLAIN": {
      const lastMessage = messages[messages.length - 1];
      if (lastMessage && lastMessage.type === "text" && !lastMessage.completed) {
        return [
          ...messages.slice(0, -1),
          {
            ...lastMessage,
            text: lastMessage.text + `${chunk.chunk.explainOptions.text}`
          }
        ];
      }
      return [
        ...messages,
        {
          type: "text",
          text: chunk.chunk.explainOptions.text,
          completed: false,
          subtype: "explain"
        }
      ];
    }
    case "ERROR": {
      const lastMessage = messages[messages.length - 1];
      if (lastMessage && lastMessage.type === "text" && !lastMessage.completed) {
        return [
          ...messages.slice(0, -1),
          {
            ...lastMessage,
            text: lastMessage.text + `${chunk.chunk.errorOptions.text}`
          }
        ];
      }
      return [
        ...messages,
        {
          type: "text",
          text: chunk.chunk.errorOptions.text,
          completed: false,
          subtype: "error"
        }
      ];
    }
    case "INSERT": {
      const after = chunk.chunk.insertOptions.after;
      return [
        ...messages,
        {
          type: "insert",
          nodes: [],
          after,
          completed: false,
          isRootLevel: !after || doc.nodes.some(
            (node) => node.id === after || node.type === Node_Type.CARD && node.nodes?.some((child) => child.id === after)
          ),
          viewBefore: false
        }
      ];
    }
    case "REPLACE": {
      const from = chunk.chunk.replaceOptions.from;
      const to = chunk.chunk.replaceOptions.to;
      return [
        ...messages,
        {
          type: "replace",
          nodes: [],
          from,
          to,
          completed: false,
          originalNodesRef: {},
          isRootLevel: doc.nodes.some(
            (node) => node.id === from || node.type === Node_Type.CARD && node.nodes?.some((child) => child.id === from)
          ),
          viewBefore: false
        }
      ];
    }
    case "NODE": {
      const messageWithExistingNode = findMessageWithNode(
        messages,
        chunk.chunk.nodeOptions.node.id
      );
      const messageWithParentNode = chunk.chunk.nodeOptions.parent ? findMessageWithNode(messages, chunk.chunk.nodeOptions.parent) : void 0;
      const lastActionableMessageIndex = messages.findLastIndex(
        (m) => m.type === "insert" || m.type === "replace"
      );
      const lastActionableMessage = {
        message: messages[lastActionableMessageIndex],
        messageIndex: lastActionableMessageIndex
      };
      const messageToUpdate = (() => {
        if (messageWithExistingNode) {
          return {
            message: messageWithExistingNode.message,
            messageIndex: messageWithExistingNode.index,
            existingNode: messageWithExistingNode.node,
            parentNode: messageWithParentNode?.node
          };
        }
        if (messageWithParentNode) {
          return {
            message: messageWithParentNode.message,
            messageIndex: messageWithParentNode.index,
            existingNode: void 0,
            parentNode: messageWithParentNode.node
          };
        }
        return lastActionableMessage;
      })();
      const node = chunk.chunk.nodeOptions.pending && ["HTML", "IMAGE"].includes(chunk.chunk.nodeOptions.node.type) ? {
        type: "EXTERNAL",
        id: chunk.chunk.nodeOptions.node.id,
        externalData: {
          ...chunk.chunk.nodeOptions.node
        }
      } : { ...chunk.chunk.nodeOptions.node };
      return messages.map((msg, idx) => {
        if (idx === messageToUpdate.messageIndex) {
          if (messageToUpdate.existingNode) {
            return updateMessageWithNode(messageToUpdate.message, node);
          }
          if (messageToUpdate.parentNode) {
            return updateMessageWithNode(messageToUpdate.message, {
              ...messageToUpdate.parentNode,
              nodes: [...messageToUpdate.parentNode.nodes ?? [], node]
            });
          }
          if (msg.type === "text") {
            logInvariant(new Error("Cannot add node to text message"));
            return msg;
          }
          if (msg.type === "theme") {
            logInvariant(new Error("Cannot add node to theme message"));
            return msg;
          }
          return {
            ...msg,
            nodes: [...msg.nodes ?? [], node]
          };
        }
        return msg;
      });
    }
    case "NODE_TEXT": {
      const { parent, text, decorations } = chunk.chunk.nodeTextOptions;
      const lastMessage = messages[messages.length - 1];
      if (!lastMessage || lastMessage.type === "text" || lastMessage.type === "theme") {
        logInvariant(new Error("No last message found before NODE chunk"));
        return messages;
      }
      const lastMessageNodes = structuredClone(lastMessage.nodes);
      const parentNode = findNode(lastMessageNodes, parent);
      if (!parentNode) {
        logInvariant(new Error(`Parent node with id ${parent} not found`));
        break;
      }
      const siblings = parentNode.nodes || [];
      const lastChild = siblings.length > 0 ? siblings[siblings.length - 1] : null;
      if (lastChild && lastChild.type === "TEXT" && _.isEqual(lastChild.textData.decorations, decorations)) {
        lastChild.textData = lastChild.textData || { text: "", decorations: [] };
        lastChild.textData.text += text;
      } else {
        const textNode = {
          type: "TEXT",
          textData: {
            text,
            decorations
          }
        };
        siblings.push(textNode);
      }
      return [
        ...messages.slice(0, -1),
        { ...lastMessage, nodes: lastMessageNodes, completed: false }
      ];
    }
    case "TOOL_USE": {
      return [
        ...messages,
        {
          type: "text",
          text: chunk.chunk.toolUseOptions.toolName,
          completed: true,
          subtype: "tool",
          toolParameters: chunk.chunk.toolUseOptions.parameters
        }
      ];
    }
    case "INSERT_END": {
      const lastMessage = messages[messages.length - 1];
      if (lastMessage && lastMessage.type === "insert") {
        return [...messages.slice(0, -1), { ...lastMessage, completed: true }];
      } else {
        logInvariant(new Error("No last insert message found before INSERT_END chunk"));
        return messages;
      }
    }
    case "REPLACE_END": {
      const lastMessage = messages[messages.length - 1];
      if (lastMessage && lastMessage.type === "replace") {
        return [...messages.slice(0, -1), { ...lastMessage, completed: true }];
      } else {
        logInvariant(new Error("No last replace message found before REPLACE_END chunk"));
        return messages;
      }
    }
    case "THEME": {
      return [
        {
          type: "theme",
          theme: chunk.chunk.themeOptions.theme
        },
        ...messages
      ];
    }
    case "UPDATE_DOCUMENT":
    case "UPDATE_DOCUMENT_END": {
      return messages;
    }
    case "METADATA": {
      return messages;
    }
    case "PATCH": {
      return parseChunk(
        messages,
        { chunk: { type: "NODE", nodeOptions: { node: chunk.chunk.patchOptions.node } } },
        doc
      );
    }
    default: {
      logInvariant(unreachable(chunk.chunk));
      return messages;
    }
  }
  return messages;
};
const findMessageWithNode = (messages, nodeId) => {
  for (let i = messages.length - 1; i >= 0; i--) {
    const message = messages[i];
    if (message.type === "insert" || message.type === "replace") {
      const node = findNode(message.nodes, nodeId);
      if (node) {
        return { index: i, message, node };
      }
    }
  }
  return void 0;
};
const updateMessageWithNode = (message, updatedNode) => {
  const updatedNodes = updateNodeTreeWithNode(message.nodes, updatedNode);
  return { ...message, nodes: updatedNodes };
};
const updateNodeTreeWithNode = (nodes, updatedNode) => {
  return nodes.map((node) => {
    if (node.id === updatedNode.id) {
      return {
        ...updatedNode,
        nodes: updatedNode.nodes?.length ? updatedNode.nodes : node.nodes
      };
    }
    if (node.nodes) {
      return {
        ...node,
        nodes: updateNodeTreeWithNode(node.nodes, updatedNode)
      };
    }
    return node;
  });
};
const findNode = (nodes, id) => {
  for (const node of nodes) {
    if (node.id === id) {
      return node;
    }
    if (node.nodes) {
      const found = findNode(node.nodes, id);
      if (found) {
        return found;
      }
    }
  }
};
export {
  parseChunk
};
//# sourceMappingURL=convert-to-ai-messages.js.map
