import { Boot } from '@wangeditor/editor';
import type { SlateElement } from '@wangeditor/editor';
import { h, type VNode } from 'snabbdom';

const TYPE = 'styled-block';

function parseStyleStr(str: string): Record<string, string> {
  const result: Record<string, string> = {};
  str.split(';').forEach((rule) => {
    const idx = rule.indexOf(':');
    if (idx === -1) return;
    const key = rule.substring(0, idx).trim().replace(/-([a-z])/g, (_, c) => c.toUpperCase());
    const value = rule.substring(idx + 1).trim();
    if (key && value) result[key] = value;
  });
  return result;
}

const renderElemConf = {
  type: TYPE,
  renderElem(elemNode: SlateElement): VNode {
    const node = elemNode as unknown as Record<string, unknown>;
    const style = (node.style as string) || '';
    const innerHtml = (node.innerHtml as string) || '';
    return h(
      'div',
      {
        attrs: { 'data-w-e-type': TYPE, contenteditable: 'false' },
        style: parseStyleStr(style),
        hook: {
          insert(vnode: VNode) {
            if (vnode.elm) (vnode.elm as HTMLElement).innerHTML = innerHtml;
          },
          postpatch(_: VNode, vnode: VNode) {
            if (vnode.elm) (vnode.elm as HTMLElement).innerHTML = innerHtml;
          },
        },
      },
      [],
    );
  },
};

const elemToHtmlConf = {
  type: TYPE,
  elemToHtml(elemNode: SlateElement): string {
    const node = elemNode as unknown as Record<string, unknown>;
    const style = (node.style as string) || '';
    const innerHtml = (node.innerHtml as string) || '';
    return `<div data-w-e-type="${TYPE}" style="${style}">${innerHtml}</div>`;
  },
};

const parseElemHtmlConf = {
  selector: `div[data-w-e-type="${TYPE}"]`,
  parseElemHtml($elem: Element): SlateElement {
    return {
      type: TYPE,
      style: $elem.getAttribute('style') || '',
      innerHtml: $elem.innerHTML,
      children: [{ text: '' }],
    } as SlateElement;
  },
};

let registered = false;

export function registerStyledBlockPlugin() {
  if (registered) return;
  Boot.registerModule({
    renderElems: [renderElemConf],
    elemsToHtml: [elemToHtmlConf],
    parseElemsHtml: [parseElemHtmlConf],
  });
  registered = true;
}

export { TYPE as STYLE_BLOCK_TYPE };
