"use client";

import { Node, mergeAttributes } from "@tiptap/react";
import {
  NodeViewContent,
  NodeViewWrapper,
  ReactNodeViewRenderer,
  type NodeViewProps,
} from "@tiptap/react";
import { ChevronDown, ChevronRight } from "lucide-react";
import * as React from "react";

import { cn } from "@/lib/utils";

function ToggleView(props: NodeViewProps) {
  const { node, updateAttributes, selected } = props;
  const open = Boolean(node.attrs.open);
  const title = typeof node.attrs.title === "string" ? node.attrs.title : "";

  const onTitleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    updateAttributes({ title: e.target.value });
  };

  return (
    <NodeViewWrapper
      as="details"
      className={cn(
        "toggle-block my-2 rounded-lg border border-border bg-card/60 dark:bg-card/40",
        selected && "ring-2 ring-primary/40 ring-offset-2 ring-offset-background",
      )}
      data-type="toggle"
      open={open}
      onToggle={(e: React.SyntheticEvent<HTMLDetailsElement>) => {
        updateAttributes({ open: e.currentTarget.open });
      }}
    >
      <summary
        className="flex cursor-pointer list-none items-center gap-2 px-2 py-1.5 text-[15px] font-medium text-foreground marker:hidden [&::-webkit-details-marker]:hidden"
      >
        <span
          className="flex size-6 shrink-0 items-center justify-center text-muted-foreground"
          contentEditable={false}
        >
          {open ? (
            <ChevronDown className="size-4" aria-hidden />
          ) : (
            <ChevronRight className="size-4" aria-hidden />
          )}
        </span>
        <input
          className="min-w-0 flex-1 bg-transparent outline-none placeholder:text-muted-foreground"
          placeholder="Toggle"
          type="text"
          value={title}
          onChange={onTitleChange}
          onClick={(e) => e.stopPropagation()}
        />
      </summary>
      <div
        className="toggle-body border-t border-border px-2 py-2 pl-9 [&_.ProseMirror_p]:my-1"
        data-toggle-body="true"
      >
        <NodeViewContent />
      </div>
    </NodeViewWrapper>
  );
}

export const Toggle = Node.create({
  name: "toggle",
  group: "block",
  content: "block+",
  defining: true,

  addAttributes() {
    return {
      open: {
        default: true,
        parseHTML: (el) =>
          el instanceof HTMLElement && el.hasAttribute("open"),
        renderHTML: (attrs) => (attrs.open ? { open: "" } : {}),
      },
      title: {
        default: "",
        parseHTML: (el) => {
          if (!(el instanceof HTMLElement)) return "";
          const s = el.querySelector(":scope > summary");
          return s?.textContent?.trim() ?? "";
        },
        renderHTML: (attrs) => ({}),
      },
    };
  },

  parseHTML() {
    return [
      {
        tag: 'details[data-type="toggle"]',
        contentElement: 'div[data-toggle-body="true"]',
      },
    ];
  },

  renderHTML({ node, HTMLAttributes }) {
    return [
      "details",
      mergeAttributes(HTMLAttributes, {
        "data-type": "toggle",
        ...(node.attrs.open ? { open: "" } : {}),
      }),
      [
        "summary",
        { class: "toggle-summary" },
        node.attrs.title ? String(node.attrs.title) : "\u00a0",
      ],
      ["div", { "data-toggle-body": "true", class: "toggle-body" }, 0],
    ];
  },

  addNodeView() {
    return ReactNodeViewRenderer(ToggleView);
  },

  addKeyboardShortcuts() {
    return {
      "Mod-Shift-Alt-t": () =>
        this.editor.commands.insertContent({
          type: this.name,
          attrs: { open: true, title: "" },
          content: [{ type: "paragraph" }],
        }),
    };
  },
});
