import * as React from "react";
import { EditorContent, useEditor } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";
import {
  Bold,
  Heading3,
  Italic,
  Link2,
  List,
  ListOrdered,
  Strikethrough,
  Underline as UnderlineIcon,
  Unlink,
} from "lucide-react";

import { Button } from "@/Components/ui/button";
import { Input } from "@/Components/ui/input";
import { Popover, PopoverContent, PopoverTrigger } from "@/Components/ui/popover";
import { cn } from "@/lib/utils";

/**
 * Editor de texto com formatação, sobre Tiptap.
 *
 * Trabalha em HTML: recebe HTML em `value` e devolve HTML em `onChange`. O que sai daqui
 * ainda passa pela lista branca do backend (`App\Services\Reports\NoteHtml`) antes de ir
 * pro banco, então a barra de ferramentas e a lista de tags aceitas lá precisam contar a
 * mesma história — o que não dá pra escrever aqui também não sobrevive lá.
 *
 * Só as marcações da barra ficam ligadas: bloco de código, linha horizontal e código
 * inline saem do StarterKit de propósito, senão um "colar" traria formatação que o
 * usuário vê na tela e some ao salvar.
 */
const RichTextEditor = React.forwardRef(
  ({ id, value = "", onChange, placeholder, className, editorClassName, disabled = false }, ref) => {
    const editor = useEditor({
      editable: !disabled,
      extensions: [
        StarterKit.configure({
          heading: { levels: [3] },
          code: false,
          codeBlock: false,
          horizontalRule: false,
          link: {
            openOnClick: false,
            // Quem digita "exent.com.br" quer um link; mesma regra do backend.
            defaultProtocol: "https",
            protocols: ["http", "https", "mailto"],
          },
        }),
      ],
      content: value || "",
      editorProps: {
        attributes: {
          // O `id` vai pro elemento editável, e não num wrapper, pra <Label htmlFor>
          // levar o foco pro lugar onde de fato se digita.
          ...(id ? { id } : {}),
          class: cn("rich-text-content focus:outline-none", editorClassName),
        },
      },
      onUpdate: ({ editor: instance }) => {
        // `isEmpty` cobre o `<p></p>` que sobra quando o usuário apaga tudo — sem isso
        // o backend receberia marcação vazia em vez de "não tem nota".
        onChange?.(instance.isEmpty ? "" : instance.getHTML());
      },
    });

    React.useImperativeHandle(ref, () => ({ editor, focus: () => editor?.commands.focus() }), [editor]);

    // Só recarrega quando a mudança veio de fora (abrir o modal com nota salva). Comparar
    // com o HTML atual é o que evita o cursor pular pro começo a cada tecla.
    React.useEffect(() => {
      if (!editor) return;

      const incoming = value || "";

      if (incoming !== editor.getHTML() && !(incoming === "" && editor.isEmpty)) {
        editor.commands.setContent(incoming, { emitUpdate: false });
      }
    }, [value, editor]);

    React.useEffect(() => {
      editor?.setEditable(!disabled);
    }, [disabled, editor]);

    if (!editor) return null;

    return (
      <div
        className={cn(
          "rounded-md border border-input bg-transparent shadow-sm transition-colors focus-within:ring-1 focus-within:ring-ring",
          disabled && "opacity-50",
          className
        )}
      >
        <div className="flex flex-wrap items-center gap-0.5 border-b bg-muted/40 px-1.5 py-1">
          <ToolbarButton
            label="Negrito"
            icon={Bold}
            active={editor.isActive("bold")}
            disabled={disabled}
            onClick={() => editor.chain().focus().toggleBold().run()}
          />
          <ToolbarButton
            label="Itálico"
            icon={Italic}
            active={editor.isActive("italic")}
            disabled={disabled}
            onClick={() => editor.chain().focus().toggleItalic().run()}
          />
          <ToolbarButton
            label="Sublinhado"
            icon={UnderlineIcon}
            active={editor.isActive("underline")}
            disabled={disabled}
            onClick={() => editor.chain().focus().toggleUnderline().run()}
          />
          <ToolbarButton
            label="Riscado"
            icon={Strikethrough}
            active={editor.isActive("strike")}
            disabled={disabled}
            onClick={() => editor.chain().focus().toggleStrike().run()}
          />

          <Separator />

          <ToolbarButton
            label="Subtítulo"
            icon={Heading3}
            active={editor.isActive("heading", { level: 3 })}
            disabled={disabled}
            onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}
          />
          <ToolbarButton
            label="Lista"
            icon={List}
            active={editor.isActive("bulletList")}
            disabled={disabled}
            onClick={() => editor.chain().focus().toggleBulletList().run()}
          />
          <ToolbarButton
            label="Lista numerada"
            icon={ListOrdered}
            active={editor.isActive("orderedList")}
            disabled={disabled}
            onClick={() => editor.chain().focus().toggleOrderedList().run()}
          />

          <Separator />

          <LinkButton editor={editor} disabled={disabled} />
          <ToolbarButton
            label="Remover link"
            icon={Unlink}
            disabled={disabled || !editor.isActive("link")}
            onClick={() => editor.chain().focus().unsetLink().run()}
          />
        </div>

        <div className="relative">
          {editor.isEmpty && placeholder && (
            <p className="pointer-events-none absolute left-3 top-2 text-sm text-muted-foreground">
              {placeholder}
            </p>
          )}
          <EditorContent editor={editor} />
        </div>
      </div>
    );
  }
);
RichTextEditor.displayName = "RichTextEditor";

