import db from '@adonisjs/lucid/services/db'

/**
 * Stats agrégées d'un client. Calculées on-the-fly à partir des invoices
 * (V1 : pas de cache, le volume reste raisonnable). Si le perf devient un
 * sujet, on cachera dans Redis avec invalidation post-mutation invoice.
 */
export type ClientStats = {
  invoiceCount: number
  activeInvoiceCount: number
  lateInvoiceCount: number
  paidInvoiceCount: number
  paidLifetimeCents: number
  pendingLifetimeCents: number
  lastActivityAt: string | null
}

export const EMPTY_CLIENT_STATS: ClientStats = {
  invoiceCount: 0,
  activeInvoiceCount: 0,
  lateInvoiceCount: 0,
  paidInvoiceCount: 0,
  paidLifetimeCents: 0,
  pendingLifetimeCents: 0,
  lastActivityAt: null,
}

/**
 * Calcule les stats pour un ensemble de clients d'une org en une seule
 * requête agrégée par client_id. Les clients sans facture reçoivent EMPTY.
 *
 * @returns Map clientId → ClientStats
 */
export async function bulkComputeClientStats(
  organizationId: string,
  clientIds: string[]
): Promise<Map<string, ClientStats>> {
  const map = new Map<string, ClientStats>()
  for (const id of clientIds) {
    map.set(id, { ...EMPTY_CLIENT_STATS })
  }

  if (clientIds.length === 0) return map

  const today = new Date()
  today.setHours(0, 0, 0, 0)

  const ACTIVE = "('pending','in_relance','awaiting_user_confirmation')"

  const rows = await db
    .from('invoices')
    .where('organization_id', organizationId)
    .whereIn('client_id', clientIds)
    .select('client_id')
    .select(db.raw('count(*)::int as invoice_count'))
    .select(db.raw(`count(*) filter (where status::text in ${ACTIVE})::int as active_count`))
    .select(
      db.raw(
        `count(*) filter (where status::text in ${ACTIVE} and due_date < ?)::int as late_count`,
        [today]
      )
    )
    .select(db.raw(`count(*) filter (where status = 'paid')::int as paid_count`))
    .select(
      db.raw(`coalesce(sum(amount_ttc_cents) filter (where status = 'paid'), 0)::int as paid_cents`)
    )
    .select(
      db.raw(
        `coalesce(sum(amount_ttc_cents) filter (where status::text in ${ACTIVE}), 0)::int as pending_cents`
      )
    )
    .select(db.raw('max(updated_at) as last_activity'))
    .groupBy('client_id')

  for (const r of rows) {
    map.set(r.client_id, {
      invoiceCount: r.invoice_count,
      activeInvoiceCount: r.active_count,
      lateInvoiceCount: r.late_count,
      paidInvoiceCount: r.paid_count,
      paidLifetimeCents: r.paid_cents,
      pendingLifetimeCents: r.pending_cents,
      lastActivityAt:
        r.last_activity instanceof Date
          ? r.last_activity.toISOString()
          : (r.last_activity as string | null),
    })
  }

  return map
}
