import type { ChannelAccountCatalogGroup, ChannelConnectionStatus } from '@src/lib/channel-types'; const KNOWN_CHANNEL_STATUSES: ChannelConnectionStatus[] = [ 'connected', 'connecting', 'disconnected', 'error', 'degraded', ]; export interface ChannelStatusInferenceInput { status?: unknown; configured?: boolean; channelUrl?: string | null; lastError?: string | null; error?: unknown; warnings?: readonly string[] | null; warningCount?: number; isConnecting?: boolean; isLoading?: boolean; connectionState?: unknown; hasBinding?: boolean; degraded?: boolean; } export interface ChannelStatusSummary { status: ChannelConnectionStatus; counts: Record; groupCount: number; accountCount: number; } function isMeaningfulText(value: unknown): boolean { return String(value ?? '').trim().length > 0; } function isValidUrl(value: string): boolean { try { new URL(value); return true; } catch { return false; } } export function normalizeChannelConnectionStatus(value: unknown): ChannelConnectionStatus | null { const normalized = String(value ?? '').trim().toLowerCase(); return KNOWN_CHANNEL_STATUSES.includes(normalized as ChannelConnectionStatus) ? (normalized as ChannelConnectionStatus) : null; } export function inferChannelConnectionStatus( input: ChannelStatusInferenceInput = {}, ): ChannelConnectionStatus { const explicitStatus = normalizeChannelConnectionStatus(input.status); const normalizedConnectionState = normalizeChannelConnectionStatus(input.connectionState); const channelUrl = String(input.channelUrl ?? '').trim(); const warningCount = typeof input.warningCount === 'number' ? input.warningCount : Array.isArray(input.warnings) ? input.warnings.filter(isMeaningfulText).length : 0; if (isMeaningfulText(input.error) || isMeaningfulText(input.lastError)) { return 'error'; } if (explicitStatus === 'error' || normalizedConnectionState === 'error') { return 'error'; } if (input.configured === false || !channelUrl) { return 'disconnected'; } if (!isValidUrl(channelUrl)) { return 'error'; } if ( explicitStatus === 'connecting' || normalizedConnectionState === 'connecting' || input.isConnecting || input.isLoading ) { return 'connecting'; } if (explicitStatus === 'disconnected' || normalizedConnectionState === 'disconnected') { return 'disconnected'; } if (explicitStatus === 'degraded' || normalizedConnectionState === 'degraded') { return 'degraded'; } if (warningCount > 0 || input.degraded || input.hasBinding === false) { return 'degraded'; } if (explicitStatus === 'connected') { return 'connected'; } return 'connected'; } export function summarizeChannelConnectionStatuses( statuses: readonly ChannelConnectionStatus[], ): ChannelConnectionStatus { const counts = statuses.reduce>( (acc, status) => { acc[status] += 1; return acc; }, { connected: 0, connecting: 0, disconnected: 0, error: 0, degraded: 0, }, ); if (counts.error > 0) { return counts.connected > 0 || counts.connecting > 0 || counts.degraded > 0 || counts.disconnected > 0 ? 'degraded' : 'error'; } if (counts.connecting > 0) { return 'connecting'; } if (counts.degraded > 0) { return 'degraded'; } if (counts.disconnected > 0 && counts.connected === 0) { return 'disconnected'; } if (counts.connected > 0 && counts.disconnected > 0) { return 'degraded'; } return counts.connected > 0 ? 'connected' : 'disconnected'; } export function buildChannelStatusSummary( groups: readonly ChannelAccountCatalogGroup[], ): ChannelStatusSummary { const counts: Record = { connected: 0, connecting: 0, disconnected: 0, error: 0, degraded: 0, }; let accountCount = 0; for (const group of groups) { accountCount += group.accounts.length; for (const account of group.accounts) { counts[account.status] += 1; } } const accountStatuses: ChannelConnectionStatus[] = []; for (const group of groups) { for (const account of group.accounts) { accountStatuses.push(account.status); } } return { status: summarizeChannelConnectionStatuses(accountStatuses), counts, groupCount: groups.length, accountCount, }; }