import { type Editor } from '@tiptap/react';

import { registerActiveLoader, unregisterActiveLoader } from './loaderRegistry';

/**
 * Inserts an image-loader skeleton, preloads the image, then replaces
 * the skeleton with a resizable-media node once the image is decoded.
 * Used by InsertImage modal where upload is already complete but img
 * decode/network fetch may still take time.
 */
export const insertImageWithLoader = (editor: Editor, src: string) => {
  const loaderId = `image-loader-${Date.now()}-${Math.random()}`;

  registerActiveLoader(loaderId);

  editor
    .chain()
    .focus()
    .insertContent({
      type: 'image-loader',
      attrs: { imageLoaderId: loaderId },
    })
    .run();

  const findLoaderPos = (): number | null => {
    let pos: number | null = null;
    editor.state.doc.descendants((node, nodePos) => {
      if (
        node.type.name === 'image-loader' &&
        node.attrs.imageLoaderId === loaderId
      ) {
        pos = nodePos;
        return false;
      }
    });
    return pos;
  };

  const preload = new window.Image();
  const settle = () => {
    unregisterActiveLoader(loaderId);
  };
  preload.onload = () => {
    try {
      if (editor.isDestroyed) return;
      const loaderPos = findLoaderPos();
      if (loaderPos === null) return;
      editor
        .chain()
        .deleteRange({ from: loaderPos, to: loaderPos + 1 })
        .insertContentAt(loaderPos, [
          { type: 'resizable-media', attrs: { tag: 'img', src } },
          { type: 'paragraph' },
        ])
        .focus()
        .run();
    } finally {
      settle();
    }
  };
  preload.onerror = () => {
    try {
      if (editor.isDestroyed) return;
      const loaderPos = findLoaderPos();
      if (loaderPos === null) return;
      editor
        .chain()
        .deleteRange({ from: loaderPos, to: loaderPos + 1 })
        .run();
    } finally {
      settle();
    }
  };
  preload.src = src;
};
