import { pageLinkRegex } from "../../common/markdown_parser/parser.ts";
import { ClickEvent } from "../../plug-api/app_event.ts";
import { Decoration, syntaxTree } from "../deps.ts";
import { Client } from "../client.ts";
import {
  decoratorStateField,
  invisibleDecoration,
  isCursorInRange,
  LinkWidget,
} from "./util.ts";
import { resolvePath } from "$sb/lib/resolve.ts";

/**
 * Plugin to hide path prefix when the cursor is not inside.
 */
export function cleanWikiLinkPlugin(editor: Client) {
  return decoratorStateField((state) => {
    const widgets: any[] = [];
    // let parentRange: [number, number];
    syntaxTree(state).iterate({
      enter: ({ type, from, to }) => {
        if (type.name !== "WikiLink") {
          return;
        }

        const text = state.sliceDoc(from, to);
        const match = pageLinkRegex.exec(text);
        if (!match) return;
        const [_fullMatch, page, pipePart, alias] = match;

        const allPages = editor.space.listPages();
        let pageExists = !editor.fullSyncCompleted;
        let cleanPage = page;
        if (page.includes("@")) {
          cleanPage = page.split("@")[0];
        }
        cleanPage = resolvePath(editor.currentPage!, cleanPage);
        const lowerCasePageName = cleanPage.toLowerCase();
        for (const pageMeta of allPages) {
          if (pageMeta.name.toLowerCase() === lowerCasePageName) {
            pageExists = true;
            break;
          }
        }
        if (
          cleanPage === "" ||
          editor.plugSpaceRemotePrimitives.isLikelyHandled(cleanPage)
        ) {
          // Empty page name with local @anchor use or a link to a page that dynamically generated by a plug
          pageExists = true;
        }

        if (isCursorInRange(state, [from, to])) {
          // Only attach a CSS class, then get out
          if (!pageExists) {
            widgets.push(
              Decoration.mark({
                class: "sb-wiki-link-page-missing",
              }).range(from + 2, from + page.length + 2),
            );
          }
          return;
        }

        // Hide the whole thing
        widgets.push(
          invisibleDecoration.range(
            from,
            to,
          ),
        );

        let linkText = alias || page;
        if (!pipePart && text.indexOf("/") !== -1) {
          // Let's use the last part of the path as the link text
          linkText = page.split("/").pop()!;
        }

        // And replace it with a widget
        widgets.push(
          Decoration.widget({
            widget: new LinkWidget(
              {
                text: linkText,
                title: pageExists
                  ? `Navigate to ${cleanPage}`
                  : `Create ${cleanPage}`,
                href: `/${cleanPage}`,
                cssClass: pageExists
                  ? "sb-wiki-link-page"
                  : "sb-wiki-link-page-missing",
                callback: (e) => {
                  if (e.altKey) {
                    // Move cursor into the link
                    return editor.editorView.dispatch({
                      selection: { anchor: from + 2 },
                    });
                  }
                  // Dispatch click event to navigate there without moving the cursor
                  const clickEvent: ClickEvent = {
                    page: editor.currentPage!,
                    ctrlKey: e.ctrlKey,
                    metaKey: e.metaKey,
                    altKey: e.altKey,
                    pos: from,
                  };
                  editor.dispatchAppEvent("page:click", clickEvent).catch(
                    console.error,
                  );
                },
              },
            ),
          }).range(from),
        );
      },
    });
    return Decoration.set(widgets, true);
  });
}
