import { atom } from 'jotai';
import { MatrixEvent } from 'matrix-js-sdk';

export type IncomingCall = {
  notifEvent: MatrixEvent;
  roomId: string;
  callId: string;
};

export type IncomingCallAction =
  | { type: 'ADD'; key: string; call: IncomingCall }
  | { type: 'REMOVE'; key: string }
  | { type: 'REMOVE_BY_ROOM'; roomId: string }
  | { type: 'REMOVE_BY_NOTIF_ID'; notifEventId: string };

const baseIncomingCallsAtom = atom<Map<string, IncomingCall>>(new Map());

// Derived boolean flips only on the empty/non-empty edge — used by the
// call-surface horseshoe so it doesn't re-render on every metadata-only
// Map churn (e.g. notification id rewrites that don't affect ring count).
export const isRingingAtom = atom((get) => get(baseIncomingCallsAtom).size > 0);

export const incomingCallsAtom = atom<Map<string, IncomingCall>, [IncomingCallAction], void>(
  (get) => get(baseIncomingCallsAtom),
  (get, set, action) => {
    const current = get(baseIncomingCallsAtom);
    if (action.type === 'ADD') {
      if (current.has(action.key)) return;
      const next = new Map(current);
      next.set(action.key, action.call);
      set(baseIncomingCallsAtom, next);
      return;
    }
    if (action.type === 'REMOVE') {
      if (!current.has(action.key)) return;
      const next = new Map(current);
      next.delete(action.key);
      set(baseIncomingCallsAtom, next);
      return;
    }
    if (action.type === 'REMOVE_BY_ROOM') {
      const next = new Map(current);
      let changed = false;
      next.forEach((call, key) => {
        if (call.roomId === action.roomId) {
          next.delete(key);
          changed = true;
        }
      });
      if (changed) set(baseIncomingCallsAtom, next);
      return;
    }
    if (action.type === 'REMOVE_BY_NOTIF_ID') {
      const next = new Map(current);
      let changed = false;
      next.forEach((call, key) => {
        if (call.notifEvent.getId() === action.notifEventId) {
          next.delete(key);
          changed = true;
        }
      });
      if (changed) set(baseIncomingCallsAtom, next);
    }
  }
);
