/**
 * Channel status bookkeeping around one outbound provider call.
 *
 * Africa's Talking is a stateless HTTP provider: there is no session and no connection event, so the
 * only moment we learn whether the deployment credentials still work is when we try to send. A
 * rejected key would otherwise leave the channel showing `connected` forever while every send fails.
 */
import type { Channel } from '@wa-ticketing/shared';
import { WhatsAppProviderError } from './africasTalkingWhatsAppProvider.js';

export type ChannelStatusWriter = (id: string, status: Channel['status']) => Promise<void>;

/**
 * Runs `send`, then moves the channel status only when the provider told us something new:
 * an authentication rejection means `disconnected`, and the first success afterwards means
 * `connected` again. Every other failure is transient or a caller mistake and leaves status alone.
 *
 * Baileys channels are passed straight through — their status belongs to the worker's session
 * events, and a send result says nothing about that session that the worker has not already seen.
 *
 * The original error always propagates: status writing is bookkeeping and must never replace or
 * mask the reason a send failed, nor fail a send that actually succeeded. A dropped write
 * self-corrects on the next outbound call.
 */
export async function trackOutboundProviderStatus<T>(
  channel: Channel,
  setStatus: ChannelStatusWriter,
  send: () => Promise<T>,
): Promise<T> {
  if (channel.provider !== 'africas_talking') return send();

  let result: T;
  try {
    result = await send();
  } catch (err) {
    if (
      err instanceof WhatsAppProviderError
      && err.type === 'authentication'
      && channel.status !== 'disconnected'
    ) {
      await setStatus(channel.id, 'disconnected').catch(() => {});
    }
    throw err;
  }

  if (channel.status === 'disconnected') {
    await setStatus(channel.id, 'connected').catch(() => {});
  }
  return result;
}
