"use client";

import Link from "next/link";
import { usePathname } from "next/navigation";
import { useEffect, useMemo, useRef, useState, type ReactNode } from "react";
import { createPortal } from "react-dom";
import { avatarColor } from "../lib/avatar";
import {
  channelPath,
  dmChannelByUserId,
  dmChannels,
  dmTitle,
  isDmChannel,
  textChannels,
  type ConversationRow,
} from "../lib/conversations";
import { useUnreadCounts } from "../lib/unread-store";
import { BrandMark, BrandWord, IconChevron, IconLock, IconPlus, IconSearch, IconVideo } from "./icons";
import { UserAvatar } from "./UserAvatar";

export interface SidebarMember {
  member: {
    role: string;
    deactivatedAt?: string | null;
    statusText?: string | null;
    statusEmoji?: string | null;
    statusExpiresAt?: string | null;
    statusSource?: string | null;
    dndActive?: boolean;
  };
  user: { id: string | number; name: string; email: string; avatarUrl?: string | null };
}

export type SidebarActive = "tasks" | "calendar" | "calls" | "rooms" | "people" | "settings" | "search" | "chat";
export type SidebarVariant = "workspace" | "chat";
export type ChatFilter = "all" | "dms" | "rooms" | "unread";

const PIN_KEY = "voxi.chat.pins.v1";

function statusExpiryLabel(expiresAt?: string | null, source?: string | null) {
  if (!expiresAt) return source && source !== "manual" ? "Updates automatically" : "No expiration";
  const expiry = new Date(expiresAt);
  if (Number.isNaN(expiry.getTime())) return "";
  const now = new Date();
  const tomorrow = new Date(now);
  tomorrow.setDate(now.getDate() + 1);
  const sameDay = (left: Date, right: Date) =>
    left.getFullYear() === right.getFullYear()
    && left.getMonth() === right.getMonth()
    && left.getDate() === right.getDate();
  const time = expiry.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" });
  if (sameDay(expiry, now)) return `Until ${time}`;
  if (sameDay(expiry, tomorrow)) return `Until tomorrow at ${time}`;
  return `Until ${expiry.toLocaleDateString([], { month: "short", day: "numeric" })} at ${time}`;
}

function StatusBadge({ member }: { member: SidebarMember["member"] }) {
  const badgeRef = useRef<HTMLSpanElement>(null);
  const hoverTimerRef = useRef<number | null>(null);
  const [position, setPosition] = useState<{ left: number; top: number } | null>(null);

  useEffect(() => () => {
    if (hoverTimerRef.current != null) window.clearTimeout(hoverTimerRef.current);
  }, []);

  if (!member.statusEmoji || !member.statusText) return null;

  function showTooltip() {
    if (hoverTimerRef.current != null) window.clearTimeout(hoverTimerRef.current);
    hoverTimerRef.current = window.setTimeout(() => {
      const rect = badgeRef.current?.getBoundingClientRect();
      if (!rect) return;
      setPosition({
        left: Math.max(92, Math.min(window.innerWidth - 92, rect.left + rect.width / 2)),
        top: rect.top - 9,
      });
    }, 180);
  }

  function hideTooltip() {
    if (hoverTimerRef.current != null) window.clearTimeout(hoverTimerRef.current);
    hoverTimerRef.current = null;
    setPosition(null);
  }

  return (
    <>
      <span
        ref={badgeRef}
        className="sidebar-status-emoji"
        aria-label={`${member.statusText}. ${statusExpiryLabel(member.statusExpiresAt, member.statusSource)}`}
        onPointerEnter={showTooltip}
        onPointerLeave={hideTooltip}
      >
        {member.statusEmoji}
      </span>
      {position && createPortal(
        <span className="sidebar-status-tooltip" role="tooltip" style={{ left: position.left, top: position.top }}>
          <strong><span>{member.statusEmoji}</span>{member.statusText}</strong>
          <small>{statusExpiryLabel(member.statusExpiresAt, member.statusSource)}</small>
        </span>,
        document.body,
      )}
    </>
  );
}

