/** * Calculates weighted average payout delay across revenue streams */ export const usePayoutExposure = () => { const calculateWeightedAverageDelay = ( streams: Array<{ targetMonthlyAmount: number; payoutDelayDays: number }> ): number => { const totalRevenue = streams.reduce((sum, stream) => sum + (stream.targetMonthlyAmount || 0), 0) if (totalRevenue === 0) return 0 const weightedSum = streams.reduce((sum, stream) => { const weight = (stream.targetMonthlyAmount || 0) / totalRevenue return sum + (weight * (stream.payoutDelayDays || 0)) }, 0) return weightedSum } const getPayoutExposureStatus = (avgDelayDays: number, minCashCushion: number): 'green' | 'yellow' | 'red' => { // Flag if weighted average >30 days and cushion <1 month if (avgDelayDays > 30 && minCashCushion < 8000) return 'red' // Assuming ~8k = 1 month expenses if (avgDelayDays > 21) return 'yellow' return 'green' } const getPayoutExposureMessage = (status: 'green' | 'yellow' | 'red'): string => { switch (status) { case 'red': return 'Money is earned now but arrives later. Delays can create mid-month dips.' case 'yellow': return 'Some payout delays present. Monitor cash timing.' case 'green': return 'Payout timing looks manageable.' } } const analyzePayoutExposure = ( streams: Array<{ targetMonthlyAmount: number; payoutDelayDays: number }>, minCashCushion: number ) => { const avgDelayDays = calculateWeightedAverageDelay(streams) const status = getPayoutExposureStatus(avgDelayDays, minCashCushion) return { avgDelayDays: Math.round(avgDelayDays), status, message: getPayoutExposureMessage(status) } } return { calculateWeightedAverageDelay, getPayoutExposureStatus, getPayoutExposureMessage, analyzePayoutExposure } }