import { atom } from 'jotai';
import type { IconSrc } from 'folds';

export type ToastNotif = {
  id: string;
  avatarUrl?: string;
  iconSrc?: IconSrc; // folds Icon src for a "system" toast (shown instead of an avatar/initials)
  displayName: string;
  body: string;
  roomName: string;
  roomId: string;
  hashPath?: string; // overrides window.location.hash navigation when set
  onClick?: () => void; // custom click handler; skips hash navigation when set
  sticky?: boolean; // when true, does not auto-dismiss — use for action toasts that require a click
};

// Build a "download complete" system toast. Kept folds-free here (the icon src is
// passed in) so this stays a pure, testable builder. roomId is empty + onClick is
// set so a click only dismisses (never navigates to a room).
export const createDownloadToast = (filename: string, iconSrc?: IconSrc): ToastNotif => ({
  id: `download-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
  displayName: 'Downloaded',
  body: filename,
  roomName: '',
  roomId: '',
  iconSrc,
  onClick: () => undefined,
});

// Build an error/system toast (e.g. a failed command or account action). Mirrors
// createDownloadToast: folds-free (icon src passed in), empty roomId + no-op
// onClick so a click only dismisses (never navigates to a room).
export const createErrorToast = (
  body: string,
  iconSrc?: IconSrc,
  displayName = 'Something went wrong',
): ToastNotif => ({
  id: `error-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
  displayName,
  body,
  roomName: '',
  roomId: '',
  iconSrc,
  onClick: () => undefined,
});

const baseAtom = atom<ToastNotif[]>([]);

// Cap concurrent toasts so a burst (e.g. many rooms lighting up while focused)
// can't stack unbounded and cover the viewport.
const MAX_TOASTS = 5;

// Write-only setter used in ClientNonUIFeatures
export const toastQueueAtom = atom<ToastNotif[], [ToastNotif | null], void>(
  (get) => get(baseAtom),
  (get, set, notif) => {
    if (notif === null) return; // no-op guard
    const next = [...get(baseAtom), notif];
    // Over cap: drop the oldest NON-sticky toasts (transient message/error
    // toasts auto-dismiss anyway); never drop a sticky action toast, which
    // requires a click. The `length - 1` bound excludes the just-appended
    // newest, so a fresh toast is never the one dropped — if everything older
    // is sticky the cap simply stretches rather than eating the new notice.
    for (let i = 0; i < next.length - 1 && next.length > MAX_TOASTS; i += 1) {
      if (!next[i].sticky) {
        next.splice(i, 1);
        i -= 1;
      }
    }
    set(baseAtom, next);
  },
);

export const dismissToastAtom = atom<null, [string], void>(null, (get, set, id) =>
  set(
    baseAtom,
    get(baseAtom).filter((t) => t.id !== id),
  ),
);