function readPins(workspaceId: string): string[] {
  if (typeof window === "undefined") return [];
  try {
    const raw = window.localStorage.getItem(`${PIN_KEY}:${workspaceId}`);
    const parsed = raw ? (JSON.parse(raw) as string[]) : [];
    return Array.isArray(parsed) ? parsed.map(String) : [];
  } catch {
    return [];
  }
}

function writePins(workspaceId: string, ids: string[]) {
  window.localStorage.setItem(`${PIN_KEY}:${workspaceId}`, JSON.stringify(ids));
}

/**
 * Workspace sidebar: brand → search → Tasks/Calendar/Rooms/People (or Chat Pinned/Recent) → Connect.
 */
export function WorkspaceSidebar({
  workspaceId,
  workspaceLabel = "Workspace",
  active = "rooms",
  variant = "workspace",
  channels,
  conversations,
  members,
  presence = {},
  myUserId,
  activeChannelId,
  taskCount,
  missedCallCount,
  onOpenChannel,
  onOpenDm,
  onCreateChannel,
  onStartConnect,
  onReopenDms,
  createChannelSlot,
  dmPickerSlot,
}: {
  workspaceId: string;
  workspaceLabel?: string;
  active?: SidebarActive;
  variant?: SidebarVariant;
  /** Text rooms for workspace mode. */
  channels: ConversationRow[];
  /** All conversations (rooms + DMs) for chat mode. Defaults to channels. */
  conversations?: ConversationRow[];
  members: SidebarMember[];
  presence?: Record<string, { status: string }>;
  myUserId: string | number | null;
  meName?: string | null;
  activeChannelId?: string | number | null;
  taskCount?: number;
  missedCallCount?: number;
  onOpenChannel?: (channelId: string | number) => void;
  onOpenDm?: (userId: string | number) => void;
  onCreateChannel?: () => void;
  onStartConnect?: () => void;
  onReopenDms?: () => void;
  createChannelSlot?: ReactNode;
  dmPickerSlot?: ReactNode;
  footerExtra?: ReactNode;
}) {
  const pathname = usePathname();
  const [chatFilter, setChatFilter] = useState<ChatFilter>("all");
  const [pins, setPins] = useState<string[]>([]);
  const allConversations = conversations ?? channels;
  const unread = useUnreadCounts(workspaceId);
  const dmByUser = useMemo(() => dmChannelByUserId(allConversations), [allConversations]);
  const people = members.filter(
    (row) => String(row.user.id) !== String(myUserId) && !row.member.deactivatedAt,
  );
  const roomRows = textChannels(channels).slice(0, 8);

  useEffect(() => {
    setPins(readPins(workspaceId));
  }, [workspaceId]);

  const chatRows = useMemo(() => {
    let rows = allConversations.filter((row) => !isDmChannel(row.channel.type) || !row.member?.isClosed);
    if (chatFilter === "dms") rows = dmChannels(rows);
    else if (chatFilter === "rooms") rows = textChannels(rows);
    else if (chatFilter === "unread") {
      rows = rows.filter((row) => (unread[String(row.channel.id)] ?? 0) > 0 || (row.member?.mentionCount ?? 0) > 0);
    }
    return rows;
  }, [allConversations, chatFilter, unread]);

  const pinnedRows = useMemo(
    () => chatRows.filter((row) => pins.includes(String(row.channel.id))),
    [chatRows, pins],
  );
  const recentRows = useMemo(
    () => chatRows.filter((row) => !pins.includes(String(row.channel.id))).slice(0, 12),
    [chatRows, pins],
  );
  const recentChannelRows = useMemo(() => textChannels(recentRows), [recentRows]);
  const recentDmRows = useMemo(() => dmChannels(recentRows), [recentRows]);
  const showChannelSection = chatFilter === "all" || chatFilter === "rooms" || chatFilter === "unread";
  const showDmSection = chatFilter === "all" || chatFilter === "dms" || chatFilter === "unread";

  function togglePin(channelId: string | number) {
    const id = String(channelId);
    setPins((prev) => {
      const next = prev.includes(id) ? prev.filter((x) => x !== id) : [id, ...prev].slice(0, 20);
      writePins(workspaceId, next);
      return next;
    });
  }

  function renderConversationRow(row: ConversationRow) {
    const id = String(row.channel.id);
    const isActive = id === String(activeChannelId);
    const isDm = isDmChannel(row.channel.type);
    const isPrivate = row.channel.type === "private";
    const title = isDm ? dmTitle(row) : (row.channel.name ?? "untitled");
    const href = channelPath(workspaceId, id);
    const peerId = row.dmPeer?.id;
    const peerMember = peerId == null ? null : members.find((member) => String(member.user.id) === String(peerId));
    const color = peerId ? avatarColor(String(peerId)) : null;
    const online = peerId ? presence[String(peerId)]?.status === "active" : false;
    const pinned = pins.includes(id);
    const unreadCount = unread[id] ?? 0;
    const mentionCount = row.member?.mentionCount ?? 0;
    const badgeCount = Math.max(unreadCount, mentionCount);
    const badgeClass = mentionCount > 0 ? "sidebar-badge mention" : "sidebar-badge";
    const badgeLabel = mentionCount > 0 ? `${mentionCount > 99 ? "99+" : mentionCount} mention${mentionCount === 1 ? "" : "s"}` : `${unreadCount} unread`;

    const content = isDm ? (
      <>
        <span className="list-row-avatar-wrap">
          <UserAvatar
            className="list-row-avatar"
            userId={peerId}
            name={title}
            avatarUrl={row.dmPeer?.avatarUrl}
            style={{ background: color?.bg ?? "#ddd", color: color?.fg ?? "#333" }}
          />
          <span className="list-row-presence" style={{ background: online ? "var(--online)" : "var(--offline)" }} />
        </span>
        <span className="sidebar-row-main">
          <span className="sidebar-row-title-line"><span className="sidebar-row-name">{title}</span>{peerMember && <StatusBadge member={peerMember.member} />}</span>
          <span className="sidebar-row-sub">{peerMember?.member.statusText || (online ? "Available" : "Away")}</span>
        </span>
        {badgeCount > 0 && !isActive && (
          <span className={badgeClass} aria-label={badgeLabel}>
            {badgeCount > 99 ? "99+" : badgeCount}
          </span>
        )}
      </>
    ) : (
      <>
        <span className="hash" aria-hidden="true">
          {isPrivate ? <IconLock size={12} /> : "#"}
        </span>
        <span className="sidebar-row-name">{title}</span>
        {badgeCount > 0 && !isActive && (
          <span className={badgeClass} aria-label={badgeLabel}>
            {badgeCount > 99 ? "99+" : badgeCount}
          </span>
        )}
      </>
    );

    const rowClass = ["sidebar-row", isDm ? "person" : "", isActive ? "active" : ""].filter(Boolean).join(" ");

    return (
      <div key={id} className="sidebar-chat-row">
        {onOpenChannel ? (
          <button type="button" className={rowClass} onClick={() => onOpenChannel(row.channel.id)}>
            {content}
          </button>
        ) : (
          <Link className={rowClass} href={href}>
            {content}
          </Link>
        )}
        <button
          type="button"
          className={pinned ? "sidebar-pin active" : "sidebar-pin"}
          aria-label={pinned ? "Unpin" : "Pin"}
          onClick={() => togglePin(row.channel.id)}
        >
          ★
        </button>
      </div>
    );
  }

  return (
    <aside className="sidebar" aria-label="Workspace">
      <div className="sidebar-brand">
        <span className="sidebar-brand-chip">
          <BrandMark size={22} />
        </span>
        <div className="sidebar-brand-copy">
          <strong>
            <BrandWord />
            <IconChevron size={14} />
          </strong>
          <span>{workspaceLabel}</span>
        </div>
      </div>

      <button
        type="button"
        className="sidebar-search"
        onClick={() => window.dispatchEvent(new Event("slackwsh:open-palette"))}
        aria-label="Search"
      >
        <IconSearch />
        <span>Search (⌘K)</span>
      </button>

      {variant === "chat" ? (
        <>
          <div className="chat-filters" role="tablist" aria-label="Chat filters">
            {(
              [
                ["all", "All"],
                ["dms", "DMs"],
                ["rooms", "Rooms"],
                ["unread", "Unread"],
              ] as const
            ).map(([id, label]) => (
              <button
                key={id}
                type="button"
                role="tab"
                className={chatFilter === id ? "chat-filter active" : "chat-filter"}
                aria-selected={chatFilter === id}
                onClick={() => setChatFilter(id)}
              >
                {label}
              </button>
            ))}
          </div>
          <div className="sidebar-scroll">
            <section className="sidebar-section">
              <div className="sidebar-section-label">Pinned</div>
              <div className="sidebar-rows">
                {pinnedRows.map(renderConversationRow)}
                {pinnedRows.length === 0 && <div className="sidebar-empty">Pin chats to keep them here</div>}
              </div>
            </section>
            {showChannelSection && (
              <section className="sidebar-section">
                <div className="sidebar-section-head">
                  <span className="sidebar-section-label">Channels</span>
                  {onCreateChannel && (
                    <button
                      type="button"
                      className="sidebar-section-add"
                      aria-label="Create a room"
                      onClick={onCreateChannel}
                    >
                      <IconPlus />
                    </button>
                  )}
                </div>
                {createChannelSlot}
                <div className="sidebar-rows">
                  {recentChannelRows.map(renderConversationRow)}
                  {recentChannelRows.length === 0 && (
                    <div className="sidebar-empty">
                      {chatFilter === "unread" ? "No unread channels" : "No channels yet"}
                    </div>
                  )}
                </div>
              </section>
            )}
            {showDmSection && (
              <section className="sidebar-section">
                <div className="sidebar-section-head">
                  <span className="sidebar-section-label">Direct messages</span>
                  {onReopenDms && dmChannels(allConversations).some((row) => row.member?.isClosed) && (
                    <button type="button" className="sidebar-section-add" aria-label="Reopen a direct message" title="Reopen a DM" onClick={onReopenDms}>
                      <IconPlus />
                    </button>
                  )}
                </div>
                {dmPickerSlot}
                <div className="sidebar-rows">
                  {recentDmRows.map(renderConversationRow)}
                  {recentDmRows.length === 0 && (
                    <div className="sidebar-empty">{chatFilter === "unread" ? "No unread DMs" : "No direct messages yet"}</div>
                  )}
                </div>
              </section>
            )}
          </div>
        </>
      ) : (
        <div className="sidebar-scroll">
          <section className="sidebar-section">
            <div className="sidebar-section-label">Workspace</div>
            <Link
              className={active === "tasks" || pathname?.startsWith("/tasks") ? "sidebar-link active" : "sidebar-link"}
              href={`/tasks?workspaceId=${workspaceId}`}
            >
              <span>Tasks</span>
              {(taskCount ?? 0) > 0 && <span className="sidebar-badge">{taskCount}</span>}
            </Link>
            <Link
              className={
                active === "calendar" || pathname?.startsWith("/calendar") ? "sidebar-link active" : "sidebar-link"
              }
              href={`/calendar?workspaceId=${workspaceId}`}
            >
              <span>Calendar</span>
            </Link>
            <Link
              className={active === "calls" || pathname?.startsWith("/calls") ? "sidebar-link active" : "sidebar-link"}
              href={`/calls?workspaceId=${workspaceId}`}
            >
              <span>Calls</span>
              {(missedCallCount ?? 0) > 0 && <span className="sidebar-badge">{missedCallCount}</span>}
            </Link>
            <Link
              className={pathname?.startsWith("/home") ? "sidebar-link active" : "sidebar-link"}
              href={`/home?workspaceId=${workspaceId}`}
            >
              <span>Library</span>
            </Link>
          </section>

          <section className="sidebar-section">
            <div className="sidebar-section-head">
              <span className="sidebar-section-label">Rooms</span>
              {onCreateChannel && (
                <button type="button" className="sidebar-section-add" aria-label="Create a room" onClick={onCreateChannel}>
                  <IconPlus />
                </button>
              )}
            </div>
            {createChannelSlot}
            <div className="sidebar-rows">
              {roomRows.map((row) => {
                const isActive = String(row.channel.id) === String(activeChannelId);
                const href = channelPath(String(workspaceId), String(row.channel.id));
                const isPrivate = row.channel.type === "private";
                const unreadCount = unread[String(row.channel.id)] ?? 0;
                const content = (
                  <>
                    <span className="hash" aria-hidden="true">
                      {isPrivate ? <IconLock size={12} /> : "#"}
                    </span>
                    <span className="sidebar-row-name">{row.channel.name ?? "untitled"}</span>
                    {unreadCount > 0 && !isActive && (
                      <span className="sidebar-badge">{unreadCount > 99 ? "99+" : unreadCount}</span>
                    )}
                  </>
                );
                if (onOpenChannel) {
                  return (
                    <button
                      key={String(row.channel.id)}
                      type="button"
                      className={isActive ? "sidebar-row active" : "sidebar-row"}
                      onClick={() => onOpenChannel(row.channel.id)}
                    >
                      {content}
                    </button>
                  );
                }
                return (
                  <Link
                    key={String(row.channel.id)}
                    className={isActive ? "sidebar-row active" : "sidebar-row"}
                    href={href}
                  >
                    {content}
                  </Link>
                );
              })}
              {roomRows.length === 0 && <div className="sidebar-empty">No rooms yet</div>}
              {textChannels(channels).length > 8 && (
                <Link className="sidebar-more" href={`/workspace?id=${workspaceId}`}>
                  Browse all {textChannels(channels).length}
                </Link>
              )}
            </div>
          </section>

          <section className="sidebar-section">
            <div className="sidebar-section-head">
              <span className="sidebar-section-label">People</span>
              <Link className="sidebar-section-add" href={`/people?workspaceId=${workspaceId}&add=1`} aria-label="Invite people">
                <IconPlus />
              </Link>
            </div>
            {dmPickerSlot}
            <div className="sidebar-rows">
              {people.slice(0, 8).map((row) => {
                const status = presence[String(row.user.id)]?.status;
                const online = status === "active";
                const away = status === "away";
                const color = avatarColor(String(row.user.id));
                const dmId = dmByUser.get(String(row.user.id));
                const unreadCount = dmId ? (unread[dmId] ?? 0) : 0;
                const statusLabel = online ? "Available" : away ? "Away" : "Offline";
                const body = (
                  <>
                    <span className="list-row-avatar-wrap">
                      <UserAvatar
                        className="list-row-avatar"
                        userId={row.user.id}
                        name={row.user.name}
                        avatarUrl={row.user.avatarUrl}
                        style={{ background: color.bg, color: color.fg }}
                      />
                      <span
                        className="list-row-presence"
                        style={{ background: online ? "var(--online)" : away ? "#e0a800" : "var(--offline)" }}
                      />
                    </span>
                    <span className="sidebar-row-main">
                      <span className="sidebar-row-title-line"><span className="sidebar-row-name">{row.user.name}</span><StatusBadge member={row.member} /></span>
                      <span className="sidebar-row-sub">{row.member.statusText || statusLabel}</span>
                    </span>
                    {unreadCount > 0 && <span className="sidebar-badge">{unreadCount > 99 ? "99+" : unreadCount}</span>}
                  </>
                );
                if (onOpenDm) {
                  return (
                    <button
                      key={String(row.user.id)}
                      type="button"
                      className="sidebar-row person"
                      onClick={() => onOpenDm(row.user.id)}
                    >
                      {body}
                    </button>
                  );
                }
                return (
                  <Link
                    key={String(row.user.id)}
                    className="sidebar-row person"
                    href={`/people?workspaceId=${workspaceId}&userId=${row.user.id}`}
                  >
                    {body}
                  </Link>
                );
              })}
              {people.length === 0 && <div className="sidebar-empty">Invite teammates</div>}
            </div>
          </section>
        </div>
      )}

      <div className="sidebar-connect">
        <div className="sidebar-connect-copy">
          <strong>Connect instantly</strong>
          <span>Start a Connect with anyone in this workspace.</span>
        </div>
        <button
          type="button"
          className="sidebar-connect-btn"
          onClick={onStartConnect}
          disabled={!onStartConnect}
          title={onStartConnect ? "Start a Connect" : "Open a room to start a Connect"}
        >
          <IconVideo size={15} />
          Start Connect
        </button>
      </div>
    </aside>
  );
}
