import { useEffect, useMemo, useState } from "react";
import { createPortal } from "react-dom";
import {
  addChatMember,
  getChatNotificationSettings,
  getChatDetail,
  leaveChat,
  listChatMembers,
  removeChatMember,
  updateChatNotificationSettings,
  updateChatMemberRole,
  updateChatTitle
} from "../api/chats";
import { blockUser, getUserById, listBlockedUsers, searchUsers, unblockUser } from "../api/users";
import type { AuthUser, ChatDetail, ChatMember, UserSearchItem } from "../chat/types";
import { useAuthStore } from "../store/authStore";
import { useChatStore } from "../store/chatStore";

interface Props {
  chatId: number | null;
  open: boolean;
  onClose: () => void;
}

export function ChatInfoPanel({ chatId, open, onClose }: Props) {
  const me = useAuthStore((s) => s.me);
  const loadChats = useChatStore((s) => s.loadChats);
  const setActiveChatId = useChatStore((s) => s.setActiveChatId);
  const [chat, setChat] = useState<ChatDetail | null>(null);
  const [members, setMembers] = useState<ChatMember[]>([]);
  const [memberUsers, setMemberUsers] = useState<Record<number, AuthUser>>({});
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [titleDraft, setTitleDraft] = useState("");
  const [savingTitle, setSavingTitle] = useState(false);
  const [searchQuery, setSearchQuery] = useState("");
  const [searchResults, setSearchResults] = useState<UserSearchItem[]>([]);
  const [muted, setMuted] = useState(false);
  const [savingMute, setSavingMute] = useState(false);
  const [counterpartBlocked, setCounterpartBlocked] = useState(false);
  const [savingBlock, setSavingBlock] = useState(false);

  const myRole = useMemo(() => members.find((m) => m.user_id === me?.id)?.role, [members, me?.id]);
  const isGroupLike = chat?.type === "group" || chat?.type === "channel";
  const showMembersSection = Boolean(chat && isGroupLike && !chat.is_saved);
  const canManageMembers = Boolean(isGroupLike && (myRole === "owner" || myRole === "admin"));
  const canChangeRoles = Boolean(isGroupLike && myRole === "owner");

  async function refreshMembers(targetChatId: number) {
    const nextMembers = await listChatMembers(targetChatId);
    setMembers(nextMembers);
    const ids = [...new Set(nextMembers.map((m) => m.user_id))];
    const profiles = await Promise.all(ids.map((id) => getUserById(id)));
    const byId: Record<number, AuthUser> = {};
    for (const profile of profiles) {
      byId[profile.id] = profile;
    }
    setMemberUsers(byId);
  }

  useEffect(() => {
    if (!open || !chatId) {
      return;
    }
    let cancelled = false;
    setLoading(true);
    setError(null);
    void (async () => {
      try {
        const detail = await getChatDetail(chatId);
        if (cancelled) return;
        setChat(detail);
        setTitleDraft(detail.title ?? "");
        const notificationSettings = await getChatNotificationSettings(chatId);
        if (!cancelled) {
          setMuted(notificationSettings.muted);
        }
        if (detail.type === "private" && !detail.is_saved && detail.counterpart_user_id) {
          const blocked = await listBlockedUsers();
          if (!cancelled) {
            setCounterpartBlocked(blocked.some((u) => u.id === detail.counterpart_user_id));
          }
        } else if (!cancelled) {
          setCounterpartBlocked(false);
        }
        await refreshMembers(chatId);
      } catch {
        if (!cancelled) setError("Failed to load chat info");
      } finally {
        if (!cancelled) setLoading(false);
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [open, chatId]);

  useEffect(() => {
    const onKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        onClose();
      }
    };
    if (open) {
      window.addEventListener("keydown", onKeyDown);
    }
    return () => window.removeEventListener("keydown", onKeyDown);
  }, [open, onClose]);

  if (!open || !chatId) {
    return null;
  }

  return createPortal(
    <div className="fixed inset-0 z-[120] bg-slate-950/55" onClick={onClose}>
      <aside className="absolute right-0 top-0 h-full w-full max-w-sm border-l border-slate-700/70 bg-slate-900/95 p-4 shadow-2xl" onClick={(e) => e.stopPropagation()}>
        <div className="mb-3 flex items-center justify-between">
          <p className="text-sm font-semibold">Chat info</p>
          <button className="rounded bg-slate-700 px-2 py-1 text-xs" onClick={onClose}>Close</button>
        </div>

        {loading ? <p className="text-sm text-slate-300">Loading...</p> : null}
        {error ? <p className="text-sm text-red-400">{error}</p> : null}

        {chat ? (
          <>
            <div className="mb-3 rounded-lg border border-slate-700/70 bg-slate-800/60 p-3">
              <div className="mb-2 flex items-center justify-between">
                <p className="text-xs text-slate-400">Notifications</p>
                <button
                  className="rounded bg-slate-700 px-2 py-1 text-xs disabled:opacity-60"
                  disabled={savingMute}
                  onClick={async () => {
                    setSavingMute(true);
                    try {
                      const updated = await updateChatNotificationSettings(chatId, !muted);
                      setMuted(updated.muted);
                    } catch {
                      setError("Failed to update notifications");
                    } finally {
                      setSavingMute(false);
                    }
                  }}
                >
                  {muted ? "Unmute" : "Mute"}
                </button>
              </div>
              <p className="mb-2 text-xs text-slate-300">{muted ? "Chat notifications are muted." : "Chat notifications are enabled."}</p>
              <p className="text-xs text-slate-400">Type</p>
              <p className="text-sm">{chat.type}</p>
              <p className="mt-2 text-xs text-slate-400">Title</p>
              <input
                className="mt-1 w-full rounded bg-slate-800 px-3 py-2 text-sm outline-none"
                disabled={!isGroupLike}
                value={titleDraft}
                onChange={(e) => setTitleDraft(e.target.value)}
              />
              {isGroupLike ? (
                <button
                  className="mt-2 w-full rounded bg-sky-500 px-3 py-2 text-sm font-semibold text-slate-950 disabled:opacity-60"
                  disabled={savingTitle || !titleDraft.trim()}
                  onClick={async () => {
                    setSavingTitle(true);
                    try {
                      const updated = await updateChatTitle(chatId, titleDraft.trim());
                      setChat((prev) => (prev ? { ...prev, ...updated } : prev));
                      await loadChats();
                    } catch {
                      setError("Failed to update title");
                    } finally {
                      setSavingTitle(false);
                    }
                  }}
                >
                  Save title
                </button>
              ) : null}
              {chat.handle ? <p className="mt-2 text-xs text-slate-300">@{chat.handle}</p> : null}
              {chat.description ? <p className="mt-1 text-xs text-slate-400">{chat.description}</p> : null}
            </div>

            {showMembersSection ? (
              <div className="mb-3 rounded-lg border border-slate-700/70 bg-slate-800/60 p-3">
                <p className="mb-2 text-xs font-semibold uppercase tracking-wide text-slate-300">Members ({members.length})</p>
                <div className="tg-scrollbar max-h-56 space-y-2 overflow-auto">
                  {members.map((member) => {
                    const user = memberUsers[member.user_id];
                    return (
                      <div className="rounded border border-slate-700/60 bg-slate-900/60 p-2" key={member.id}>
                        <p className="truncate text-sm font-semibold">{user?.name || `user #${member.user_id}`}</p>
                        <p className="truncate text-xs text-slate-400">@{user?.username || "unknown"}</p>
                        <div className="mt-2 flex items-center gap-2">
                          <select
                            className="flex-1 rounded bg-slate-800 px-2 py-1 text-xs"
                            disabled={!canChangeRoles || member.user_id === me?.id}
                            value={member.role}
                            onChange={async (e) => {
                              try {
                                await updateChatMemberRole(chatId, member.user_id, e.target.value as ChatMember["role"]);
                                await refreshMembers(chatId);
                              } catch {
                                setError("Failed to update role");
                              }
                            }}
                          >
                            <option value="member">member</option>
                            <option value="admin">admin</option>
                            <option value="owner">owner</option>
                          </select>
                          {canManageMembers && member.user_id !== me?.id ? (
                            <button
                              className="rounded bg-red-500 px-2 py-1 text-xs font-semibold text-white"
                              onClick={async () => {
                                try {
                                  await removeChatMember(chatId, member.user_id);
                                  await refreshMembers(chatId);
                                } catch {
                                  setError("Failed to remove member");
                                }
                              }}
                            >
                              Remove
                            </button>
                          ) : null}
                        </div>
                      </div>
                    );
                  })}
                </div>
              </div>
            ) : (
              <div className="mb-3 rounded-lg border border-slate-700/70 bg-slate-800/60 p-3">
                {chat.is_saved ? (
                  <p className="text-sm text-slate-300">Saved Messages is your personal cloud chat.</p>
                ) : chat.type === "private" ? (
                  <p className="text-sm text-slate-300">
                    {chat.counterpart_is_online
                      ? "User is online"
                      : chat.counterpart_last_seen_at
                        ? `Last seen ${formatLastSeen(chat.counterpart_last_seen_at)}`
                        : "User is offline"}
                  </p>
                ) : (
                  <p className="text-sm text-slate-300">No extra information.</p>
                )}
              </div>
            )}

            {showMembersSection && canManageMembers ? (
              <div className="mb-3 rounded-lg border border-slate-700/70 bg-slate-800/60 p-3">
                <p className="mb-2 text-xs font-semibold uppercase tracking-wide text-slate-300">Add member</p>
                <input
                  className="mb-2 w-full rounded bg-slate-800 px-3 py-2 text-sm outline-none"
                  placeholder="@username"
                  value={searchQuery}
                  onChange={async (e) => {
                    const value = e.target.value;
                    setSearchQuery(value);
                    if (value.trim().replace("@", "").length < 2) {
                      setSearchResults([]);
                      return;
                    }
                    try {
                      const users = await searchUsers(value);
                      setSearchResults(users.filter((u) => !members.some((m) => m.user_id === u.id)));
                    } catch {
                      setError("Failed to search users");
                    }
                  }}
                />
                <div className="tg-scrollbar max-h-40 space-y-1 overflow-auto">
                  {searchResults.map((user) => (
                    <button
                      className="block w-full rounded bg-slate-900/70 px-3 py-2 text-left text-sm hover:bg-slate-700"
                      key={user.id}
                      onClick={async () => {
                        try {
                          await addChatMember(chatId, user.id);
                          setSearchQuery("");
                          setSearchResults([]);
                          await refreshMembers(chatId);
                        } catch {
                          setError("Failed to add member");
                        }
                      }}
                    >
                      <p className="truncate font-semibold">{user.name}</p>
                      <p className="truncate text-xs text-slate-400">@{user.username}</p>
                    </button>
                  ))}
                </div>
              </div>
            ) : null}

            {chat.type === "private" && !chat.is_saved && chat.counterpart_user_id ? (
              <button
                className="mb-3 w-full rounded bg-slate-700 px-3 py-2 text-sm disabled:opacity-60"
                disabled={savingBlock}
                onClick={async () => {
                  setSavingBlock(true);
                  try {
                    if (counterpartBlocked) {
                      await unblockUser(chat.counterpart_user_id!);
                      setCounterpartBlocked(false);
                    } else {
                      await blockUser(chat.counterpart_user_id!);
                      setCounterpartBlocked(true);
                    }
                  } catch {
                    setError("Failed to update block status");
                  } finally {
                    setSavingBlock(false);
                  }
                }}
              >
                {counterpartBlocked ? "Unblock user" : "Block user"}
              </button>
            ) : null}

            {showMembersSection && (chat.type === "group" || chat.type === "channel") ? (
              <button
                className="w-full rounded bg-slate-700 px-3 py-2 text-sm"
                onClick={async () => {
                  try {
                    await leaveChat(chatId);
                    await loadChats();
                    setActiveChatId(null);
                    onClose();
                  } catch {
                    setError("Failed to leave chat");
                  }
                }}
              >
                Leave chat
              </button>
            ) : null}
          </>
        ) : null}
      </aside>
    </div>,
    document.body
  );
}

function formatLastSeen(value: string): string {
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) {
    return "recently";
  }
  return date.toLocaleString(undefined, {
    day: "2-digit",
    month: "short",
    hour: "2-digit",
    minute: "2-digit"
  });
}
