import { useEffect, useRef, useCallback, useState } from "react";
import { Paperclip } from "lucide-react";
import { cn } from "@/lib/utils";
import { metaKey } from "@/lib/platform";
import { useAllLinkMetadata } from "@/hooks/use-link-metadata";
import { AttachmentStrip } from "@/features/compose/attachment-strip";
import type { PendingAttachment } from "@/features/compose/attachment-strip";
import { Button } from "@/components/ui/button";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import rehypeHighlight from "rehype-highlight";
import "highlight.js/styles/github-dark.css";

export interface TextEditorAttachmentProps {
  attachments: PendingAttachment[];
  onRemoveAttachment: (id: string) => void;
  onAddFiles: () => void;
  isDragging: boolean;
  dropZoneProps: {
    onDragOver: (e: React.DragEvent) => void;
    onDragEnter: (e: React.DragEvent) => void;
    onDragLeave: (e: React.DragEvent) => void;
    onDrop: (e: React.DragEvent) => void;
  };
}

interface TextEditorProps {
  textContent: string;
  onTextChange: (text: string) => void;
  onSubmit: () => void;
  onCancel: () => void;
  /** Label on the ⌘+Enter hint. Defaults to "next". */
  submitHint?: string;
  /** When omitted, the editor renders without attachment support (no attach button, no drop zone, no strip). */
  attachmentProps?: TextEditorAttachmentProps;
}

const IMMERSIVE_CHAR_LIMIT = 120;

function getImmersiveTextStyle(length: number) {
  if (length < 70) return { size: "text-5xl", weight: "font-semibold" };
  if (length < 130) return { size: "text-3xl", weight: "font-semibold" };
  return { size: "text-2xl", weight: "font-normal" };
}

const markdownComponents: React.ComponentProps<typeof ReactMarkdown>["components"] = {
  h1: ({ children }) => <h1 className="mb-3 text-3xl font-bold text-white">{children}</h1>,
  h2: ({ children }) => <h2 className="mb-2 text-2xl font-semibold text-white">{children}</h2>,
  h3: ({ children }) => <h3 className="mb-2 text-xl font-semibold text-white">{children}</h3>,
  h4: ({ children }) => <h4 className="mb-1 text-lg font-medium text-white">{children}</h4>,
  h5: ({ children }) => <h5 className="mb-1 text-base font-medium text-white">{children}</h5>,
  h6: ({ children }) => <h6 className="mb-1 text-sm font-medium text-white">{children}</h6>,
  p: ({ children }) => <p className="mb-3 leading-relaxed text-white last:mb-0">{children}</p>,
  strong: ({ children }) => <strong className="font-semibold text-white">{children}</strong>,
  em: ({ children }) => <em className="italic text-white">{children}</em>,
  a: ({ href, children }) => (
    <a href={href} className="text-blue-400 underline" target="_blank" rel="noreferrer">
      {children}
    </a>
  ),
  code: ({ className, children, ...props }) => {
    const isBlock = className?.startsWith("language-");
    if (isBlock) {
      return (
        <code className={cn(className, "text-sm")} {...props}>
          {children}
        </code>
      );
    }
    return (
      <code className="rounded bg-white/10 px-1.5 py-0.5 font-mono text-sm text-white" {...props}>
        {children}
      </code>
    );
  },
  pre: ({ children }) => (
    <pre className="mb-3 overflow-x-auto rounded-lg bg-black/40 p-4 text-sm last:mb-0">
      {children}
    </pre>
  ),
  ul: ({ children }) => <ul className="mb-3 list-disc pl-5 text-white last:mb-0">{children}</ul>,
  ol: ({ children }) => <ol className="mb-3 list-decimal pl-5 text-white last:mb-0">{children}</ol>,
  li: ({ children }) => <li className="mb-1 leading-relaxed">{children}</li>,
  blockquote: ({ children }) => (
    <blockquote className="mb-3 border-l-2 border-white/30 pl-4 italic text-white/70 last:mb-0">
      {children}
    </blockquote>
  ),
  hr: () => <hr className="my-4 border-white/10" />,
};

function MarkdownPreview({ content }: { content: string }) {
  return (
    <div className="min-h-0 flex-1 overflow-y-auto overflow-x-hidden break-words">
      <ReactMarkdown
        remarkPlugins={[remarkGfm]}
        rehypePlugins={[rehypeHighlight]}
        components={markdownComponents}
      >
        {content}
      </ReactMarkdown>
    </div>
  );
}

