"use client";

import { useState, useRef, useCallback, useEffect, forwardRef, useImperativeHandle, KeyboardEvent, ChangeEvent } from "react";
import { Paperclip, Send, SmilePlus, X, FileIcon } from "lucide-react";
import { useSendMessage, useUploadFile, useCompanyUsers } from "@/hooks/useMessenger";
import { toast } from "sonner";

const QUICK_EMOJIS = ["\u{1F44D}", "\u{2764}\u{FE0F}", "\u{1F602}", "\u{1F44F}", "\u{1F64F}", "\u{1F525}", "\u{1F389}", "\u{1F914}"];

interface PendingFile {
  file: File;
  previewUrl: string | null; // object URL for images, null for others
}

export interface MessageInputHandle {
  addFiles: (files: File[]) => void;
}

interface MessageInputProps {
  roomId: string;
  onTypingStart?: () => void;
  onTypingStop?: () => void;
}

export const MessageInput = forwardRef<MessageInputHandle, MessageInputProps>(
function MessageInput({ roomId, onTypingStart, onTypingStop }: MessageInputProps, ref) {
  const [text, setText] = useState("");
  const [pendingFiles, setPendingFiles] = useState<PendingFile[]>([]);
  const [showEmoji, setShowEmoji] = useState(false);
  const emojiRef = useRef<HTMLDivElement>(null);
  const [mentionQuery, setMentionQuery] = useState<string | null>(null);
  const [mentionIndex, setMentionIndex] = useState(0);
  const textareaRef = useRef<HTMLTextAreaElement>(null);
  const fileRef = useRef<HTMLInputElement>(null);
  const typingTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  const sendMessage = useSendMessage();
  const uploadFile = useUploadFile();
  const { data: users } = useCompanyUsers();

  const filteredMentionUsers = mentionQuery !== null && users
    ? users.filter((u) => u.userName.toLowerCase().includes(mentionQuery.toLowerCase())).slice(0, 5)
    : [];

  // Revoke object URLs when pending files change or component unmounts
  useEffect(() => {
    return () => {
      pendingFiles.forEach((pf) => { if (pf.previewUrl) URL.revokeObjectURL(pf.previewUrl); });
    };
  }, [pendingFiles]);

  const adjustHeight = useCallback(() => {
    const el = textareaRef.current;
    if (el) {
      el.style.height = "auto";
      el.style.height = Math.min(el.scrollHeight, 120) + "px";
    }
  }, []);

  useEffect(() => { adjustHeight(); }, [text, adjustHeight]);

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

  // Close emoji picker on outside click
  useEffect(() => {
    if (!showEmoji) return;
    const handler = (e: MouseEvent) => {
      if (emojiRef.current && !emojiRef.current.contains(e.target as Node)) setShowEmoji(false);
    };
    document.addEventListener("mousedown", handler);
    return () => document.removeEventListener("mousedown", handler);
  }, [showEmoji]);

  const BLOCKED_TYPES = /^(audio|video)\//;

  const addFiles = (files: FileList | File[]) => {
    const arr = Array.from(files).filter((f) => {
      if (BLOCKED_TYPES.test(f.type)) {
        toast(`${f.name} — 음원/동영상 파일은 전송할 수 없습니다.`);
        return false;
      }
      return true;
    });
    if (arr.length === 0) return;
    setPendingFiles((prev) => [
      ...prev,
      ...arr.map((file) => ({
        file,
        previewUrl: file.type.startsWith("image/") ? URL.createObjectURL(file) : null,
      })),
    ]);
    textareaRef.current?.focus();
  };

  useImperativeHandle(ref, () => ({ addFiles }));

  const removePendingFile = (idx: number) => {
    setPendingFiles((prev) => {
      const pf = prev[idx];
      if (pf.previewUrl) URL.revokeObjectURL(pf.previewUrl);
      return prev.filter((_, i) => i !== idx);
    });
  };

  const handleSend = useCallback(async () => {
    const trimmed = text.trim();
    if (!trimmed && pendingFiles.length === 0) return;

    // Upload all pending files (backend creates a message per file)
    for (const pf of pendingFiles) {
      try {
        await uploadFile.mutateAsync({ file: pf.file, roomId });
        if (pf.previewUrl) URL.revokeObjectURL(pf.previewUrl);
      } catch {
        // upload failed silently
      }
    }
    setPendingFiles([]);

    // Send text message if any
    if (trimmed) {
      sendMessage.mutate({ roomId, content: trimmed });
      setText("");
    }

    if (typingTimerRef.current) { clearTimeout(typingTimerRef.current); typingTimerRef.current = null; }
    onTypingStop?.();
  }, [text, pendingFiles, roomId, uploadFile, sendMessage, onTypingStop]);

  const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
    if (mentionQuery !== null && filteredMentionUsers.length > 0) {
      if (e.key === "ArrowDown") { e.preventDefault(); setMentionIndex((p) => Math.min(p + 1, filteredMentionUsers.length - 1)); return; }
      if (e.key === "ArrowUp") { e.preventDefault(); setMentionIndex((p) => Math.max(p - 1, 0)); return; }
      if (e.key === "Enter" || e.key === "Tab") { e.preventDefault(); insertMention(filteredMentionUsers[mentionIndex]); return; }
      if (e.key === "Escape") { setMentionQuery(null); return; }
    }
    if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
      e.preventDefault();
      handleSend();
    }
  };

  const insertMention = (user: { userId: string; userName: string }) => {
    const el = textareaRef.current;
    if (!el) return;
    const val = el.value;
    const atIdx = val.lastIndexOf("@", el.selectionStart - 1);
    if (atIdx === -1) return;
    setText(`${val.slice(0, atIdx)}@${user.userName} ${val.slice(el.selectionStart)}`);
    setMentionQuery(null);
  };

  const handleChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
    const val = e.target.value;
    setText(val);
    if (typingTimerRef.current) clearTimeout(typingTimerRef.current);
    if (val.trim()) {
      onTypingStart?.();
      typingTimerRef.current = setTimeout(() => {
        onTypingStop?.();
        typingTimerRef.current = null;
      }, 3000);
    } else {
      onTypingStop?.();
    }
    const cursor = e.target.selectionStart;
    const atMatch = val.slice(0, cursor).match(/@(\S*)$/);
    if (atMatch) { setMentionQuery(atMatch[1]); setMentionIndex(0); } else { setMentionQuery(null); }
  };

  const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
    if (e.target.files?.length) addFiles(e.target.files);
    e.target.value = "";
  };

  const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
    e.preventDefault();
    if (e.dataTransfer.files?.length) addFiles(e.dataTransfer.files);
  };

  const handlePaste = (e: React.ClipboardEvent<HTMLTextAreaElement>) => {
    if (e.clipboardData.files?.length) {
      e.preventDefault();
      addFiles(e.clipboardData.files);
    }
  };

  const canSend = text.trim().length > 0 || pendingFiles.length > 0;

  return (
    <div
      className="relative shrink-0"
      onDragOver={(e) => e.preventDefault()}
      onDrop={handleDrop}
    >

      {/* Mention dropdown */}
      {mentionQuery !== null && filteredMentionUsers.length > 0 && (
        <div className="absolute bottom-full left-2 right-2 bg-background border rounded-md shadow-md max-h-40 overflow-y-auto z-10">
          {filteredMentionUsers.map((u, i) => (
            <button
              key={u.userId}
              onClick={() => insertMention(u)}
              className={`w-full text-left px-3 py-1.5 text-sm hover:bg-muted ${i === mentionIndex ? "bg-muted" : ""}`}
            >
              <span className="font-medium">{u.userName}</span>
              {u.deptName && <span className="text-muted-foreground ml-2">{u.deptName}</span>}
            </button>
          ))}
        </div>
      )}

      {/* Pending file previews */}
      {pendingFiles.length > 0 && (
        <div className="flex flex-wrap gap-2 px-3 pt-2 pb-1">
          {pendingFiles.map((pf, idx) => (
            <div key={idx} className="relative group/preview">
              {pf.previewUrl ? (
                <img
                  src={pf.previewUrl}
                  alt={pf.file.name}
                  className="h-16 w-16 rounded-md object-cover border"
                />
              ) : (
                <div className="h-16 w-28 rounded-md border bg-muted flex flex-col items-center justify-center gap-1 px-2">
                  <FileIcon className="h-5 w-5 text-muted-foreground shrink-0" />
                  <span className="text-[10px] text-muted-foreground truncate w-full text-center">{pf.file.name}</span>
                </div>
              )}
              <button
                onClick={() => removePendingFile(idx)}
                className="absolute -top-1.5 -right-1.5 h-4 w-4 rounded-full bg-foreground text-background flex items-center justify-center opacity-0 group-hover/preview:opacity-100 transition-opacity"
              >
                <X className="h-2.5 w-2.5" />
              </button>
            </div>
          ))}
        </div>
      )}

      {/* Input toolbar */}
      <div className="flex items-center gap-1 p-2 mx-2 mb-2 border rounded-lg focus-within:border-primary focus-within:ring-1 focus-within:ring-primary/30 transition-colors">
        <button onClick={() => fileRef.current?.click()} className="p-1.5 hover:bg-muted rounded shrink-0">
          <Paperclip className="h-4 w-4 text-muted-foreground" />
        </button>
        <input ref={fileRef} type="file" multiple className="hidden" onChange={handleFileChange} />

        <div className="relative shrink-0" ref={emojiRef}>
          <button onClick={() => setShowEmoji((p) => !p)} className="p-1.5 hover:bg-muted rounded">
            <SmilePlus className="h-4 w-4 text-muted-foreground" />
          </button>
          {showEmoji && (
            <div className="absolute bottom-full left-0 bg-background border rounded-md shadow-md p-1.5 flex flex-wrap gap-1 w-48 z-10">
              {QUICK_EMOJIS.map((emoji) => (
                <button
                  key={emoji}
                  onClick={() => { setText((p) => p + emoji); setShowEmoji(false); textareaRef.current?.focus(); }}
                  className="hover:bg-muted rounded p-1 text-lg"
                >
                  {emoji}
                </button>
              ))}
            </div>
          )}
        </div>

        <textarea
          ref={textareaRef}
          value={text}
          onChange={handleChange}
          onKeyDown={handleKeyDown}
          onPaste={handlePaste}
          placeholder="메시지를 입력하세요..."
          rows={1}
          className="flex-1 resize-none bg-transparent text-sm outline-none placeholder:text-muted-foreground py-1.5 pl-1.5 pr-2 ml-1 max-h-[120px]"
        />

        <button
          onClick={handleSend}
          disabled={!canSend || uploadFile.isPending}
          className="p-1.5 hover:bg-muted rounded disabled:opacity-40 shrink-0"
        >
          <Send className="h-4 w-4 text-primary" />
        </button>
      </div>
    </div>
  );
});
