import type { MessageKind, RoomSummary, TimelineItem } from './types';

const RECENT_MS = 5 * 60 * 1000;

export interface NotificationSource {
  senderId: string | null;
  senderName: string | null;
  senderAvatar: string | null;
  kind: MessageKind | null;
  body: string | null;
  undecryptable: boolean;
  highlight: boolean;
}

export interface NotificationPlan {
  title: string;
  body: string;
  tag: string;
  renotify: boolean;
  roomId: string;
  iconMxc: string | null;
}

export function notifyingCount(room: RoomSummary): number {
  if (room.space || room.membership !== 'Joined' || room.notification_mode === 'Mute') return 0;
  if (room.notification_mode === 'MentionsAndKeywordsOnly') return room.unread_mentions;
  return room.unread_messages + room.unread_mentions;
}

export function badgeTotal(rooms: RoomSummary[]): number {
  return rooms.reduce((sum, room) => sum + notifyingCount(room), 0);
}

export function roomTag(roomId: string): string {
  return `room:${roomId}`;
}

export interface Arrival {
  mention: boolean;
}

export function arrivalIn(previous: RoomSummary | undefined, next: RoomSummary, now: number): Arrival | null {
  if (!previous || notifyingCount(next) <= notifyingCount(previous)) return null;
  const at = next.latest_event_timestamp_ms;
  if (at !== null && now - at > RECENT_MS) return null;
  return { mention: next.unread_mentions > previous.unread_mentions };
}

export function isRoomWatched(roomId: string, openRoomId: string | null, visible: boolean, focused: boolean): boolean {
  return visible && focused && roomId === openRoomId;
}

export function sourceFromTimeline(items: TimelineItem[] | undefined): NotificationSource | null {
  if (!items) return null;
  for (let i = items.length - 1; i >= 0; i--) {
    const item = items[i];
    if (item.kind !== 'event') continue;
    const { event } = item;
    if (event.own) return null;
    const content = event.content;
    const common = {
      senderId: event.sender.user_id,
      senderName: event.sender.display_name,
      senderAvatar: event.sender.avatar
    };
    if (content.kind === 'Message') {
      return { ...common, kind: content.message.kind, body: content.message.body, undecryptable: false, highlight: event.highlight === true };
    }
    if (content.kind === 'Sticker') return { ...common, kind: null, body: content.body, undecryptable: false, highlight: event.highlight === true };
    if (content.kind === 'UnableToDecrypt') return { ...common, kind: null, body: null, undecryptable: true, highlight: false };
  }
  return null;
}

export function sourceFromSummary(room: RoomSummary): NotificationSource | null {
  const latest = room.latest_event;
  if (!latest || latest.send_state.kind !== 'Sent') return null;
  const hero = room.heroes.find((h) => h.user_id === latest.sender);
  return {
    senderId: latest.sender,
    senderName: hero?.display_name ?? null,
    senderAvatar: hero?.avatar ?? null,
    kind: latest.kind,
    body: latest.body,
    undecryptable: false,
    highlight: false
  };
}

const MEDIA_LABEL: Partial<Record<string, string>> = {
  Image: 'Sent an image',
  Video: 'Sent a video',
  Audio: 'Sent an audio message',
  File: 'Sent a file',
  Location: 'Shared a location'
};

function previewText(source: NotificationSource, sender: string): string | null {
  if (source.undecryptable) return null;
  const kind = typeof source.kind === 'string' ? source.kind : null;
  const label = kind ? MEDIA_LABEL[kind] : undefined;
  const text = source.body?.trim();
  if (label) return label;
  if (!text) return null;
  return kind === 'Emote' ? `${sender} ${text}` : text;
}

function localPart(userId: string): string {
  const name = userId.startsWith('@') ? userId.slice(1) : userId;
  const colon = name.indexOf(':');
  return colon > 0 ? name.slice(0, colon) : name;
}

export function planNotification(
  room: RoomSummary,
  source: NotificationSource | null,
  arrival: Arrival
): NotificationPlan {
  const sender = source?.senderName ?? (source?.senderId ? localPart(source.senderId) : null);
  const text = source && sender ? previewText(source, sender) : null;
  const generic = room.direct ? 'New message' : 'New messages';
  let body: string;
  if (!text) body = sender && !room.direct ? `${sender}: ${generic}` : generic;
  else body = room.direct || !sender || source?.kind === 'Emote' ? text : `${sender}: ${text}`;
  return {
    title: room.direct && sender ? sender : room.name,
    body,
    tag: roomTag(room.room_id),
    renotify: arrival.mention || source?.highlight === true,
    roomId: room.room_id,
    iconMxc: (room.direct ? source?.senderAvatar : null) ?? room.avatar
  };
}
