/**
 * Admin cross-client billing-health console (the /abonnements → Facturation tab).
 *
 * Status rule (server-computed): 0 unpaid → a_jour · 1 → en_retard ·
 * 2..(tolerance-1) → impaye · ≥ tolerance → suspendu. Suspension is also forced
 * by a manual `lock_override = locked` and never by `unlocked`.
 */

export type BillingStatusValue = "a_jour" | "en_retard" | "impaye" | "suspendu";
/** sepa: set by the mandate sync once the client has signed a direct debit mandate. */
export type PaymentMode = "card" | "transfer" | "sepa";
export type LockOverride = "auto" | "locked" | "unlocked";

/**
 * What a product's lines count: fleet, every vehicle in the fleet; telematics, every connected
 * vehicle; bundle, every box vehicle (fleet and telematics together).
 */
export type BillingProductRole = "fleet" | "telematics" | "bundle";

/** A product the contract clients are invoiced (Abonnements > Produits facturés). */
export interface BillingProduct {
  id: number;
  /** Stable: kept on the contracts and on the invoice lines. */
  key: string;
  role: BillingProductRole;
  label: string;
  /** The text under the line on the invoice. */
  description: string | null;
  /** HT per vehicle and month. */
  list_price: number;
  pennylane_product_id: string | null;
  /** Off: contracts can no longer take it. A product on a contract stays on. */
  active: boolean;
  /** The contracts that invoice it. */
  clients_count: number;
  updated_at?: string | null;
}

export interface BillingProductPayload {
  label: string;
  /** Set once, at creation. */
  role?: BillingProductRole;
  list_price: number;
  description: string | null;
  pennylane_product_id: string | null;
  active?: boolean;
}

/**
 * What a client is invoiced and at what price (billing automation, part 1): for each role, a
 * product (null: the role is not invoiced) and the client's price, net HT per vehicle and month
 * (null: the product's list price).
 */
export interface BillingProfile {
  active: boolean;
  /** contract: the month just ended at its own prices; plan: the plan's price, the month ahead. */
  mode: "contract" | "plan";
  fleet_product: string | null;
  fleet_unit_price: number | null;
  telematics_product: string | null;
  telematics_unit_price: number | null;
  bundle_product: string | null;
  bundle_unit_price: number | null;
  notes: string | null;
  updated_at?: string | null;
}

export interface BillingInvoiceLine {
  /** A product key on a contract; plan once the client is billed by its vehicles' plans. */
  product: string;
  /** Plans per vehicle: the plan of the line. */
  plan_id?: number;
  label: string;
  quantity: number;
  list_price: number;
  unit_price: number;
  discount_percent: number;
  total_ht: number;
}

/** An invoice as the run would issue it, computed and written nowhere. */
export interface BillingInvoicePreview {
  rule: "contract" | "plan";
  period_start?: string;
  period_end?: string;
  /** Null once the client is billed by its vehicles' plans: the lines are the plans. */
  counts?: { fleet: number; boxes: number; connected_cars: number } | null;
  lines?: BillingInvoiceLine[];
  /** Plan rule: the prorated amounts of plan changes the invoice will carry. */
  adjustments?: { label: string; amount_ht: number }[];
  vehicles_count: number;
  unit_price: number;
  amount_ht: number;
  amount_ttc: number;
}

/** A customer of Dadycar's Pennylane account. */
export interface PennylaneCustomer {
  id: number;
  name: string | null;
  reg_no: string | null;
  external_reference: string | null;
  emails: string[];
}

/** The Pennylane customer a client's invoices go to, linked by hand (billing automation, part 1). */
export interface PennylaneLinkState {
  enabled: boolean;
  customer_id: string | null;
  customer: PennylaneCustomer | null;
  company_siren: string | null;
  /** The linked customer's SIREN is not the company's: a group or another entity is invoiced. */
  siren_differs: boolean;
  also_linked_to: string[];
  error: string | null;
}

export interface BillingProfilePayload {
  profile: BillingProfile | null;
  /** The products the form offers: the active ones, and those on this contract. */
  products: { key: string; role: BillingProductRole; label: string; list_price: number }[];
  /** Contract rule: the month just ended, and this month so far. */
  last_month: BillingInvoicePreview | null;
  this_month: BillingInvoicePreview | null;
  /** Plan rule: the invoice of the 1st, for the month ahead. */
  next_month?: BillingInvoicePreview | null;
}

/**
 * SEPA direct debit mandate on the Pennylane Compte Pro (billing automation, part 3).
 * phase: none (never asked) · waiting (e-mail sent, not signed) · active (signed) · inactive.
 */
export interface DirectDebitMandateState {
  available: boolean;
  phase: "none" | "waiting" | "active" | "inactive";
  status: string | null;
  requested_on: string | null;
  signed_on: string | null;
  request_source: "client" | "admin" | "auto" | "command" | null;
  requested_by: string | null;
  synced_at: string | null;
  last_error: string | null;
  email: string | null;
  /** Debits the client's bank rejected, the last twelve months. */
  rejects?: {
    invoice_id: number;
    number: string | null;
    amount_ttc: number;
    rejected_on: string;
    debit_status: string | null;
    /** Paid since (card, a new debit, or marked paid). */
    settled: boolean;
  }[];
}

