/**
 * pdf-templates/common — types, formatters, et helpers partagés entre
 * les 4 thèmes de factures Rubis.
 *
 * Les thèmes consomment tous le même `InvoiceTemplateProps`. Le dispatcher
 * (`#pdf-templates/index`) sélectionne le bon composant selon le slug.
 *
 * Convention :
 *  - Tous les montants en *centimes* (int). On formate au moment du render
 *    via `formatCents(cents)` (sépare millier + ", " + " €").
 *  - Toutes les dates en `DateTime` Luxon — on formate via `formatDate(d)`
 *    en français long ("15 mai 2026").
 */

import { DateTime } from 'luxon'
import type {
  InvoiceIssuer,
  InvoiceThemeSlug,
} from '#services/invoice_settings'
import type {
  ComputedInvoiceLine,
  TvaBreakdownItem,
} from '#services/invoice_totals'
import type { ClientSnapshot } from '#models/invoice'

/**
 * Props passées à chaque template. C'est le contrat figé que respectent
 * tous les thèmes — ajouter un champ = mettre à jour les 4 composants.
 */
export interface InvoiceTemplateProps {
  /** Métadonnées en-tête : numéro, dates, paiement. */
  numero: string
  issueDate: DateTime
  dueDate: DateTime
  paymentTermsDays: number
  /** Émetteur (snapshot figé à l'émission). */
  issuer: InvoiceIssuer
  /** Client destinataire (snapshot figé à l'émission). */
  client: ClientSnapshot
  /** Lignes calculées (HT par ligne déjà arrondi). */
  lines: ComputedInvoiceLine[]
  /** Ventilation TVA — affichée seulement si plusieurs taux. */
  tvaBreakdown: TvaBreakdownItem[]
  /** Totaux agrégés (en centimes). */
  amountHtCents: number
  amountTvaCents: number
  amountTtcCents: number
  /** Mentions légales (snapshot des settings au moment de l'émission). */
  penaltyRateText: string
  escompteText: string
  footerLegalText: string
  /** Notes libres en pied de page (custom par facture). */
  footerNotes: string | null
  /** RIB pour le pied de page paiement. */
  rib: {
    iban: string | null
    bic: string | null
    bankName: string | null
  }
  /** Couleur d'accent appliquée (hex #RRGGBB). */
  accentColor: string
  /** URL absolue du logo (null = pas de logo). */
  logoUrl: string | null
}

// ============================================================================
// Formatters (format français)
// ============================================================================

/**
 * Formate des centimes en string "X 123,45 €". Pas de décimales sans virgule
 * (toujours 2 chiffres après la virgule, exigence comptable).
 */
export function formatCents(cents: number): string {
  const euros = cents / 100
  return new Intl.NumberFormat('fr-FR', {
    style: 'currency',
    currency: 'EUR',
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  }).format(euros)
}

/** Format français long : "15 mai 2026". */
export function formatDate(d: DateTime): string {
  return d.setLocale('fr').toFormat('d MMMM yyyy')
}

/** Format quantité : 2 décimales si non-entier, sinon int. */
export function formatQuantity(q: number): string {
  return Number.isInteger(q)
    ? String(q)
    : new Intl.NumberFormat('fr-FR', {
        minimumFractionDigits: 2,
        maximumFractionDigits: 2,
      }).format(q)
}

/** Format taux TVA : "20 %" ou "5,5 %". */
export function formatTvaRate(rate: number): string {
  return Number.isInteger(rate) ? `${rate} %` : `${rate.toString().replace('.', ',')} %`
}

/**
 * Formate l'adresse postale en multi-lignes utilisable dans le PDF.
 * Retourne un tableau de strings non-vides (le template fait un map → Text).
 */
export function formatAddress(parts: {
  line1: string | null | undefined
  line2: string | null | undefined
  zip: string | null | undefined
  city: string | null | undefined
  country: string | null | undefined
}): string[] {
  const out: string[] = []
  if (parts.line1) out.push(parts.line1)
  if (parts.line2) out.push(parts.line2)
  if (parts.zip || parts.city) {
    out.push([parts.zip, parts.city].filter(Boolean).join(' '))
  }
  // Pays affiché uniquement hors France (par convention factures domestiques).
  if (parts.country && parts.country !== 'FR') out.push(parts.country)
  return out
}

/** Calcule le nombre de jours entre deux dates (issue vs due) pour affichage. */
export function daysBetween(from: DateTime, to: DateTime): number {
  return Math.round(to.diff(from, 'days').days)
}

// ============================================================================
// Palette commune
// ============================================================================

/** Tons de gris cohérents avec la palette Rubis (cream + ink). */
export const PALETTE = {
  ink: '#1A1410',
  ink2: '#4F4640',
  ink3: '#8A7F76',
  line: '#E8E0D6',
  cream: '#FAF7F2',
  paper: '#FFFFFF',
} as const

// ============================================================================
// Dispatcher type — réexporté pour le sélecteur côté `index.tsx`
// ============================================================================
export type { InvoiceThemeSlug }
