// The one shape every producer sends and every channel receives.
//
// A notification is a DOORBELL, not a message. Apple and Google can read anything we hand them, so the
// payload carries a category and an id — never a subject line, a sender, a filename or an error string.
// The device composes the visible text from `type` and fetches the real content over the tailnet when
// tapped. See docs/push-notifications.md.

/** What happened. Deliberately coarse — the categories a device needs to route and render, nothing more. */
export type NotifyType = 'job' | 'mail' | 'agent' | 'download' | 'test';

export type Notification = {
  type: NotifyType;
  /** Who to notify. Resolved by ./resolve-user.ts — a proxied header beats anything a body claims. */
  userId: number;
  /**
   * The thing this is about, if there is one — a job id, a session id. The device fetches by it.
   * Never a human-readable string.
   */
  id?: string | number;
  /** How many, where a count is the whole story ("3 new emails"). */
  count?: number;
  /** Outcome, where there is one. */
  ok?: boolean;
  /** Restrict to one app: `mobile` | `music` | `read-aloud`. Absent = every registered app. */
  appSlug?: string;
};

/** What a channel reports back. Never throws — a failed notification must not break its producer. */
export type DeliveryResult = {
  channel: string;
  sent: number;
  failed: number;
  /** Tokens Apple/Google rejected outright; the caller deletes these rows. */
  dead?: string[];
};

export type Channel = {
  name: string;
  /** False when unconfigured — the sidecar skips it rather than erroring. */
  isConfigured: () => boolean;
  send: (n: Notification) => Promise<DeliveryResult>;
};
