import { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { FiTrash2, FiCornerUpLeft, FiSmile, FiMoreVertical, FiX } from "react-icons/fi";
import type { Message as MessageModel } from "@/api/generated/private/models/message";
import type { Chat } from "@/api/generated/private/models/chat";
import ChatMediaGallery from "@/components/social/chat/ChatMediaGallery";
import EmojiPicker from "@/components/social/EmojiPicker";
import Avatar from "@/components/ui/Avatar";
import IconButton from "@/components/ui/IconButton";
import { useAuth } from "@/hooks/useAuth";
import { canDeleteMessage } from "@/hooks/usePermissions";
import { formatRelative } from "@/utils/relativeTime";
import { mediaUrl } from "@/utils/mediaUrl";
import { apiSocialMessagesDestroy } from "@/api/generated/private/chat/chat";

type MemberInfo = { id: number; username: string; avatar: string | null };
type ReplyMedia = { id: number; file: string; media_type: string };
type ExtendedReply = { id: number; content?: string; sender?: MemberInfo; created_at?: string; media_files?: ReplyMedia[] };

interface Props {
  message: MessageModel;
  chat: Chat | null;
  onReply?: (message: MessageModel) => void;
  onReact?: (message: MessageModel, emoji: string) => void;
  highlighted?: boolean;
  onScrollToMessage?: (messageId: number) => void;
}

export default function Message({ message, chat, onReply, onReact, highlighted, onScrollToMessage }: Props) {
  const { t } = useTranslation("social");
  const { user } = useAuth();
  const [menuOpen, setMenuOpen] = useState(false);
  const [pickerOpen, setPickerOpen] = useState(false);
  const menuRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!menuOpen) return;
    function handleOutside(e: MouseEvent) {
      if (menuRef.current && !menuRef.current.contains(e.target as Node)) {
        setMenuOpen(false);
        setPickerOpen(false);
      }
    }
    document.addEventListener("mousedown", handleOutside);
    return () => document.removeEventListener("mousedown", handleOutside);
  }, [menuOpen]);

  const sender = message.sender as { id: number; username: string; avatar: string | null } | null;
  const isOwn = user?.id != null && sender?.id === user.id;

  async function handleDelete() {
    if (!confirm("Smazat zprávu?")) return;
    await apiSocialMessagesDestroy(String(message.id));
  }

  const canDelete = canDeleteMessage(user, message, chat);
  const replyTo = message.reply_to;
  const replyDeleted = replyTo != null && replyTo.content == null;

  function handleJump() {
    if (replyTo && !replyDeleted) onScrollToMessage?.(replyTo.id);
  }

  const hasMedia = (message.media_files?.length ?? 0) > 0;
  const hasText = !!message.content;

  // Build a username/avatar lookup from the chat member list (members_detail is
  // returned by the API but not yet in the generated type, so we cast).
  const membersMap = (
    (chat as unknown as { members_detail?: MemberInfo[] })?.members_detail ?? []
  ).reduce<Record<number, MemberInfo>>((acc, m) => { acc[m.id] = m; return acc; }, {});
  if (user != null) {
    membersMap[user.id] ??= { id: user.id, username: user.username, avatar: user.avatar ?? null };
  }

  // Group reactions by emoji { "👍": { count, mine, reactors } }
  const reactionGroups = (message.reactions ?? []).reduce<
    Record<string, { count: number; mine: boolean; reactors: MemberInfo[] }>
  >(
    (acc, r) => {
      const emoji = r.emoji;
      const userId = r.user as unknown as number;
      if (!acc[emoji]) acc[emoji] = { count: 0, mine: false, reactors: [] };
      acc[emoji].count++;
      if (userId === user?.id) acc[emoji].mine = true;
      acc[emoji].reactors.push(membersMap[userId] ?? { id: userId, username: `User ${userId}`, avatar: null });
      return acc;
    },
    {},
  );

  return (
    <div
      id={`msg-${message.id}`}
      className={[
        "group flex items-end gap-2 px-4 py-1.5",
        isOwn ? "flex-row-reverse" : "",
      ].join(" ")}
    >
      {/* Avatar */}
      <div className="shrink-0 self-start mt-1">
        <Avatar name={sender?.username} src={sender?.avatar} size={28} />
      </div>

      {/* Message body column: reply → bubble → timestamp → reactions */}
      <div
        className={[
          "flex min-w-0 max-w-[70%] flex-col gap-0.5",
          isOwn ? "items-end" : "items-start",
        ].join(" ")}
      >
        {/* Reply preview */}
        {replyTo && (() => {
          const ext = replyTo as unknown as ExtendedReply;
          const firstMedia = ext.media_files?.[0];
          return (
            <div
              role={replyDeleted ? undefined : "button"}
              tabIndex={replyDeleted ? undefined : 0}
              onClick={replyDeleted ? undefined : handleJump}
              onKeyDown={replyDeleted ? undefined : (e) => e.key === "Enter" && handleJump()}
              className={[
                "max-w-[260px] select-none rounded-lg border-l-2 px-3 py-1.5 opacity-50 transition-opacity hover:opacity-90",
                replyDeleted ? "cursor-default" : "cursor-pointer",
                isOwn
                  ? "border-white/30 bg-brand-lines/10"
                  : "border-brand-accent/40 bg-brand-lines/10",
              ].join(" ")}
            >
              {replyDeleted ? (
                <span className="text-xs italic text-brand-text/40">{t("chat.room.deletedMessage")}</span>
              ) : (
                <>
                  {/* Sender + time */}
                  <div className="flex items-center gap-1.5 mb-0.5">
                    <span className="text-xs font-semibold text-brand-accent/80 truncate">
                      {replyTo.sender?.username ?? "…"}
                    </span>
                    {ext.created_at && (
                      <span className="shrink-0 text-[10px] text-brand-text/40">
                        · {formatRelative(ext.created_at)}
                      </span>
                    )}
                  </div>
                  {/* Content: thumbnail + text */}
                  <div className="flex items-center gap-1.5">
                    {firstMedia?.media_type === "IMAGE" && (
                      <img
                        src={mediaUrl(firstMedia.file) ?? undefined}
                        className="h-8 w-8 shrink-0 rounded object-cover opacity-80"
                        alt=""
                      />
                    )}
                    {firstMedia && firstMedia.media_type !== "IMAGE" && (
                      <span className="shrink-0 text-[11px] text-brand-text/50">📎</span>
                    )}
                    <span className="truncate text-xs italic text-brand-text/50">
                      {replyTo.content
                        ? replyTo.content.slice(0, 80)
                        : firstMedia
                          ? firstMedia.media_type === "IMAGE" ? "Fotka" : "Soubor"
                          : "…"}
                    </span>
                  </div>
                </>
              )}
            </div>
          );
        })()}

        {/* Bubble */}
        <div
          className={[
            "w-fit overflow-hidden rounded-2xl text-sm",
            highlighted ? "msg-flash" : "",
            !hasMedia ? "max-w-full wrap-break-word whitespace-pre-wrap" : "max-w-xs",
            hasText ? "glass" : "",
            hasText && !hasMedia ? "px-3 py-2" : "",
            hasText &&  hasMedia ? "px-3 pt-2 pb-0" : "",
            isOwn
              ? `rounded-br-sm ${hasText ? "bg-brand-accent text-brand-bg" : ""}`
              : `rounded-bl-sm ${hasText ? "bg-brand-bgLight/70 text-brand-text" : ""}`,
          ].join(" ")}
        >
          {hasText && <p className="wrap-break-word whitespace-pre-wrap">{message.content}</p>}
          {hasMedia && (
            <div className={hasText ? "-mx-3 mt-2" : ""}>
              <ChatMediaGallery files={message.media_files} />
            </div>
          )}
        </div>

        {/* Timestamp */}
        <div className="flex items-center gap-2 text-[11px] text-brand-text/50">
          <time dateTime={String(message.created_at)}>{formatRelative(message.created_at)}</time>
          {message.is_edited && <span>· {t("chat.room.edited")}</span>}
        </div>

        {/* Reactions */}
        {Object.keys(reactionGroups).length > 0 && (
          <div className={["flex flex-wrap gap-1", isOwn ? "justify-end" : ""].join(" ")}>
            {Object.entries(reactionGroups).map(([emoji, { count, mine }]) => (
              <ReactionPill
                key={emoji}
                emoji={emoji}
                count={count}
                mine={mine}
                allGroups={reactionGroups}
                currentUserId={user?.id}
                isOwn={isOwn}
                onRemove={(ej) => onReact?.(message, ej)}
              />
            ))}
          </div>
        )}
      </div>

      {/* ⋮ trigger — always sits directly next to the bubble */}
      <div
        ref={menuRef}
        className={[
          hasMedia ? "self-center" : "self-start mt-1",
          "relative flex shrink-0 items-center",
          isOwn ? "flex-row-reverse" : "",
          menuOpen ? "opacity-100" : "opacity-0 group-hover:opacity-100",
          "transition-opacity",
        ].join(" ")}
      >
        {/* Emoji picker */}
        {pickerOpen && (
          <EmojiPicker
            className={["absolute bottom-full mb-2 z-20", isOwn ? "right-0" : "left-0"].join(" ")}
            onSelect={(emoji) => { onReact?.(message, emoji); }}
            onClose={() => setPickerOpen(false)}
          />
        )}

        {/* Actions slide out away from the bubble */}
        <div
          className={[
            "flex items-center gap-0.5 overflow-hidden transition-[max-width] duration-200 ease-out",
            isOwn ? "flex-row-reverse" : "",
            menuOpen ? "max-w-32" : "max-w-0",
          ].join(" ")}
        >
          <IconButton
            icon={<FiCornerUpLeft size={14} />}
            label={t("chat.actions.reply")}
            onClick={() => { onReply?.(message); setMenuOpen(false); }}
          />
          <IconButton
            icon={<FiSmile size={14} />}
            label={t("chat.actions.react")}
            onClick={() => setPickerOpen((v) => !v)}
          />
          {canDelete && (
            <IconButton
              icon={<FiTrash2 size={14} />}
              label={t("chat.actions.delete")}
              onClick={() => { setMenuOpen(false); void handleDelete(); }}
            />
          )}
        </div>

        {/* Toggle ⋮ / ✕ */}
        <button
          onClick={() => { setMenuOpen((v) => !v); if (menuOpen) setPickerOpen(false); }}
          className="relative flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-brand-text/60 hover:bg-brand-lines/20 hover:text-brand-text transition-colors"
          aria-label="Akce"
        >
          <FiMoreVertical
            size={16}
            className={["absolute transition-all duration-200", menuOpen ? "opacity-0 scale-0 rotate-90" : "opacity-100 scale-100 rotate-0"].join(" ")}
          />
          <FiX
            size={16}
            className={["absolute transition-all duration-200", menuOpen ? "opacity-100 scale-100 rotate-0" : "opacity-0 scale-0 -rotate-90"].join(" ")}
          />
        </button>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// ReactionPill — self-contained pill + tabbed who-reacted popover
// ---------------------------------------------------------------------------

type AllReactor = MemberInfo & { reactionEmoji: string };

interface ReactionPillProps {
  emoji: string;
  count: number;
  mine: boolean;
  allGroups: Record<string, { count: number; mine: boolean; reactors: MemberInfo[] }>;
  currentUserId?: number;
  isOwn: boolean;
  onRemove: (emoji: string) => void;
}

function ReactionPill({ emoji, count, mine, allGroups, currentUserId, isOwn, onRemove }: ReactionPillProps) {
  const [open, setOpen] = useState(false);
  const [activeTab, setActiveTab] = useState<string>("all");
  const wrapperRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!open) return;
    function handleOutside(e: MouseEvent) {
      if (wrapperRef.current && !wrapperRef.current.contains(e.target as Node)) {
        setOpen(false);
      }
    }
    document.addEventListener("mousedown", handleOutside);
    return () => document.removeEventListener("mousedown", handleOutside);
  }, [open]);

  function handleToggle() {
    if (!open) {
      setActiveTab(emoji);
      setOpen(true);
    } else {
      setOpen(false);
    }
  }

  const emojiTabs = Object.keys(allGroups);

  const allReactors: AllReactor[] = emojiTabs.flatMap((ej) =>
    allGroups[ej].reactors.map((r) => ({ ...r, reactionEmoji: ej })),
  );

  const displayReactors: AllReactor[] =
    activeTab === "all"
      ? allReactors
      : (allGroups[activeTab]?.reactors ?? []).map((r) => ({ ...r, reactionEmoji: activeTab }));

  return (
    <div ref={wrapperRef} className="relative">
      {open && (
        <div
          className={[
            "absolute bottom-full mb-1.5 z-30 w-72 rounded-2xl border border-brand-lines/20 bg-brand-bgLight shadow-2xl",
            isOwn ? "right-0" : "left-0",
          ].join(" ")}
        >
          {/* Tab bar */}
          <div className="flex items-center gap-0.5 overflow-x-auto border-b border-brand-lines/15 px-3 pt-2.5 pb-2 scrollbar-none">
            <button
              type="button"
              onClick={() => setActiveTab("all")}
              className={[
                "shrink-0 rounded-lg px-2.5 py-1 text-xs font-medium transition-colors",
                activeTab === "all"
                  ? "bg-brand-accent/20 text-brand-accent"
                  : "text-brand-text/50 hover:bg-brand-lines/10 hover:text-brand-text/80",
              ].join(" ")}
            >
              Vše <span className="opacity-60">{allReactors.length}</span>
            </button>
            {emojiTabs.map((ej) => (
              <button
                key={ej}
                type="button"
                onClick={() => setActiveTab(ej)}
                className={[
                  "flex shrink-0 items-center gap-1 rounded-lg px-2.5 py-1 text-xs transition-colors",
                  activeTab === ej
                    ? "bg-brand-accent/20 text-brand-accent"
                    : "text-brand-text/50 hover:bg-brand-lines/10 hover:text-brand-text/80",
                ].join(" ")}
              >
                <span>{ej}</span>
                <span className="opacity-60">{allGroups[ej].count}</span>
              </button>
            ))}
          </div>

          {/* Reactor list */}
          <ul className="max-h-56 overflow-y-auto py-1.5">
            {displayReactors.map((r) => {
              const isMe = r.id === currentUserId;
              return (
                <li key={`${r.id}-${r.reactionEmoji}`}>
                  {isMe ? (
                    <button
                      type="button"
                      onClick={() => { onRemove(r.reactionEmoji); setOpen(false); }}
                      className="flex w-full flex-col px-4 py-2.5 text-left transition-colors hover:bg-brand-lines/10"
                    >
                      <div className="flex items-center gap-3">
                        <Avatar name={r.username} src={r.avatar} size={24} />
                        <span className="flex-1 text-sm font-medium text-brand-text">{r.username}</span>
                        {activeTab === "all" && <span className="text-base leading-none">{r.reactionEmoji}</span>}
                      </div>
                      <span className="mt-1 pl-[36px] text-[10px] text-brand-text/40">Klikni pro odebrání reakce</span>
                    </button>
                  ) : (
                    <div className="flex items-center gap-3 px-4 py-2.5">
                      <Avatar name={r.username} src={r.avatar} size={24} />
                      <span className="flex-1 text-sm text-brand-text/80">{r.username}</span>
                      {activeTab === "all" && <span className="text-base leading-none">{r.reactionEmoji}</span>}
                    </div>
                  )}
                </li>
              );
            })}
          </ul>
        </div>
      )}
      <button
        type="button"
        onClick={handleToggle}
        className={[
          "flex items-center gap-1 rounded-full px-2 py-0.5 text-xs transition-colors",
          mine
            ? "bg-brand-accent/20 border border-brand-accent/50 text-brand-accent"
            : "bg-brand-bgLight/60 border border-transparent hover:border-brand-lines/30 text-brand-text/80",
        ].join(" ")}
      >
        <span>{emoji}</span>
        {count > 1 && <span>{count}</span>}
      </button>
    </div>
  );
}
