import { toast } from 'sonner';

// v1.8.1 thresholds. First disconnect is silent — mobile Authelia idle timeouts
// and tab suspensions trip reconnects constantly and the old red "websocket
// error" toast made the app feel broken. Only escalate once the failure is
// sustained.
const TOAST_AFTER_FAILS = 3;
const TOAST_AFTER_MS = 15_000;
const PERSISTENT_AFTER_MS = 60_000;

export interface WsReconnectToast {
  onFailure(): void;
  onConnected(): void;
  dispose(): void;
}

interface Options {
  label: string;            // shown in the toast (e.g. "Live updates")
  onRetryNow: () => void;   // user clicked the "Retry now" action
}

// Per-connection toast wrapper. Caller drives it from the WS lifecycle:
//   onFailure   — after each failed connection attempt
//   onConnected — after a successful onopen
//   dispose     — on hook unmount
// The wrapper itself runs no timers and does not change the caller's reconnect
// cadence; it only decides when to show / dismiss the toast.
export function createWsReconnectToast(opts: Options): WsReconnectToast {
  let firstFailureAt: number | null = null;
  let failureCount = 0;
  let reconnectingId: string | number | null = null;
  let persistentId: string | number | null = null;

  function dismissReconnecting(): void {
    if (reconnectingId !== null) {
      toast.dismiss(reconnectingId);
      reconnectingId = null;
    }
  }
  function dismissPersistent(): void {
    if (persistentId !== null) {
      toast.dismiss(persistentId);
      persistentId = null;
    }
  }

  return {
    onFailure() {
      if (firstFailureAt === null) firstFailureAt = Date.now();
      failureCount += 1;
      const elapsed = Date.now() - firstFailureAt;

      if (persistentId === null && elapsed >= PERSISTENT_AFTER_MS) {
        dismissReconnecting();
        persistentId = toast.error(`${opts.label}: connection lost`, {
          duration: Infinity,
          action: {
            label: 'Retry now',
            onClick: () => {
              dismissReconnecting();
              dismissPersistent();
              opts.onRetryNow();
            },
          },
        });
        return;
      }

      // Gray "reconnecting…" toast once we've crossed either threshold.
      if (
        reconnectingId === null &&
        persistentId === null &&
        (failureCount >= TOAST_AFTER_FAILS || elapsed >= TOAST_AFTER_MS)
      ) {
        reconnectingId = toast.warning(`${opts.label}: reconnecting…`, {
          duration: Infinity,
        });
      }
    },
    onConnected() {
      firstFailureAt = null;
      failureCount = 0;
      dismissReconnecting();
      dismissPersistent();
    },
    dispose() {
      firstFailureAt = null;
      failureCount = 0;
      dismissReconnecting();
      dismissPersistent();
    },
  };
}
