/**
 * Helpers facturation : numéro, calculs HT/TTC, défauts émetteur.
 * Partagé entre les server actions et le rendu PDF.
 */

import { like } from "drizzle-orm";
import { db, schema } from "@/lib/db";
import type {
  InvoiceClientInfo,
  InvoiceEmitterInfo,
  InvoiceLineItem,
} from "@/lib/db/schema";

/** Émetteur Socialex par défaut (utilisé si pas d'override). */
export const DEFAULT_EMITTER: InvoiceEmitterInfo = {
  name: "Socialex",
  tagline: "Expert juridique",
  email: "contact@socialex.pro",
  addressLines: null,
  siret: null,
};

/**
 * Génère le prochain numéro de facture pour l'année donnée
 * au format "F-YYYY-XXXX".
 *
 * Calcule le max sur le suffixe (et non un COUNT) pour rester stable
 * quand une facture a été supprimée : sinon le compteur retombe sur un
 * numéro déjà pris et viole la contrainte unique.
 */
export async function nextInvoiceNumber(year: number): Promise<string> {
  const prefix = `F-${year}-`;
  const rows = await db
    .select({ number: schema.invoice.number })
    .from(schema.invoice)
    .where(like(schema.invoice.number, `${prefix}%`));
  let maxSeq = 0;
  for (const r of rows) {
    const m = r.number.match(/^F-\d{4}-(\d+)$/);
    if (!m) continue;
    const n = parseInt(m[1], 10);
    if (Number.isFinite(n) && n > maxSeq) maxSeq = n;
  }
  return `${prefix}${String(maxSeq + 1).padStart(4, "0")}`;
}

/**
 * Prochaine référence dossier (format "D-YYYY-XXXX"), même logique
 * que nextInvoiceNumber : max sur le suffixe, pas un COUNT.
 */
export async function nextDossierReference(year: number): Promise<string> {
  const prefix = `D-${year}-`;
  const rows = await db
    .select({ reference: schema.dossier.reference })
    .from(schema.dossier)
    .where(like(schema.dossier.reference, `${prefix}%`));
  let maxSeq = 0;
  for (const r of rows) {
    const m = r.reference.match(/^D-\d{4}-(\d+)$/);
    if (!m) continue;
    const n = parseInt(m[1], 10);
    if (Number.isFinite(n) && n > maxSeq) maxSeq = n;
  }
  return `${prefix}${String(maxSeq + 1).padStart(4, "0")}`;
}

/** Total HT en centimes pour une liste de lignes. */
export function computeHtCents(items: InvoiceLineItem[]): number {
  return items.reduce(
    (acc, li) =>
      acc +
      Math.round(li.quantity * li.unitPriceHtCents),
    0
  );
}

/**
 * Calcul du total TTC en centimes à partir des lignes et du taux TVA.
 * vatRateBps = points de base (2000 = 20 %). Null = pas de TVA.
 */
export function computeTtcCents(
  items: InvoiceLineItem[],
  vatRateBps: number | null
): { htCents: number; vatCents: number; ttcCents: number } {
  const htCents = computeHtCents(items);
  if (vatRateBps == null) {
    return { htCents, vatCents: 0, ttcCents: htCents };
  }
  const vatCents = Math.round((htCents * vatRateBps) / 10_000);
  return { htCents, vatCents, ttcCents: htCents + vatCents };
}

/** Format euros depuis centimes, en français. */
export function formatEurFromCents(cents: number): string {
  return new Intl.NumberFormat("fr-FR", {
    style: "currency",
    currency: "EUR",
  }).format(cents / 100);
}

/** Retourne l'émetteur effectif (override si présent, défaut sinon). */
export function resolveEmitter(
  override: InvoiceEmitterInfo | null | undefined
): InvoiceEmitterInfo {
  if (!override) return DEFAULT_EMITTER;
  return {
    name: override.name || DEFAULT_EMITTER.name,
    tagline: override.tagline ?? DEFAULT_EMITTER.tagline,
    email: override.email ?? DEFAULT_EMITTER.email,
    addressLines: override.addressLines ?? null,
    siret: override.siret ?? null,
  };
}

/** Type guard sur les lineItems jsonb (qui sont des `unknown` en sortie de db). */
export function isLineItemArray(v: unknown): v is InvoiceLineItem[] {
  return (
    Array.isArray(v) &&
    v.every(
      (x) =>
        x &&
        typeof x === "object" &&
        typeof (x as Record<string, unknown>).description === "string" &&
        typeof (x as Record<string, unknown>).quantity === "number" &&
        typeof (x as Record<string, unknown>).unitPriceHtCents === "number"
    )
  );
}

export type { InvoiceLineItem, InvoiceEmitterInfo, InvoiceClientInfo };
