import { useEffect, useRef, useState, useCallback, memo } from "react";
import { useParams } from "react-router-dom";
import { useConversationStore, type ConversationMessage } from "../stores/conversation.ts";
import { useAuthStore } from "../stores/auth.ts";
import { useTypingStore } from "../stores/typing.ts";
import { useLayoutStore } from "../stores/layout.ts";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";

function formatTime(iso: string): string {
  const date = new Date(iso);
  const hours = date.getHours().toString().padStart(2, "0");
  const minutes = date.getMinutes().toString().padStart(2, "0");
  return `${hours}:${minutes}`;
}

function renderDMContent(content: string) {
  return (
    <ReactMarkdown
      remarkPlugins={[remarkGfm]}
      components={{
        a: ({ ...props }) => <a {...props} className="text-gb-aqua hover:underline" target="_blank" rel="noreferrer" />,
        code: ({ ...props }) => <code {...props} className="bg-gb-bg-t px-1 rounded text-gb-fg-s" />,
        pre: ({ ...props }) => <pre {...props} className="bg-gb-bg-s p-2 my-1 overflow-x-auto text-gb-fg-s" />,
        blockquote: ({ ...props }) => <blockquote {...props} className="border-l-2 border-gb-orange pl-2 my-1 text-gb-fg-s" />,
        p: ({ ...props }) => <span {...props} className="inline" />,
        img: ({ src, ...props }) => {
          const finalSrc = src?.startsWith("https://media") && src.includes(".giphy.com/")
            ? `/api/v1/gifs/proxy?url=${encodeURIComponent(src)}`
            : src;
          return (
            <img
              {...props}
              src={finalSrc}
              className="max-w-[240px] max-h-[240px] object-contain rounded my-1 block"
              loading="lazy"
            />
          );
        },
      }}
    >
      {content}
    </ReactMarkdown>
  );
}

const DMMessageItem = memo(({ msg }: { msg: ConversationMessage }) => {
  return (
    <div className="break-words">
      <span className="text-gb-fg-f">[{formatTime(msg.created_at)}]</span>{" "}
      <span className="text-gb-aqua">&lt;{msg.author_username}&gt;</span>{" "}
      <span className="text-gb-fg">{renderDMContent(msg.content)}</span>
    </div>
  );
});
DMMessageItem.displayName = "DMMessageItem";

export function DMChat() {
  const { conversationId } = useParams<{ conversationId: string }>();
  const activeId = useConversationStore((s) => s.activeConversationId);
  const setActive = useConversationStore((s) => s.setActiveConversation);
  const conversations = useConversationStore((s) => s.conversations);
  const messagesByConv = useConversationStore((s) => s.messagesByConversation);
  const fetchMessages = useConversationStore((s) => s.fetchMessages);
  const fetchOlderMessages = useConversationStore((s) => s.fetchOlderMessages);
  const isLoadingOlder = useConversationStore((s) => s.isLoadingOlder);
  const sendMessage = useConversationStore((s) => s.sendMessage);
  const fetchConversations = useConversationStore((s) => s.fetchConversations);
  const currentUser = useAuthStore((s) => s.user);
  const typingUsers = useTypingStore((s) => s.typingUsers);
  const sendTypingStart = useTypingStore((s) => s.sendTypingStart);
  const [input, setInput] = useState("");
  const [error, setError] = useState<string | null>(null);
  const bottomRef = useRef<HTMLDivElement>(null);
  const scrollContainerRef = useRef<HTMLDivElement>(null);
  const lastTypingRef = useRef<number>(0);

  const id = conversationId || activeId;
  const conversation = conversations.find((c) => c.id === id);

  const handleScroll = useCallback(() => {
    const el = scrollContainerRef.current;
    if (!el || !id || isLoadingOlder) return;
    if (el.scrollTop < 100) {
      const prevHeight = el.scrollHeight;
      fetchOlderMessages(id).then(() => {
        requestAnimationFrame(() => {
          el.scrollTop = el.scrollHeight - prevHeight;
        });
      });
    }
  }, [id, isLoadingOlder, fetchOlderMessages]);
  const messages = id ? messagesByConv[id] || [] : [];

  useEffect(() => {
    fetchConversations();
  }, [fetchConversations]);

  useEffect(() => {
    if (id) {
      setActive(id);
      fetchMessages(id);
      setError(null);
    }
  }, [id, setActive, fetchMessages]);

  useEffect(() => {
    bottomRef.current?.scrollIntoView({ behavior: "auto" });
  }, [messages]);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!id || !input.trim()) return;
    setError(null);
    try {
      await sendMessage(id, input.trim());
      setInput("");
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to send");
    }
  };

  const selfDM = conversation && conversation.members.length === 1 && conversation.members[0].id === currentUser?.id;
  const title = selfDM
    ? "Notes"
    : conversation
      ? conversation.type === "group_dm"
        ? conversation.name || conversation.members.map((m) => m.username).join(", ")
        : conversation.members.find((m) => m.id !== currentUser?.id)?.username || "DM"
      : id
        ? "[LOADING...]"
        : "[NO CONVERSATION]";

  return (
    <div className="flex flex-col h-full bg-gb-bg">
      <div className="terminal-border border-t-0 border-x-0 px-2 md:px-3 py-2 text-gb-fg-s flex items-center gap-2">
        <button
          type="button"
          onClick={() => useLayoutStore.getState().setMobileView('sidebar')}
          className="md:hidden terminal-button text-xs px-2 py-0.5 shrink-0"
        >
          ←
        </button>
        <span className="truncate">@ {title}</span>
      </div>
      <div ref={scrollContainerRef} onScroll={handleScroll} className="flex-1 overflow-y-auto p-3 space-y-1 font-mono text-sm">
        {isLoadingOlder && <p className="text-center text-gb-fg-f text-xs">[loading older messages...]</p>}
        {!id && <p className="text-gb-fg-f">[select a conversation]</p>}
        {id && messages.length === 0 && <p className="text-gb-fg-f">[no messages]</p>}
        {messages.map((msg: ConversationMessage) => (
          <DMMessageItem key={msg.id} msg={msg} />
        ))}
        <div ref={bottomRef} />
      </div>
      <div className="px-3 pt-1 text-xs text-gb-fg-f font-mono italic h-5 select-none">
        {(() => {
          const convTyping = id ? (typingUsers[id] || []).filter(u => u.userId !== currentUser?.id) : [];
          if (convTyping.length === 0) return "\u00A0";
          const names = convTyping.map(u => u.username);
          return names.length === 1 ? `${names[0]} is typing...` : names.length === 2 ? `${names[0]} and ${names[1]} are typing...` : `${names[0]} and ${names.length - 1} others are typing...`;
        })()}
      </div>
      {error && (
        <div className="px-3 pb-1">
          <p className="text-gb-red text-xs font-mono">ERR: {error}</p>
        </div>
      )}
      <form onSubmit={handleSubmit} className="p-3 flex items-center gap-2">
        <span className="text-gb-fg-f select-none shrink-0">{">"}</span>
        <input
          type="text"
          value={input}
          onChange={(e) => {
            setInput(e.target.value);
            if (id && e.target.value.length > 0) {
              const now = Date.now();
              if (now - lastTypingRef.current > 3000) {
                sendTypingStart(id);
                lastTypingRef.current = now;
              }
            }
          }}
          placeholder="type a message..."
          className="terminal-input w-full"
          disabled={!id}
        />
      </form>
    </div>
  );
}
