import { Mark_Type } from "./../../ricos-types/index.js";
import { Plugin } from "./../../tiptap/pm/state.js";
import { createRicosMarkExtension } from "./../../plugin-commons/index.js";
import { isInlineTextOnly } from "../../ricos-common-plugins/transaction-predicates/is-inline-text-only.js";
import { SKETCH_DATA_HOOK } from "./data-hooks.js";
import {
  DEFAULT_ANIMATE,
  DEFAULT_COLOR,
  DEFAULT_STYLE,
  STYLE_TO_ARIA_LABEL,
  TEXT_LAYER_Z_INDEX,
  getExplicitAnimate
} from "./defaults.js";
import {
  SKETCH_PLUGIN_KEY,
  buildDecorationSet,
  getPluginState
} from "./editor-decorations.js";
import { createSketchPreviewState } from "./editor-preview-state.js";
import { createWidgetController } from "./editor-widget-controller.js";
import {
  applyFastPathReconcile,
  isOverlayPreviewStyle,
  mapTrackedGroupPositions,
  reconcileTrackedAnnotationGroups,
  transactionInsertsSketchMark,
  transactionTouchesTrackedGroup
} from "./range-tracking.js";
const sketchPreviewState = createSketchPreviewState();
const SKETCH_PREVIEW_OVERRIDE = "sketchPreviewOverride";
const ADD_TO_HISTORY_META = "addToHistory";
const createSketchPlugin = (previewState = sketchPreviewState) => new Plugin({
  key: SKETCH_PLUGIN_KEY,
  state: {
    init: (_, state) => {
      const { trackedGroups, nextRangeId } = reconcileTrackedAnnotationGroups(state, [], 1);
      return {
        decorations: buildDecorationSet(state, trackedGroups, previewState.getOverride()),
        trackedGroups,
        nextRangeId
      };
    },
    apply: (tr, value, _oldState, newState) => {
      if (!tr.docChanged) {
        const previewOverrideChanged = !!tr.getMeta(SKETCH_PREVIEW_OVERRIDE);
        return {
          ...value,
          decorations: previewOverrideChanged ? buildDecorationSet(newState, value.trackedGroups, previewState.getOverride()) : value.decorations
        };
      }
      const mappedTrackedGroups = mapTrackedGroupPositions(tr, value.trackedGroups);
      const markType = newState.schema.marks[Mark_Type.SKETCH];
      const canSkipFullReconcile = !!markType && isInlineTextOnly(tr) && !transactionInsertsSketchMark(tr, markType) && !transactionTouchesTrackedGroup(tr, value.trackedGroups);
      const { trackedGroups, nextRangeId } = canSkipFullReconcile ? {
        trackedGroups: applyFastPathReconcile(newState.doc, mappedTrackedGroups),
        nextRangeId: value.nextRangeId
      } : reconcileTrackedAnnotationGroups(newState, mappedTrackedGroups, value.nextRangeId);
      return {
        decorations: buildDecorationSet(newState, trackedGroups, previewState.getOverride()),
        trackedGroups,
        nextRangeId
      };
    }
  },
  props: {
    decorations(state) {
      return getPluginState(state)?.decorations;
    }
  },
  view: (view) => createWidgetController(view, previewState)
});
const tiptapSketchExtension = createRicosMarkExtension({
  type: "mark",
  name: Mark_Type.SKETCH,
  groups: [],
  reconfigure: (config, _extensions, _props, settings) => ({
    ...config,
    addOptions() {
      return {
        HTMLAttributes: {},
        ...settings
      };
    }
  }),
  createExtensionConfig() {
    return {
      name: this.name,
      addAttributes() {
        return {
          style: {
            default: DEFAULT_STYLE,
            parseHTML: (element) => element.getAttribute("data-style") || DEFAULT_STYLE,
            renderHTML: (attrs) => ({ "data-style": attrs.style || DEFAULT_STYLE })
          },
          color: {
            default: DEFAULT_COLOR,
            parseHTML: (element) => element.getAttribute("data-color") || DEFAULT_COLOR,
            renderHTML: (attrs) => ({ "data-color": attrs.color || DEFAULT_COLOR })
          },
          animate: {
            default: DEFAULT_ANIMATE,
            parseHTML: (element) => element.getAttribute("data-animate") !== "false",
            renderHTML: (attrs) => ({ "data-animate": String(attrs.animate ?? DEFAULT_ANIMATE) })
          }
        };
      },
      parseHTML() {
        return [
          {
            tag: `span[data-hook="${SKETCH_DATA_HOOK}"]`,
            getAttrs: (node) => {
              if (typeof node === "string") {
                return false;
              }
              return {
                style: node.getAttribute("data-style") || DEFAULT_STYLE,
                color: node.getAttribute("data-color") || DEFAULT_COLOR,
                animate: node.getAttribute("data-animate") !== "false"
              };
            }
          }
        ];
      },
      renderHTML({ mark }) {
        const { style, color, animate } = mark.attrs;
        const styleKey = style || DEFAULT_STYLE;
        const ariaLabel = STYLE_TO_ARIA_LABEL[styleKey] ?? STYLE_TO_ARIA_LABEL[DEFAULT_STYLE];
        return [
          "span",
          {
            "data-hook": SKETCH_DATA_HOOK,
            "data-style": style || DEFAULT_STYLE,
            "data-color": color || DEFAULT_COLOR,
            "data-animate": String(animate ?? DEFAULT_ANIMATE),
            "aria-label": ariaLabel,
            style: `position: relative; z-index: ${TEXT_LAYER_Z_INDEX};`
          },
          0
        ];
      },
      addCommands() {
        return {
          setSketch: (attrs = {}) => ({ commands }) => {
            const animate = getExplicitAnimate(attrs.animate);
            commands.setMark(this.name, {
              style: attrs.style ?? DEFAULT_STYLE,
              color: attrs.color ?? DEFAULT_COLOR,
              ...animate !== void 0 && { animate }
            });
            return true;
          },
          unsetSketch: () => ({ commands }) => commands.unsetMark(this.name),
          previewSketch: (override) => ({ state, tr, dispatch }) => {
            sketchPreviewState.setOverride(override);
            if (override.animate && isOverlayPreviewStyle(override.style)) {
              sketchPreviewState.setAnimationRange({
                from: override.from,
                to: override.to
              });
            }
            sketchPreviewState.hideBackgroundMarks(state, tr, override);
            tr.setMeta(SKETCH_PREVIEW_OVERRIDE, true);
            tr.setMeta(ADD_TO_HISTORY_META, false);
            dispatch?.(tr);
            return true;
          },
          clearSketchPreview: () => ({ tr, dispatch }) => {
            if (sketchPreviewState.getOverride() === null && !sketchPreviewState.hasBackgroundRestoreRanges()) {
              return true;
            }
            sketchPreviewState.setOverride(null);
            sketchPreviewState.restoreBackgroundMarks(tr);
            tr.setMeta(SKETCH_PREVIEW_OVERRIDE, true);
            tr.setMeta(ADD_TO_HISTORY_META, false);
            dispatch?.(tr);
            return true;
          }
        };
      },
      addProseMirrorPlugins() {
        return [createSketchPlugin()];
      }
    };
  }
});
export {
  createSketchPlugin,
  tiptapSketchExtension
};
//# sourceMappingURL=tiptap.js.map