export interface BillingStats {
  total_due: number;
  clients_with_unpaid: number;
  at_risk: number;
  suspended: number;
  currency: string;
}

export interface BillingOption {
  value: string;
  label: string;
}

export interface BillingOptions {
  statuses: BillingOption[];
  payment_modes: BillingOption[];
  lock_overrides: BillingOption[];
}

export interface BillingSettings {
  default_tolerance_months: number;
}

export interface BillingClientRef {
  id: number;
  name: string;
  contact: string | null;
  email: string | null;
}

export interface BillingPlanRef {
  id: number;
  name: string;
  monthly_amount: number;
  monthly_amount_ht?: number;
  price_per_vehicle?: number;
  currency: string;
}

/** Label+color status descriptor (color is a semantic key: success | warning | failure …). */
export interface BillingStatus {
  value: BillingStatusValue;
  label: string;
  color: string;
}

/** One row of the billing clients list. */
export interface BillingClientRow {
  id: number;
  client: BillingClientRef;
  plan: BillingPlanRef | null;
  vehicles_count: number;
  status: BillingStatus;
  unpaid_count: number;
  tolerance_months: number;
  amount_due: number;
  currency: string;
  next_due_date: string | null;
  /** The backend sends the mode with its label. */
  payment_mode: { value: PaymentMode; label: string } | null;
}

/** An unpaid/recent invoice surfaced for reconciliation (Virement). Shape is best-effort. */
export interface BillingInvoice {
  id: number;
  reference?: string | null;
  amount: number;
  currency?: string | null;
  issued_at?: string | null;
  due_date?: string | null;
  period?: string | null;
  status?: string | null;
  paid?: boolean;
}

/** Full "Gérer" detail. Adds the editable config + audit dates. */
export interface BillingClientDetail extends BillingClientRow {
  auto_lock: boolean;
  lock_override: LockOverride;
  /** null = inherit the global default tolerance. */
  tolerance_override: number | null;
  subscription_started_at: string | null;
  last_payment_at: string | null;
  /** Present only when the backend surfaces reconcilable invoices for the client. */
  invoices?: BillingInvoice[];
}

export interface UpdateBillingConfigPayload {
  /** null = inherit global default, else 1–60. */
  billing_tolerance_months?: number | null;
  billing_auto_lock?: boolean;
  billing_lock_override?: LockOverride;
  billing_payment_mode?: PaymentMode;
}

export interface UpdateBillingSettingsPayload {
  default_tolerance_months: number;
}

/** A plan a vehicle can hold (plans per vehicle), at this client's price. */
export interface VehiclePlanOption {
  id: number;
  name: string;
  description: string | null;
  list_price: number;
  /** The client's own price where Dadycar set one, the list price otherwise. HT, per vehicle and month. */
  unit_price: number;
  own_price: boolean;
  on_sale: boolean;
  /** Vehicles holding it now (before the first choice: the vehicles the offer bills). */
  vehicles: number;
}

/**
 * Plans per vehicle (2026-09-28): each vehicle holds the plans it is billed; the company's offer
 * keeps opening its modules. The client is billed by them from the first plan set on a vehicle.
 */
export interface VehiclePlansState {
  in_use: boolean;
  rule: "contract" | "plan";
  /** Invoiced by the monthly run at all. */
  billed: boolean;
  /** Before the first choice, the vehicles a plan client's offer bills (its connected vehicles). */
  /** plan_by_vehicle: the plan each vehicle is billed (the telematics offer: Fleet Business when not connected). */
  billed_by_offer: { plan_id: number; vehicle_ids: number[]; plan_by_vehicle?: Record<number, number> } | null;
  can_edit: boolean;
  /** Taking a plan off a vehicle: Dadycar only (always true here, false on the client's page). */
  can_remove: boolean;
  plans: VehiclePlanOption[];
  vehicles: {
    id: number;
    numberplate: string | null;
    mark: string | null;
    model: string | null;
    connected: boolean;
    plan_ids: number[];
  }[];
  totals: { vehicles: number; with_plan: number; amount_ht: number; currency: string };
  /** After a change: what it did, and the prorata for the rest of an invoiced month. */
  result?: { added: number; removed: number; adjustment: { amount_ht: number; label: string } | null };
}

export interface UpdateVehiclePlansPayload {
  vehicle_ids: number[];
  add: number[];
  remove: number[];
}

/** unit_price null: back to the list price. */
export interface PlanPricePayload {
  subscription_plan_id: number;
  unit_price: number | null;
}

/** Returned by mark-paid ({ result, client }) and suspend/reactivate — bodies aren't relied on (we refetch). */
export interface BillingActionResult {
  result?: unknown;
  client?: BillingClientDetail;
}
