import { createServerFn } from '@tanstack/react-start'
import { z } from 'zod'
import { requireSupabaseAuth } from '@/integrations/supabase/auth-middleware'

const horizonSchema = z.object({ days: z.union([z.literal(7), z.literal(30), z.literal(90)]) })

function round(value: number) {
  return Math.round(value * 100) / 100
}

export const getFinanceIntelligence = createServerFn({ method: 'POST' })
  .middleware([requireSupabaseAuth])
  .inputValidator((input) => horizonSchema.parse(input))
  .handler(async ({ data, context }) => {
    const membership = await context.supabase
      .from('user_roles')
      .select('workspace_id')
      .eq('user_id', context.userId)
      .limit(1)
      .maybeSingle()

    if (membership.error) throw membership.error
    if (!membership.data) {
      return { state: 'empty' as const, calculatedAt: new Date().toISOString(), days: data.days }
    }

    const workspaceId = membership.data.workspace_id
    const [invoiceResult, paymentResult, customerResult] = await Promise.all([
      context.supabase.from('invoices').select('amount,due_date,status').eq('workspace_id', workspaceId),
      context.supabase.from('payments').select('amount,paid_at,status').eq('workspace_id', workspaceId),
      context.supabase.from('customers').select('outstanding_balance,average_payment_days,risk_score').eq('workspace_id', workspaceId),
    ])
    if (invoiceResult.error) throw invoiceResult.error
    if (paymentResult.error) throw paymentResult.error
    if (customerResult.error) throw customerResult.error

    const invoices = invoiceResult.data ?? []
    const payments = paymentResult.data ?? []
    const customers = customerResult.data ?? []
    if (invoices.length === 0 && payments.length === 0 && customers.length === 0) {
      return { state: 'empty' as const, calculatedAt: new Date().toISOString(), days: data.days }
    }

    const today = new Date()
    const horizon = new Date(today)
    horizon.setUTCDate(horizon.getUTCDate() + data.days)
    const open = invoices.filter((invoice) => invoice.status !== 'paid' && invoice.status !== 'draft')
    const overdue = open.filter((invoice) => new Date(`${invoice.due_date}T00:00:00Z`) < today)
    const expected = open.filter((invoice) => {
      const due = new Date(`${invoice.due_date}T00:00:00Z`)
      return due >= today && due <= horizon
    })
    const outstanding = customers.reduce((sum, customer) => sum + Number(customer.outstanding_balance), 0)
    const averageDays = customers.length
      ? customers.reduce((sum, customer) => sum + customer.average_payment_days, 0) / customers.length
      : 0
    const portfolioScore = customers.length
      ? customers.reduce((sum, customer) => sum + customer.risk_score, 0) / customers.length
      : Math.max(20, 100 - overdue.length * 12)
    const latePaymentLikelihood = open.length ? (overdue.length / open.length) * 100 : 0
    const recordCount = invoices.length + payments.length + customers.length
    const confidence = Math.min(88, 45 + recordCount * 3)
    const factors = [
      `${overdue.length} of ${open.length} open invoices are overdue`,
      customers.length ? `Average customer payment time is ${Math.round(averageDays)} days` : 'Customer payment history is still limited',
      `${payments.filter((payment) => payment.status === 'completed').length} completed payments are included`,
    ]

    return {
      state: 'ready' as const,
      status: 'Early Intelligence' as const,
      calculatedAt: new Date().toISOString(),
      days: data.days,
      paymentRiskScore: Math.round(portfolioScore),
      riskLabel: portfolioScore >= 80 ? 'Low risk' : portfolioScore >= 60 ? 'Moderate risk' : 'Elevated risk',
      latePaymentLikelihood: Math.round(latePaymentLikelihood),
      confidence,
      factors,
      totals: {
        expected: round(expected.reduce((sum, invoice) => sum + Number(invoice.amount), 0)),
        outstanding: round(outstanding || open.reduce((sum, invoice) => sum + Number(invoice.amount), 0)),
        overdue: round(overdue.reduce((sum, invoice) => sum + Number(invoice.amount), 0)),
      },
      invoiceCount: invoices.length,
    }
  })