"use client";

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

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

function mockEmbedMeta(url: string): {
  title: string;
  description: string;
  image: string;
} {
  try {
    const u = new URL(url);
    const host = u.hostname.replace(/^www\./, "");
    return {
      title: host || "Link preview",
      description: `Preview for ${url}`,
      image: `https://picsum.photos/seed/${encodeURIComponent(host)}/400/200`,
    };
  } catch {
    return {
      title: "Link preview",
      description: url,
      image: "",
    };
  }
}

function EmbedView(props: NodeViewProps) {
  const { node, updateAttributes, selected } = props;
  const url = String(node.attrs.url ?? "");
  const title = String(node.attrs.title ?? "");
  const description = String(node.attrs.description ?? "");
  const image = String(node.attrs.image ?? "");
  const [draft, setDraft] = React.useState(url);

  React.useEffect(() => {
    setDraft(url);
  }, [url]);

  const applyUrl = React.useCallback(() => {
    const next = draft.trim();
    if (!next) return;
    let normalized = next;
    if (!/^https?:\/\//i.test(normalized)) {
      normalized = `https://${normalized}`;
    }
    const meta = mockEmbedMeta(normalized);
    updateAttributes({
      url: normalized,
      title: meta.title,
      description: meta.description,
      image: meta.image,
    });
  }, [draft, updateAttributes]);

  const onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === "Enter") {
      e.preventDefault();
      applyUrl();
    }
  };

  if (!url) {
    return (
      <NodeViewWrapper
        className={cn(
          "embed-block my-4 rounded-lg border border-dashed border-border bg-muted/30 p-4 dark:bg-muted/15",
          selected && "ring-2 ring-primary/40 ring-offset-2 ring-offset-background",
        )}
        data-type="embed"
      >
        <div className="flex items-center gap-2 text-muted-foreground">
          <Link2 className="size-4 shrink-0" aria-hidden />
          <input
            className="min-w-0 flex-1 rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground outline-none ring-primary/30 focus:ring-2"
            placeholder="Paste a URL and press Enter…"
            type="url"
            value={draft}
            onChange={(e) => setDraft(e.target.value)}
            onBlur={applyUrl}
            onKeyDown={onKeyDown}
          />
        </div>
      </NodeViewWrapper>
    );
  }

  return (
    <NodeViewWrapper
      className={cn(
        "embed-block my-4 overflow-hidden rounded-xl border border-border bg-card text-card-foreground shadow-sm",
        selected && "ring-2 ring-primary/40 ring-offset-2 ring-offset-background",
      )}
      data-type="embed"
      data-url={url}
    >
      {image ? (
        // eslint-disable-next-line @next/next/no-img-element
        <img
          alt=""
          className="h-40 w-full object-cover"
          src={image}
        />
      ) : null}
      <div className="flex flex-col gap-1 p-4">
        <a
          className="inline-flex items-center gap-1.5 text-base font-semibold text-primary hover:underline"
          href={url}
          rel="noopener noreferrer"
          target="_blank"
        >
          {title || url}
          <ExternalLink className="size-3.5 opacity-70" aria-hidden />
        </a>
        {description ? (
          <p className="text-sm leading-relaxed text-muted-foreground">
            {description}
          </p>
        ) : null}
        <p className="truncate text-xs text-muted-foreground/80">{url}</p>
      </div>
    </NodeViewWrapper>
  );
}

export const Embed = Node.create({
  name: "embed",
  group: "block",
  atom: true,
  draggable: true,
  selectable: true,

  addAttributes() {
    return {
      url: {
        default: "",
        parseHTML: (el) => el.getAttribute("data-url") ?? "",
        renderHTML: (attrs) =>
          attrs.url ? { "data-url": attrs.url } : {},
      },
      title: {
        default: "",
        parseHTML: (el) => el.querySelector("a")?.textContent?.trim() ?? "",
        renderHTML: () => ({}),
      },
      description: {
        default: "",
        parseHTML: (el) =>
          el.querySelector("p")?.textContent?.trim() ?? "",
        renderHTML: () => ({}),
      },
      image: {
        default: "",
        parseHTML: () => "",
        renderHTML: () => ({}),
      },
    };
  },

  parseHTML() {
    return [
      {
        tag: 'div[data-type="embed"]',
      },
    ];
  },

  renderHTML({ node, HTMLAttributes }) {
    const url = String(node.attrs.url ?? "");
    const title = String(node.attrs.title ?? url);
    const description = String(node.attrs.description ?? "");
    return [
      "div",
      mergeAttributes(HTMLAttributes, {
        "data-type": "embed",
        ...(url ? { "data-url": url } : {}),
      }),
      [
        "a",
        {
          href: url || "#",
          rel: "noopener noreferrer",
          target: "_blank",
        },
        title,
      ],
      ["p", {}, description],
    ];
  },

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

  addKeyboardShortcuts() {
    return {
      "Mod-Shift-Alt-e": () =>
        this.editor.commands.insertContent({
          type: this.name,
          attrs: {
            url: "",
            title: "",
            description: "",
            image: "",
          },
        }),
    };
  },
});
