/** Shared helpers for channel vs DM conversation navigation. */

export interface ConversationChannel {
  id: string;
  name: string | null;
  type: string;
}

export interface ConversationPeer {
  id: string;
  name: string;
  email: string;
  avatarUrl: string | null;
}

export interface ConversationMembership {
  lastReadSeq?: number;
  mentionCount?: number;
  unreadCount?: number;
  isMuted?: boolean;
  isStarred?: boolean;
  isClosed?: boolean;
}

export interface ConversationRow {
  channel: ConversationChannel;
  dmPeer?: ConversationPeer | null;
  dmPeers?: ConversationPeer[];
  member?: ConversationMembership | null;
}

function asId(value: unknown): string | null {
  if (typeof value === "string" && value) return value;
  if (typeof value === "number" && Number.isFinite(value)) return String(value);
  return null;
}

export function normalizeChannelRows(raw: unknown): ConversationRow[] {
  if (!Array.isArray(raw)) return [];
  const rows: ConversationRow[] = [];
  for (const row of raw) {
    if (!row || typeof row !== "object") continue;
    const r = row as Record<string, unknown>;
    if (r.channel && typeof r.channel === "object") {
      const rawChannel = r.channel as Record<string, unknown>;
      const id = asId(rawChannel.id);
      if (!id) continue;
      const dmPeerRaw = r.dmPeer as Record<string, unknown> | null | undefined;
      const dmPeerId = dmPeerRaw ? asId(dmPeerRaw.id) : null;
      rows.push({
        channel: {
          id,
          name: (rawChannel.name as string | null) ?? null,
          type: (rawChannel.type as string) ?? "public",
        },
        member: normalizeMembership(r.member),
        dmPeer:
          dmPeerRaw && dmPeerId
            ? {
                id: dmPeerId,
                name: String(dmPeerRaw.name ?? ""),
                email: String(dmPeerRaw.email ?? ""),
                avatarUrl: typeof dmPeerRaw.avatarUrl === "string" ? dmPeerRaw.avatarUrl : null,
              }
            : null,
        dmPeers: Array.isArray(r.dmPeers)
          ? (r.dmPeers as Record<string, unknown>[])
              .map((peer) => {
                const peerId = asId(peer.id);
                if (!peerId) return null;
                return {
                  id: peerId,
                  name: String(peer.name ?? ""),
                  email: String(peer.email ?? ""),
                  avatarUrl: typeof peer.avatarUrl === "string" ? peer.avatarUrl : null,
                };
              })
              .filter((peer): peer is ConversationPeer => peer != null)
          : [],
      });
      continue;
    }
    const bareId = asId(r.id);
    if (bareId) {
      rows.push({
        channel: {
          id: bareId,
          name: (r.name as string | null) ?? null,
          type: (r.type as string) ?? "public",
        },
        dmPeer: null,
        dmPeers: [],
      });
    }
  }
  return rows;
}

function normalizeMembership(raw: unknown): ConversationMembership | null {
  if (!raw || typeof raw !== "object") return null;
  const r = raw as Record<string, unknown>;
  return {
    lastReadSeq: typeof r.lastReadSeq === "number" ? r.lastReadSeq : undefined,
    mentionCount: typeof r.mentionCount === "number" ? r.mentionCount : undefined,
    unreadCount: typeof r.unreadCount === "number" ? r.unreadCount : undefined,
    isMuted: typeof r.isMuted === "boolean" ? r.isMuted : undefined,
    isStarred: typeof r.isStarred === "boolean" ? r.isStarred : undefined,
    isClosed: typeof r.isClosed === "boolean" ? r.isClosed : undefined,
  };
}

export function isTextChannel(type: string) {
  return type === "public" || type === "private";
}

export function isDmChannel(type: string) {
  return type === "dm" || type === "group_dm";
}

export function textChannels(rows: ConversationRow[]) {
  return rows.filter((row) => isTextChannel(row.channel.type));
}

export function dmChannels(rows: ConversationRow[]) {
  return rows.filter((row) => isDmChannel(row.channel.type));
}

export function dmTitle(row: ConversationRow): string {
  if (row.channel.type === "group_dm") {
    if (row.channel.name?.trim()) return row.channel.name.trim();
    const names = (row.dmPeers ?? []).map((p) => p.name).filter(Boolean);
    if (names.length > 0) return names.join(", ");
    return "Group DM";
  }
  return row.dmPeer?.name ?? row.channel.name ?? "Direct message";
}

export function channelPath(workspaceId: string, channelId: string) {
  return `/channel?workspaceId=${encodeURIComponent(workspaceId)}&channelId=${encodeURIComponent(channelId)}`;
}

/** Map other-user-id → existing 1:1 DM channel id. */
export function dmChannelByUserId(rows: ConversationRow[]): Map<string, string> {
  const map = new Map<string, string>();
  for (const row of dmChannels(rows)) {
    if (row.channel.type !== "dm") continue;
    if (row.dmPeer?.id != null) map.set(String(row.dmPeer.id), String(row.channel.id));
  }
  return map;
}
