/** * Configuratore guidato (prompt 18): tipi della definizione del wizard (GET /configurator/definition) * e del risultato (POST /configurator/evaluate | submit). Nessuna logica: le regole stanno in apps/api. */ export const CONFIGURATOR_PATHS = ["acqua", "fotovoltaico", "pompa_calore", "azienda"] as const export type ConfiguratorPath = (typeof CONFIGURATOR_PATHS)[number] /** Condizione di visibilità: tutte le condizioni di un elenco devono valere (AND). */ export interface ConfiguratorCondition { question: string /** Risposta (scelta singola) tra questi valori. */ in?: string[] /** Risposta (scelta multipla) che include questo valore. */ includes?: string } export interface ConfiguratorOption { value: string label: string help?: string } interface QuestionBase { id: string label: string help?: string /** Obbligatoria quando visibile. */ required: boolean visibleIf?: ConfiguratorCondition[] } export type ConfiguratorQuestion = | (QuestionBase & { type: "single"; options: ConfiguratorOption[] }) | (QuestionBase & { type: "multi"; options: ConfiguratorOption[]; minSelected: number }) | (QuestionBase & { type: "number"; unit: string; min: number; max: number; step: number }) | (QuestionBase & { type: "province" }) export interface ConfiguratorStep { id: string title: string description?: string visibleIf?: ConfiguratorCondition[] questions: ConfiguratorQuestion[] } export interface ConfiguratorDefinition { version: string steps: ConfiguratorStep[] /** Province per le domande di tipo "province" (sigla + nome). */ provinces: { code: string; name: string }[] } /** Risposte: id domanda → valore (scelta singola e provincia: string; multipla: string[]; numero: number). */ export type ConfiguratorAnswers = Record export interface ConfiguratorResult { /** Versione delle regole usate (per riprodurre il calcolo). */ rulesVersion: string path: ConfiguratorPath solution: { code: string; title: string; description: string } size: { value: number; unit: string; label: string } | null /** Prodotti suggeriti (handle Medusa). */ products: { handle: string; quantity: number; note: string | null }[] /** Stime in centesimi di euro (IVA inclusa); null se non calcolabili per il percorso. */ estimates: { investmentCents: number | null annualSavingsCents: number | null paybackYears: number | null } /** Riepilogo leggibile dei calcoli (etichetta/valore). */ details: { label: string; value: string }[] warnings: string[] incentivesNote: string disclaimer: string }