// Copyright 2024 The Lynx Authors. All rights reserved.
// Licensed under the Apache License Version 2.0 that can be found in the
// LICENSE file in the root directory of this source tree.
import { hydrate } from './hydrate.js';
import { componentAtIndexFactory, enqueueComponentFactory, gRecycleMap, gSignMap } from '../list/list.js';
import { CHILDREN } from './constants.js';
import { SnapshotInstance } from '../snapshot/snapshot.js';
const OpcodeBegin = 0;
const OpcodeEnd = 1;
const OpcodeAttr = 2;
const OpcodeText = 3;
export function ssrHydrateByOpcodes(opcodes, into, refMap) {
    let top = into;
    const stack = [into];
    for (let i = 0; i < opcodes.length;) {
        const opcode = opcodes[i];
        switch (opcode) {
            case OpcodeBegin: {
                const p = top;
                const [type, __id, elements] = opcodes[i + 1];
                top = new SnapshotInstance(type, __id);
                top.__pendingElements = elements;
                top.__slotIndex = opcodes[i + 2];
                p.insertBefore(top);
                stack.push(top);
                i += 3;
                break;
            }
            case OpcodeEnd: {
                // @ts-ignore
                top[CHILDREN] = undefined;
                top.__elements = top.__pendingElements.map(({ ssrID }) => refMap[ssrID]);
                top.__element_root = top.__elements[0];
                delete top.__pendingElements;
                if (top.__snapshot_def.isListHolder) {
                    const listElement = top.__element_root;
                    const listElementUniqueID = __GetElementUniqueID(listElement);
                    const signMap = gSignMap[listElementUniqueID] = new Map();
                    gRecycleMap[listElementUniqueID] = new Map();
                    const enqueueFunc = enqueueComponentFactory();
                    const [componentAtIndex, componentAtIndexes] = componentAtIndexFactory(top.childNodes, hydrate);
                    for (const child of top.childNodes) {
                        if (child.__element_root) {
                            const childElementUniqueID = __GetElementUniqueID(child.__element_root);
                            signMap.set(childElementUniqueID, child);
                            enqueueFunc(listElement, listElementUniqueID, childElementUniqueID);
                        }
                    }
                    __UpdateListCallbacks(listElement, componentAtIndex, enqueueFunc, componentAtIndexes);
                }
                stack.pop();
                const p = stack[stack.length - 1];
                top = p;
                i += 1;
                break;
            }
            case OpcodeAttr: {
                const key = opcodes[i + 1];
                const value = opcodes[i + 2];
                top.setAttribute(key, value);
                i += 3;
                break;
            }
            case OpcodeText: {
                const [[type, __id, elements], text] = opcodes[i + 1];
                const s = new SnapshotInstance(type, __id);
                s.__slotIndex = opcodes[i + 2];
                s.setAttribute(0, text);
                top.insertBefore(s);
                s.__elements = elements.map(({ ssrID }) => refMap[ssrID]);
                s.__element_root = s.__elements[0];
                i += 3;
                break;
            }
        }
    }
}
// export function renderOpcodesInto(opcodes: any[], into: SnapshotInstance): void {
//   let top: SnapshotInstance = into;
//   const stack: SnapshotInstance[] = [into];
//   for (let i = 0; i < opcodes.length;) {
//     const opcode = opcodes[i];
//     switch (opcode) {
//       case OpcodeBegin: {
//         const p = top;
//         top = opcodes[i + 1];
//         // @ts-ignore
//         if (top.__parent) {
//           // already inserted
//           top = new SnapshotInstance(top.type);
//           opcodes[i + 1] = top;
//         }
//         p.insertBefore(top);
//         stack.push(top);
//         i += 2;
//         break;
//       }
//       case OpcodeEnd: {
//         // @ts-ignore
//         top[CHILDREN] = undefined;
//         stack.pop();
//         const p = stack[stack.length - 1];
//         top = p!;
//         i += 1;
//         break;
//       }
//       case OpcodeAttr: {
//         const key = opcodes[i + 1];
//         const value = opcodes[i + 2];
//         top.setAttribute(key, value);
//         i += 3;
//         break;
//       }
//       case OpcodeText: {
//         const text = opcodes[i + 1];
//         const s = new SnapshotInstance(null as unknown as string);
//         if (__ENABLE_SSR__) {
//           // We need store the just created SnapshotInstance, or it will be lost when we leave the function
//           opcodes[i + 1] = [s, text];
//         }
//         s.setAttribute(0, text);
//         top.insertBefore(s);
//         i += 2;
//         break;
//       }
//     }
//   }
// }
//# sourceMappingURL=opcodes.js.map