function Separator() {
  return <span className="mx-1 h-5 w-px bg-border" aria-hidden="true" />;
}

function ToolbarButton({ label, icon: Icon, active = false, disabled, onClick }) {
  return (
    <Button
      type="button"
      variant="ghost"
      size="icon"
      aria-label={label}
      aria-pressed={active}
      title={label}
      disabled={disabled}
      onClick={onClick}
      className={cn("h-7 w-7", active && "bg-accent text-accent-foreground")}
    >
      <Icon className="h-4 w-4" />
    </Button>
  );
}

/** Link com campo próprio em vez de `window.prompt`, que não dá pra estilizar nem editar. */
function LinkButton({ editor, disabled }) {
  const [open, setOpen] = React.useState(false);
  const [href, setHref] = React.useState("");

  const start = (isOpen) => {
    setOpen(isOpen);
    if (isOpen) setHref(editor.getAttributes("link").href ?? "");
  };

  const apply = () => {
    const url = href.trim();

    if (url === "") {
      editor.chain().focus().unsetLink().run();
    } else {
      editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
    }

    setOpen(false);
  };

  return (
    <Popover open={open} onOpenChange={start}>
      <PopoverTrigger asChild>
        <Button
          type="button"
          variant="ghost"
          size="icon"
          aria-label="Inserir link"
          title="Inserir link"
          disabled={disabled}
          className={cn("h-7 w-7", editor.isActive("link") && "bg-accent text-accent-foreground")}
        >
          <Link2 className="h-4 w-4" />
        </Button>
      </PopoverTrigger>
      <PopoverContent align="start" className="w-72 space-y-2 p-3">
        <label className="text-xs font-medium text-muted-foreground" htmlFor="rte-link">
          Endereço do link
        </label>
        <Input
          id="rte-link"
          value={href}
          onChange={(e) => setHref(e.target.value)}
          onKeyDown={(e) => {
            if (e.key === "Enter") {
              e.preventDefault();
              apply();
            }
          }}
          placeholder="exent.com.br/pagina"
        />
        <div className="flex justify-end gap-2">
          <Button type="button" variant="outline" size="sm" onClick={() => setOpen(false)}>
            Cancelar
          </Button>
          <Button type="button" size="sm" onClick={apply}>
            Aplicar
          </Button>
        </div>
      </PopoverContent>
    </Popover>
  );
}

export { RichTextEditor };