export function TextEditor({
  textContent,
  onTextChange,
  onSubmit,
  onCancel,
  submitHint = "next",
  attachmentProps,
}: TextEditorProps) {
  const textareaRef = useRef<HTMLTextAreaElement>(null);
  const [previewMode, setPreviewMode] = useState(false);
  const [forceCardMode, setForceCardMode] = useState(false);

  const [debouncedText, setDebouncedText] = useState(textContent);
  useEffect(() => {
    const t = setTimeout(() => setDebouncedText(textContent), 500);
    return () => clearTimeout(t);
  }, [textContent]);
  const linkPreviews = useAllLinkMetadata(debouncedText);

  const attachmentCount = attachmentProps?.attachments.length ?? 0;
  const hasEnrichments = attachmentCount > 0 || linkPreviews.length > 0;
  const immersive =
    textContent.length < IMMERSIVE_CHAR_LIMIT && !hasEnrichments && !forceCardMode;

  useEffect(() => {
    if (!previewMode) {
      const t = setTimeout(() => {
        const el = textareaRef.current;
        if (el) {
          el.focus();
          el.selectionStart = el.selectionEnd = el.value.length;
        }
      }, 0);
      return () => clearTimeout(t);
    }
  }, [previewMode, forceCardMode, immersive]);

  useEffect(() => {
    textareaRef.current?.focus();
  }, []);

  const handleKeyDown = useCallback(
    (e: React.KeyboardEvent) => {
      if (e.key === "Escape") {
        e.preventDefault();
        onCancel();
      } else if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
        e.preventDefault();
        if (textContent.trim()) onSubmit();
      } else if (e.key === "m" && (e.metaKey || e.ctrlKey)) {
        e.preventDefault();
        setForceCardMode(true);
      }
    },
    [onCancel, onSubmit, textContent],
  );

  const strip = attachmentProps && (
    <AttachmentStrip
      attachments={attachmentProps.attachments}
      onRemove={attachmentProps.onRemoveAttachment}
      onAddClick={attachmentProps.onAddFiles}
      linkPreviews={linkPreviews}
    />
  );

  const keyboardHints = (
    <div className="absolute bottom-4 flex items-center gap-4 text-sm text-white/50">
      <span>
        <kbd className="rounded bg-white/10 px-1.5 py-0.5 font-mono text-xs">
          Esc
        </kbd>{" "}
        cancel
      </span>
      <span>
        <kbd className="rounded bg-white/10 px-1.5 py-0.5 font-mono text-xs">
          {metaKey}+Enter
        </kbd>{" "}
        {submitHint}
      </span>
      {immersive && (
        <span>
          <kbd className="rounded bg-white/10 px-1.5 py-0.5 font-mono text-xs">
            {metaKey}+M
          </kbd>{" "}
          markdown
        </span>
      )}
      {attachmentProps && (
        <span>
          <Button
            variant="ghost"
            type="button"
            onClick={(e) => {
              e.stopPropagation();
              attachmentProps.onAddFiles();
            }}
            title="Attach files"
          >
            <Paperclip className="size-4" />
            attach
          </Button>
        </span>
      )}
    </div>
  );

  const dropZoneProps = attachmentProps?.dropZoneProps;
  const isDragging = attachmentProps?.isDragging ?? false;

  if (immersive) {
    const style = getImmersiveTextStyle(textContent.length);
    return (
      <div
        className={cn(
          "absolute inset-0 z-50 flex items-center justify-center bg-black/90",
          isDragging && "ring-2 ring-inset ring-white/30",
        )}
        {...dropZoneProps}
      >
        <div className="flex w-full flex-col items-center justify-center gap-6 px-6">
          <textarea
            ref={textareaRef}
            value={textContent}
            onChange={(e) => onTextChange(e.target.value)}
            onKeyDown={handleKeyDown}
            placeholder="Type a message..."
            className={cn(
              "w-full resize-none border-none bg-transparent p-8 text-center text-white placeholder-white/40 outline-none",
              style.size,
              style.weight,
            )}
            rows={4}
          />
        </div>
        {keyboardHints}
      </div>
    );
  }

  return (
    <div
      className={cn(
        "absolute inset-0 z-50 flex items-center justify-center bg-black/90",
        isDragging && "ring-2 ring-inset ring-white/30",
      )}
      {...dropZoneProps}
      onKeyDown={handleKeyDown}
    >
      <div className="mx-8 flex h-[calc(100%-8rem)] w-full min-w-0 flex-col overflow-hidden rounded-2xl border border-white/10 bg-white/5 p-5 backdrop-blur-xl">
        <div className="mb-3 flex shrink-0 items-center justify-end gap-1">
          <button
            type="button"
            onClick={() => setPreviewMode(false)}
            className={cn(
              "rounded-md px-3 py-1 text-xs font-medium transition-colors",
              !previewMode
                ? "bg-white/15 text-white"
                : "text-white/40 hover:text-white/60",
            )}
          >
            Write
          </button>
          <button
            type="button"
            onClick={() => setPreviewMode(true)}
            className={cn(
              "rounded-md px-3 py-1 text-xs font-medium transition-colors",
              previewMode
                ? "bg-white/15 text-white"
                : "text-white/40 hover:text-white/60",
            )}
          >
            Preview
          </button>
        </div>

        {previewMode ? (
          <MarkdownPreview content={textContent} />
        ) : (
          <textarea
            ref={textareaRef}
            value={textContent}
            onChange={(e) => onTextChange(e.target.value)}
            onKeyDown={handleKeyDown}
            placeholder="Type a message... (markdown supported)"
            className="min-h-0 flex-1 resize-none border-none bg-transparent font-mono text-sm leading-relaxed text-white placeholder-white/40 outline-none"
          />
        )}

        {hasEnrichments && strip && (
          <div className="shrink-0 border-t border-white/10 pt-3">
            {strip}
          </div>
        )}
      </div>
      {keyboardHints}
    </div>
  );
}
