/**
 * SidebarMemberSection — the collapsible member list panel that sits below
 * channels in "channels" mode. Supports drag-to-resize and persists
 * collapsed state and height to localStorage.
 */

import { createElement, appendChildren } from "@lib/dom";
import type { MountableComponent } from "@lib/safe-render";
import { createMemberList } from "@components/MemberList";
import { authStore } from "@stores/auth.store";
import { setUserBlockedByMe } from "@stores/blocks.store";
import { getRoleIdByName } from "@stores/channels.store";
import type { ApiClient } from "@lib/api";
import type { ToastContainer } from "@components/Toast";

// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------

const LS_KEY_HEIGHT = "owncord:member-list-height";
const LS_KEY_COLLAPSED = "owncord:member-list-collapsed";

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

export interface SidebarMemberSectionOptions {
  readonly api: ApiClient;
  readonly getToast: () => ToastContainer | null;
  /** Start a DM with a user (profile popup's Message button). */
  readonly onMessageUser?: (userId: number) => void;
}

export interface SidebarMemberSectionResult {
  /** The root element to insert into the DOM. */
  readonly element: HTMLDivElement;
  /** The member list MountableComponent (for external cleanup tracking). */
  readonly memberListComponent: MountableComponent;
  /** Clean up event listeners and abort controller. */
  readonly destroy: () => void;
}

// ---------------------------------------------------------------------------
// Factory
// ---------------------------------------------------------------------------

export function createSidebarMemberSection(
  opts: SidebarMemberSectionOptions,
): SidebarMemberSectionResult {
  const { api, getToast, onMessageUser } = opts;
  const unsubs: Array<() => void> = [];

  // --- Container ---
  const memberListContainer = createElement("div", {
    class: "sidebar-members-section",
    "data-testid": "sidebar-members",
  });

  // --- Header ---
  const memberHeader = createElement("div", { class: "category sidebar-members-header" });
  const memberArrow = createElement("span", { class: "category-arrow" }, "\u25BC");
  const memberLabelEl = createElement("span", { class: "category-name" }, "MEMBERS");
  appendChildren(memberHeader, memberArrow, memberLabelEl);
  memberListContainer.appendChild(memberHeader);

  // --- Resize handle ---
  const resizeHandle = createElement("div", { class: "sidebar-resize-handle" });
  memberListContainer.appendChild(resizeHandle);

  // Restore saved height
  const savedHeight = localStorage.getItem(LS_KEY_HEIGHT);
  if (savedHeight !== null) {
    memberListContainer.style.height = `${savedHeight}px`;
  }

  // --- Drag-to-resize logic ---
  const resizeAbort = new AbortController();
  let isDragging = false;
  let startY = 0;
  let startHeight = 0;

  resizeHandle.addEventListener(
    "mousedown",
    (e: MouseEvent) => {
      isDragging = true;
      startY = e.clientY;
      startHeight = memberListContainer.offsetHeight;
      e.preventDefault();
    },
    { signal: resizeAbort.signal },
  );

  document.addEventListener(
    "mousemove",
    (e: MouseEvent) => {
      if (!isDragging) return;
      const delta = startY - e.clientY;
      const maxH = window.innerHeight * 0.65;
      const newHeight = Math.max(80, Math.min(startHeight + delta, maxH));
      memberListContainer.style.height = `${newHeight}px`;
    },
    { signal: resizeAbort.signal },
  );

  document.addEventListener(
    "mouseup",
    () => {
      if (!isDragging) return;
      isDragging = false;
      localStorage.setItem(LS_KEY_HEIGHT, String(memberListContainer.offsetHeight));
    },
    { signal: resizeAbort.signal },
  );

  unsubs.push(() => {
    resizeAbort.abort();
  });

  // --- Collapse state ---
  const savedCollapsed = localStorage.getItem(LS_KEY_COLLAPSED);
  let membersCollapsed = savedCollapsed === "true";
  const memberContent = createElement("div", { class: "sidebar-members-content" });

  function applyMembersCollapsed(): void {
    memberHeader.classList.toggle("collapsed", membersCollapsed);
    memberArrow.textContent = membersCollapsed ? "\u25B6" : "\u25BC";
    memberContent.style.display = membersCollapsed ? "none" : "";
    resizeHandle.style.display = membersCollapsed ? "none" : "";
    if (membersCollapsed) {
      memberListContainer.style.height = "auto";
    } else {
      const h = localStorage.getItem(LS_KEY_HEIGHT);
      if (h !== null) {
        memberListContainer.style.height = `${h}px`;
      } else {
        memberListContainer.style.height = "";
      }
    }
  }

  // Apply initial state
  applyMembersCollapsed();

  memberHeader.addEventListener("click", () => {
    membersCollapsed = !membersCollapsed;
    localStorage.setItem(LS_KEY_COLLAPSED, String(membersCollapsed));
    applyMembersCollapsed();
  });

  // --- Member list component ---
  const memberList = createMemberList({
    currentUserRole: authStore.getState().user?.role ?? "member",
    ...(onMessageUser !== undefined ? { onMessageUser } : {}),
    // "Force Logout", not "Kick": the endpoint revokes the target's sessions
    // and nothing stops them signing back in — there is no membership to remove.
    onKick: async (userId, username) => {
      try {
        await api.adminKickMember(userId);
        getToast()?.show(`Forced ${username} to log out`, "success");
      } catch (err) {
        const msg = err instanceof Error ? err.message : "Failed to force logout";
        getToast()?.show(msg, "error");
      }
    },
    onBan: async (userId, username, reason, durationHours) => {
      try {
        await api.adminBanMember(userId, reason, durationHours);
        getToast()?.show(
          durationHours > 0 ? `Banned ${username} for ${durationHours}h` : `Banned ${username}`,
          "success",
        );
      } catch (err) {
        const msg = err instanceof Error ? err.message : "Failed to ban member";
        getToast()?.show(msg, "error");
      }
    },
    onToggleBlock: async (userId, username, block) => {
      try {
        if (block) {
          await api.blockUser(userId);
        } else {
          await api.unblockUser(userId);
        }
        setUserBlockedByMe(userId, block);
        getToast()?.show(block ? `Blocked ${username}` : `Unblocked ${username}`, "success");
      } catch (err) {
        const fallback = block ? "Failed to block user" : "Failed to unblock user";
        const msg = err instanceof Error ? err.message : fallback;
        getToast()?.show(msg, "error");
      }
    },
    onChangeRole: async (userId, username, newRole) => {
      const roleId = getRoleIdByName(newRole);
      if (roleId === undefined) {
        // No silent failures: the role vanished from the server's list.
        getToast()?.show(`Unknown role "${newRole}" — try reconnecting`, "error");
        return;
      }
      try {
        await api.adminChangeRole(userId, roleId);
        getToast()?.show(`Changed ${username}'s role to ${newRole}`, "success");
      } catch (err) {
        const msg = err instanceof Error ? err.message : "Failed to change role";
        getToast()?.show(msg, "error");
      }
    },
  });
  memberList.mount(memberContent);
  memberListContainer.appendChild(memberContent);

  return {
    element: memberListContainer,
    memberListComponent: memberList,
    destroy: () => {
      for (const unsub of unsubs) {
        unsub();
      }
    },
  };
}
