Skip to main content

datasynth_config/
schema.rs

1//! Configuration schema for synthetic data generation.
2
3use datasynth_core::distributions::{
4    AmountDistributionConfig, DebitCreditDistributionConfig, EvenOddDistributionConfig,
5    LineItemDistributionConfig, SeasonalityConfig,
6};
7use datasynth_core::models::{CoAComplexity, IndustrySector};
8use serde::{Deserialize, Serialize};
9use std::path::PathBuf;
10
11/// Root configuration for the synthetic data generator.
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct GeneratorConfig {
14    /// Global settings
15    pub global: GlobalConfig,
16    /// Company configuration
17    pub companies: Vec<CompanyConfig>,
18    /// Chart of Accounts configuration
19    pub chart_of_accounts: ChartOfAccountsConfig,
20    /// Transaction generation settings
21    #[serde(default)]
22    pub transactions: TransactionConfig,
23    /// Output configuration
24    pub output: OutputConfig,
25    /// Fraud simulation settings
26    #[serde(default)]
27    pub fraud: FraudConfig,
28    /// Data quality variation settings
29    #[serde(default)]
30    pub data_quality: DataQualitySchemaConfig,
31    /// Internal Controls System settings
32    #[serde(default)]
33    pub internal_controls: InternalControlsConfig,
34    /// Business process mix
35    #[serde(default)]
36    pub business_processes: BusinessProcessConfig,
37    /// User persona distribution
38    #[serde(default)]
39    pub user_personas: UserPersonaConfig,
40    /// Template configuration for realistic data
41    #[serde(default)]
42    pub templates: TemplateConfig,
43    /// Approval workflow configuration
44    #[serde(default)]
45    pub approval: ApprovalConfig,
46    /// Department structure configuration
47    #[serde(default)]
48    pub departments: DepartmentConfig,
49    /// Master data generation settings
50    #[serde(default)]
51    pub master_data: MasterDataConfig,
52    /// Document flow generation settings
53    #[serde(default)]
54    pub document_flows: DocumentFlowConfig,
55    /// Intercompany transaction settings
56    #[serde(default)]
57    pub intercompany: IntercompanyConfig,
58    /// Balance and trial balance settings
59    #[serde(default)]
60    pub balance: BalanceConfig,
61    /// OCPM (Object-Centric Process Mining) settings
62    #[serde(default)]
63    pub ocpm: OcpmConfig,
64    /// Audit engagement and workpaper generation settings
65    #[serde(default)]
66    pub audit: AuditGenerationConfig,
67    /// Banking KYC/AML transaction generation settings
68    #[serde(default)]
69    pub banking: datasynth_banking::BankingConfig,
70    /// Scenario configuration for metadata and tagging (Phase 1.3)
71    #[serde(default)]
72    pub scenario: ScenarioConfig,
73    /// Temporal drift configuration for simulating distribution changes over time (Phase 2.2)
74    #[serde(default)]
75    pub temporal: TemporalDriftConfig,
76    /// Graph export configuration for accounting network export
77    #[serde(default)]
78    pub graph_export: GraphExportConfig,
79    /// Streaming output API configuration
80    #[serde(default)]
81    pub streaming: StreamingSchemaConfig,
82    /// Rate limiting configuration
83    #[serde(default)]
84    pub rate_limit: RateLimitSchemaConfig,
85    /// Temporal attribute generation configuration
86    #[serde(default)]
87    pub temporal_attributes: TemporalAttributeSchemaConfig,
88    /// Relationship generation configuration
89    #[serde(default)]
90    pub relationships: RelationshipSchemaConfig,
91    /// Accounting standards framework configuration (IFRS, US GAAP)
92    #[serde(default)]
93    pub accounting_standards: AccountingStandardsConfig,
94    /// Audit standards framework configuration (ISA, PCAOB)
95    #[serde(default)]
96    pub audit_standards: AuditStandardsConfig,
97    /// Advanced distribution configuration (mixture models, correlations, regime changes)
98    #[serde(default)]
99    pub distributions: AdvancedDistributionConfig,
100    /// Temporal patterns configuration (business days, period-end dynamics, processing lags)
101    #[serde(default)]
102    pub temporal_patterns: TemporalPatternsConfig,
103    /// Vendor network configuration (multi-tier supply chain modeling)
104    #[serde(default)]
105    pub vendor_network: VendorNetworkSchemaConfig,
106    /// Customer segmentation configuration (value segments, lifecycle stages)
107    #[serde(default)]
108    pub customer_segmentation: CustomerSegmentationSchemaConfig,
109    /// Relationship strength calculation configuration
110    #[serde(default)]
111    pub relationship_strength: RelationshipStrengthSchemaConfig,
112    /// Cross-process link configuration (P2P ↔ O2C via inventory)
113    #[serde(default)]
114    pub cross_process_links: CrossProcessLinksSchemaConfig,
115    /// Organizational events configuration (acquisitions, divestitures, etc.)
116    #[serde(default)]
117    pub organizational_events: OrganizationalEventsSchemaConfig,
118    /// Behavioral drift configuration (vendor, customer, employee behavior)
119    #[serde(default)]
120    pub behavioral_drift: BehavioralDriftSchemaConfig,
121    /// Market drift configuration (economic cycles, commodities, price shocks)
122    #[serde(default)]
123    pub market_drift: MarketDriftSchemaConfig,
124    /// Drift labeling configuration for ground truth generation
125    #[serde(default)]
126    pub drift_labeling: DriftLabelingSchemaConfig,
127    /// Enhanced anomaly injection configuration (multi-stage schemes, correlated injection, near-miss)
128    #[serde(default)]
129    pub anomaly_injection: EnhancedAnomalyConfig,
130    /// Industry-specific transaction and anomaly generation configuration
131    #[serde(default)]
132    pub industry_specific: IndustrySpecificConfig,
133    /// Fingerprint privacy configuration for extraction/synthesis
134    #[serde(default)]
135    pub fingerprint_privacy: FingerprintPrivacyConfig,
136    /// Quality gate configuration for pass/fail thresholds
137    #[serde(default)]
138    pub quality_gates: QualityGatesSchemaConfig,
139    /// Compliance configuration (EU AI Act, content marking)
140    #[serde(default)]
141    pub compliance: ComplianceSchemaConfig,
142    /// Webhook notification configuration
143    #[serde(default)]
144    pub webhooks: WebhookSchemaConfig,
145    /// LLM enrichment configuration (AI-augmented vendor names, descriptions, explanations)
146    #[serde(default)]
147    pub llm: LlmSchemaConfig,
148    /// Diffusion model configuration (statistical diffusion-based data enhancement)
149    #[serde(default)]
150    pub diffusion: DiffusionSchemaConfig,
151    /// Causal generation configuration (structural causal models, interventions)
152    #[serde(default)]
153    pub causal: CausalSchemaConfig,
154
155    // ===== Enterprise Process Chain Extensions =====
156    /// Source-to-Pay (S2C/S2P) configuration (sourcing, contracts, catalogs, scorecards)
157    #[serde(default)]
158    pub source_to_pay: SourceToPayConfig,
159    /// Financial reporting configuration (financial statements, KPIs, budgets)
160    #[serde(default)]
161    pub financial_reporting: FinancialReportingConfig,
162    /// HR process configuration (payroll, time & attendance, expenses)
163    #[serde(default)]
164    pub hr: HrConfig,
165    /// Manufacturing configuration (production orders, WIP, routing)
166    #[serde(default)]
167    pub manufacturing: ManufacturingProcessConfig,
168    /// Sales quote configuration (quote-to-order pipeline)
169    #[serde(default)]
170    pub sales_quotes: SalesQuoteConfig,
171    /// Tax accounting configuration (VAT/GST, sales tax, withholding, provisions, payroll tax)
172    #[serde(default)]
173    pub tax: TaxConfig,
174    /// Treasury and cash management configuration
175    #[serde(default)]
176    pub treasury: TreasuryConfig,
177    /// Project accounting configuration
178    #[serde(default)]
179    pub project_accounting: ProjectAccountingConfig,
180    /// ESG / Sustainability reporting configuration
181    #[serde(default)]
182    pub esg: EsgConfig,
183    /// Country pack configuration (external packs directory, per-country overrides)
184    #[serde(default)]
185    pub country_packs: Option<CountryPacksSchemaConfig>,
186    /// Counterfactual simulation scenario configuration
187    #[serde(default)]
188    pub scenarios: ScenariosConfig,
189    /// Generation session configuration (period-by-period generation with balance carry-forward)
190    #[serde(default)]
191    pub session: SessionSchemaConfig,
192    /// Compliance regulations framework configuration (standards registry, jurisdictions, temporal versioning, audit templates, graph integration)
193    #[serde(default)]
194    pub compliance_regulations: ComplianceRegulationsConfig,
195}
196
197/// LLM enrichment configuration.
198///
199/// Controls AI-augmented metadata enrichment using LLM providers.
200/// When enabled, vendor names, transaction descriptions, and anomaly explanations
201/// are enriched using the configured provider (mock by default).
202#[derive(Debug, Clone, Serialize, Deserialize)]
203pub struct LlmSchemaConfig {
204    /// Whether LLM enrichment is enabled.
205    #[serde(default)]
206    pub enabled: bool,
207    /// Provider type: "mock", "openai", "anthropic", "custom".
208    #[serde(default = "default_llm_provider")]
209    pub provider: String,
210    /// Model name/ID for the provider.
211    #[serde(default = "default_llm_model_name")]
212    pub model: String,
213    /// Maximum number of vendor names to enrich per run.
214    #[serde(default = "default_llm_batch_size")]
215    pub max_vendor_enrichments: usize,
216}
217
218fn default_llm_provider() -> String {
219    "mock".to_string()
220}
221
222fn default_llm_model_name() -> String {
223    "gpt-4o-mini".to_string()
224}
225
226fn default_llm_batch_size() -> usize {
227    50
228}
229
230impl Default for LlmSchemaConfig {
231    fn default() -> Self {
232        Self {
233            enabled: false,
234            provider: default_llm_provider(),
235            model: default_llm_model_name(),
236            max_vendor_enrichments: default_llm_batch_size(),
237        }
238    }
239}
240
241/// Diffusion model configuration.
242///
243/// Controls statistical diffusion-based data enhancement that generates samples
244/// matching target distribution properties (means, standard deviations, correlations).
245#[derive(Debug, Clone, Serialize, Deserialize)]
246pub struct DiffusionSchemaConfig {
247    /// Whether diffusion enhancement is enabled.
248    #[serde(default)]
249    pub enabled: bool,
250    /// Number of diffusion steps (higher = better quality, slower).
251    #[serde(default = "default_diffusion_steps")]
252    pub n_steps: usize,
253    /// Noise schedule type: "linear", "cosine", "sigmoid".
254    #[serde(default = "default_diffusion_schedule")]
255    pub schedule: String,
256    /// Number of sample rows to generate for demonstration.
257    #[serde(default = "default_diffusion_sample_size")]
258    pub sample_size: usize,
259    /// Backend type: "statistical" (default), "neural", "hybrid".
260    #[serde(default = "default_diffusion_backend")]
261    pub backend: String,
262    /// Neural diffusion backend configuration (used when backend is "neural" or "hybrid").
263    #[serde(default)]
264    pub neural: NeuralDiffusionSchemaConfig,
265}
266
267fn default_diffusion_steps() -> usize {
268    100
269}
270
271fn default_diffusion_schedule() -> String {
272    "linear".to_string()
273}
274
275fn default_diffusion_sample_size() -> usize {
276    100
277}
278
279fn default_diffusion_backend() -> String {
280    "statistical".to_string()
281}
282
283impl Default for DiffusionSchemaConfig {
284    fn default() -> Self {
285        Self {
286            enabled: false,
287            n_steps: default_diffusion_steps(),
288            schedule: default_diffusion_schedule(),
289            sample_size: default_diffusion_sample_size(),
290            backend: default_diffusion_backend(),
291            neural: NeuralDiffusionSchemaConfig::default(),
292        }
293    }
294}
295
296/// Neural diffusion backend configuration.
297///
298/// Controls the `candle`-based neural score network that learns joint distributions
299/// from training data for the neural and hybrid diffusion backends.
300#[derive(Debug, Clone, Serialize, Deserialize)]
301pub struct NeuralDiffusionSchemaConfig {
302    /// Hidden layer dimensions for the score network MLP.
303    #[serde(default = "default_neural_hidden_dims")]
304    pub hidden_dims: Vec<usize>,
305    /// Dimensionality of the timestep embedding.
306    #[serde(default = "default_neural_timestep_embed_dim")]
307    pub timestep_embed_dim: usize,
308    /// Learning rate for training.
309    #[serde(default = "default_neural_learning_rate")]
310    pub learning_rate: f64,
311    /// Number of training epochs.
312    #[serde(default = "default_neural_training_epochs")]
313    pub training_epochs: usize,
314    /// Training batch size.
315    #[serde(default = "default_neural_batch_size")]
316    pub batch_size: usize,
317    /// Blend weight for hybrid mode (0.0 = all statistical, 1.0 = all neural).
318    #[serde(default = "default_neural_hybrid_weight")]
319    pub hybrid_weight: f64,
320    /// Hybrid blending strategy: "weighted_average", "column_select", "threshold".
321    #[serde(default = "default_neural_hybrid_strategy")]
322    pub hybrid_strategy: String,
323    /// Columns to apply neural generation to (empty = all numeric columns).
324    #[serde(default)]
325    pub neural_columns: Vec<String>,
326}
327
328fn default_neural_hidden_dims() -> Vec<usize> {
329    vec![256, 256, 128]
330}
331
332fn default_neural_timestep_embed_dim() -> usize {
333    64
334}
335
336fn default_neural_learning_rate() -> f64 {
337    0.001
338}
339
340fn default_neural_training_epochs() -> usize {
341    100
342}
343
344fn default_neural_batch_size() -> usize {
345    64
346}
347
348fn default_neural_hybrid_weight() -> f64 {
349    0.5
350}
351
352fn default_neural_hybrid_strategy() -> String {
353    "weighted_average".to_string()
354}
355
356impl Default for NeuralDiffusionSchemaConfig {
357    fn default() -> Self {
358        Self {
359            hidden_dims: default_neural_hidden_dims(),
360            timestep_embed_dim: default_neural_timestep_embed_dim(),
361            learning_rate: default_neural_learning_rate(),
362            training_epochs: default_neural_training_epochs(),
363            batch_size: default_neural_batch_size(),
364            hybrid_weight: default_neural_hybrid_weight(),
365            hybrid_strategy: default_neural_hybrid_strategy(),
366            neural_columns: Vec::new(),
367        }
368    }
369}
370
371/// Causal generation configuration.
372///
373/// Controls structural causal model (SCM) based data generation that respects
374/// causal relationships between variables, supports do-calculus interventions,
375/// and enables counterfactual scenarios.
376#[derive(Debug, Clone, Serialize, Deserialize)]
377pub struct CausalSchemaConfig {
378    /// Whether causal generation is enabled.
379    #[serde(default)]
380    pub enabled: bool,
381    /// Built-in template to use: "fraud_detection", "revenue_cycle", or "custom".
382    #[serde(default = "default_causal_template")]
383    pub template: String,
384    /// Number of causal samples to generate.
385    #[serde(default = "default_causal_sample_size")]
386    pub sample_size: usize,
387    /// Whether to run causal validation on the output.
388    #[serde(default = "default_true")]
389    pub validate: bool,
390}
391
392fn default_causal_template() -> String {
393    "fraud_detection".to_string()
394}
395
396fn default_causal_sample_size() -> usize {
397    500
398}
399
400impl Default for CausalSchemaConfig {
401    fn default() -> Self {
402        Self {
403            enabled: false,
404            template: default_causal_template(),
405            sample_size: default_causal_sample_size(),
406            validate: true,
407        }
408    }
409}
410
411/// Graph export configuration for accounting network and ML training exports.
412///
413/// This section enables exporting generated data as graphs for:
414/// - Network reconstruction algorithms
415/// - Graph neural network training
416/// - Neo4j graph database import
417#[derive(Debug, Clone, Serialize, Deserialize)]
418pub struct GraphExportConfig {
419    /// Enable graph export.
420    #[serde(default)]
421    pub enabled: bool,
422
423    /// Graph types to generate.
424    #[serde(default = "default_graph_types")]
425    pub graph_types: Vec<GraphTypeConfig>,
426
427    /// Export formats to generate.
428    #[serde(default = "default_graph_formats")]
429    pub formats: Vec<GraphExportFormat>,
430
431    /// Train split ratio for ML datasets.
432    #[serde(default = "default_train_ratio")]
433    pub train_ratio: f64,
434
435    /// Validation split ratio for ML datasets.
436    #[serde(default = "default_val_ratio")]
437    pub validation_ratio: f64,
438
439    /// Random seed for train/val/test splits.
440    #[serde(default)]
441    pub split_seed: Option<u64>,
442
443    /// Output subdirectory for graph exports (relative to output directory).
444    #[serde(default = "default_graph_subdir")]
445    pub output_subdirectory: String,
446
447    /// Multi-layer hypergraph export settings for RustGraph integration.
448    #[serde(default)]
449    pub hypergraph: HypergraphExportSettings,
450
451    /// DGL-specific export settings.
452    #[serde(default)]
453    pub dgl: DglExportConfig,
454}
455
456fn default_graph_types() -> Vec<GraphTypeConfig> {
457    vec![GraphTypeConfig::default()]
458}
459
460fn default_graph_formats() -> Vec<GraphExportFormat> {
461    vec![GraphExportFormat::PytorchGeometric]
462}
463
464fn default_train_ratio() -> f64 {
465    0.7
466}
467
468fn default_val_ratio() -> f64 {
469    0.15
470}
471
472fn default_graph_subdir() -> String {
473    "graphs".to_string()
474}
475
476impl Default for GraphExportConfig {
477    fn default() -> Self {
478        Self {
479            enabled: false,
480            graph_types: default_graph_types(),
481            formats: default_graph_formats(),
482            train_ratio: 0.7,
483            validation_ratio: 0.15,
484            split_seed: None,
485            output_subdirectory: "graphs".to_string(),
486            hypergraph: HypergraphExportSettings::default(),
487            dgl: DglExportConfig::default(),
488        }
489    }
490}
491
492/// DGL-specific export settings.
493#[derive(Debug, Clone, Default, Serialize, Deserialize)]
494pub struct DglExportConfig {
495    /// Export as a heterogeneous graph (distinct node/edge types).
496    ///
497    /// When `true` the DGL exporter produces a `HeteroData` object with typed
498    /// node and edge stores rather than a single homogeneous graph.
499    /// Set to `true` in `graph_export.dgl.heterogeneous: true` in YAML.
500    #[serde(default)]
501    pub heterogeneous: bool,
502}
503
504// Default derived: heterogeneous = false (bool default)
505
506/// Settings for the multi-layer hypergraph export (RustGraph integration).
507///
508/// Produces a 3-layer hypergraph:
509/// - Layer 1: Governance & Controls (COSO, SOX, internal controls, organizational)
510/// - Layer 2: Process Events (P2P/O2C document flows, OCPM events)
511/// - Layer 3: Accounting Network (GL accounts, journal entries as hyperedges)
512#[derive(Debug, Clone, Serialize, Deserialize)]
513pub struct HypergraphExportSettings {
514    /// Enable hypergraph export.
515    #[serde(default)]
516    pub enabled: bool,
517
518    /// Maximum total nodes across all layers (default 50000).
519    #[serde(default = "default_hypergraph_max_nodes")]
520    pub max_nodes: usize,
521
522    /// Aggregation strategy when node budget is exceeded.
523    #[serde(default = "default_aggregation_strategy")]
524    pub aggregation_strategy: String,
525
526    /// Layer 1 (Governance & Controls) settings.
527    #[serde(default)]
528    pub governance_layer: GovernanceLayerSettings,
529
530    /// Layer 2 (Process Events) settings.
531    #[serde(default)]
532    pub process_layer: ProcessLayerSettings,
533
534    /// Layer 3 (Accounting Network) settings.
535    #[serde(default)]
536    pub accounting_layer: AccountingLayerSettings,
537
538    /// Cross-layer edge generation settings.
539    #[serde(default)]
540    pub cross_layer: CrossLayerSettings,
541
542    /// Output subdirectory for hypergraph files (relative to graph output directory).
543    #[serde(default = "default_hypergraph_subdir")]
544    pub output_subdirectory: String,
545
546    /// Output format: "native" (default) for internal field names, "unified" for RustGraph format.
547    #[serde(default = "default_hypergraph_format")]
548    pub output_format: String,
549
550    /// Optional URL for streaming unified JSONL to a RustGraph ingest endpoint.
551    #[serde(default)]
552    pub stream_target: Option<String>,
553
554    /// Batch size for streaming (number of JSONL lines per HTTP POST). Default: 1000.
555    #[serde(default = "default_stream_batch_size")]
556    pub stream_batch_size: usize,
557}
558
559fn default_hypergraph_max_nodes() -> usize {
560    50_000
561}
562
563fn default_aggregation_strategy() -> String {
564    "pool_by_counterparty".to_string()
565}
566
567fn default_hypergraph_subdir() -> String {
568    "hypergraph".to_string()
569}
570
571fn default_hypergraph_format() -> String {
572    "native".to_string()
573}
574
575fn default_stream_batch_size() -> usize {
576    1000
577}
578
579impl Default for HypergraphExportSettings {
580    fn default() -> Self {
581        Self {
582            enabled: false,
583            max_nodes: 50_000,
584            aggregation_strategy: "pool_by_counterparty".to_string(),
585            governance_layer: GovernanceLayerSettings::default(),
586            process_layer: ProcessLayerSettings::default(),
587            accounting_layer: AccountingLayerSettings::default(),
588            cross_layer: CrossLayerSettings::default(),
589            output_subdirectory: "hypergraph".to_string(),
590            output_format: "native".to_string(),
591            stream_target: None,
592            stream_batch_size: 1000,
593        }
594    }
595}
596
597/// Layer 1: Governance & Controls layer settings.
598#[derive(Debug, Clone, Serialize, Deserialize)]
599pub struct GovernanceLayerSettings {
600    /// Include COSO framework nodes (5 components + 17 principles).
601    #[serde(default = "default_true")]
602    pub include_coso: bool,
603    /// Include internal control nodes.
604    #[serde(default = "default_true")]
605    pub include_controls: bool,
606    /// Include SOX assertion nodes.
607    #[serde(default = "default_true")]
608    pub include_sox: bool,
609    /// Include vendor master data nodes.
610    #[serde(default = "default_true")]
611    pub include_vendors: bool,
612    /// Include customer master data nodes.
613    #[serde(default = "default_true")]
614    pub include_customers: bool,
615    /// Include employee/organizational nodes.
616    #[serde(default = "default_true")]
617    pub include_employees: bool,
618}
619
620impl Default for GovernanceLayerSettings {
621    fn default() -> Self {
622        Self {
623            include_coso: true,
624            include_controls: true,
625            include_sox: true,
626            include_vendors: true,
627            include_customers: true,
628            include_employees: true,
629        }
630    }
631}
632
633/// Layer 2: Process Events layer settings.
634#[derive(Debug, Clone, Serialize, Deserialize)]
635pub struct ProcessLayerSettings {
636    /// Include P2P (Procure-to-Pay) document flow nodes.
637    #[serde(default = "default_true")]
638    pub include_p2p: bool,
639    /// Include O2C (Order-to-Cash) document flow nodes.
640    #[serde(default = "default_true")]
641    pub include_o2c: bool,
642    /// Include S2C (Source-to-Contract) document flow nodes.
643    #[serde(default = "default_true")]
644    pub include_s2c: bool,
645    /// Include H2R (Hire-to-Retire) document flow nodes.
646    #[serde(default = "default_true")]
647    pub include_h2r: bool,
648    /// Include MFG (Manufacturing) document flow nodes.
649    #[serde(default = "default_true")]
650    pub include_mfg: bool,
651    /// Include BANK (Banking) document flow nodes.
652    #[serde(default = "default_true")]
653    pub include_bank: bool,
654    /// Include AUDIT document flow nodes.
655    #[serde(default = "default_true")]
656    pub include_audit: bool,
657    /// Include R2R (Record-to-Report) document flow nodes (bank recon + period close).
658    #[serde(default = "default_true")]
659    pub include_r2r: bool,
660    /// Export OCPM events as hyperedges.
661    #[serde(default = "default_true")]
662    pub events_as_hyperedges: bool,
663    /// Threshold: if a counterparty has more documents than this, aggregate into pool nodes.
664    #[serde(default = "default_docs_per_counterparty_threshold")]
665    pub docs_per_counterparty_threshold: usize,
666}
667
668fn default_docs_per_counterparty_threshold() -> usize {
669    20
670}
671
672impl Default for ProcessLayerSettings {
673    fn default() -> Self {
674        Self {
675            include_p2p: true,
676            include_o2c: true,
677            include_s2c: true,
678            include_h2r: true,
679            include_mfg: true,
680            include_bank: true,
681            include_audit: true,
682            include_r2r: true,
683            events_as_hyperedges: true,
684            docs_per_counterparty_threshold: 20,
685        }
686    }
687}
688
689/// Layer 3: Accounting Network layer settings.
690#[derive(Debug, Clone, Serialize, Deserialize)]
691pub struct AccountingLayerSettings {
692    /// Include GL account nodes.
693    #[serde(default = "default_true")]
694    pub include_accounts: bool,
695    /// Export journal entries as hyperedges (debit+credit accounts as participants).
696    #[serde(default = "default_true")]
697    pub je_as_hyperedges: bool,
698}
699
700impl Default for AccountingLayerSettings {
701    fn default() -> Self {
702        Self {
703            include_accounts: true,
704            je_as_hyperedges: true,
705        }
706    }
707}
708
709/// Cross-layer edge generation settings.
710#[derive(Debug, Clone, Serialize, Deserialize)]
711pub struct CrossLayerSettings {
712    /// Generate cross-layer edges (Control→Account, Vendor→PO, etc.).
713    #[serde(default = "default_true")]
714    pub enabled: bool,
715}
716
717impl Default for CrossLayerSettings {
718    fn default() -> Self {
719        Self { enabled: true }
720    }
721}
722
723/// Configuration for a specific graph type to export.
724#[derive(Debug, Clone, Serialize, Deserialize)]
725pub struct GraphTypeConfig {
726    /// Name identifier for this graph configuration.
727    #[serde(default = "default_graph_name")]
728    pub name: String,
729
730    /// Whether to aggregate parallel edges between the same nodes.
731    #[serde(default)]
732    pub aggregate_edges: bool,
733
734    /// Minimum edge weight to include (filters out small transactions).
735    #[serde(default)]
736    pub min_edge_weight: f64,
737
738    /// Whether to include document nodes (creates hub-and-spoke structure).
739    #[serde(default)]
740    pub include_document_nodes: bool,
741}
742
743fn default_graph_name() -> String {
744    "accounting_network".to_string()
745}
746
747impl Default for GraphTypeConfig {
748    fn default() -> Self {
749        Self {
750            name: "accounting_network".to_string(),
751            aggregate_edges: false,
752            min_edge_weight: 0.0,
753            include_document_nodes: false,
754        }
755    }
756}
757
758/// Export format for graph data.
759#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
760#[serde(rename_all = "snake_case")]
761pub enum GraphExportFormat {
762    /// PyTorch Geometric format (.npy files + metadata.json).
763    PytorchGeometric,
764    /// Neo4j format (CSV files + Cypher import scripts).
765    Neo4j,
766    /// Deep Graph Library format.
767    Dgl,
768    /// RustGraph/RustAssureTwin JSON format.
769    RustGraph,
770    /// RustGraph multi-layer hypergraph format (nodes.jsonl + edges.jsonl + hyperedges.jsonl).
771    RustGraphHypergraph,
772}
773
774/// Scenario configuration for metadata, tagging, and ML training setup.
775///
776/// This section enables tracking the purpose and characteristics of a generation run.
777#[derive(Debug, Clone, Default, Serialize, Deserialize)]
778pub struct ScenarioConfig {
779    /// Tags for categorizing and filtering datasets.
780    /// Examples: "fraud_detection", "retail", "month_end_stress", "ml_training"
781    #[serde(default)]
782    pub tags: Vec<String>,
783
784    /// Data quality profile preset.
785    /// - "clean": Minimal data quality issues (0.1% missing, 0.05% typos)
786    /// - "noisy": Moderate issues (5% missing, 2% typos, 1% duplicates)
787    /// - "legacy": Heavy issues simulating legacy system data (10% missing, 5% typos)
788    #[serde(default)]
789    pub profile: Option<String>,
790
791    /// Human-readable description of the scenario purpose.
792    #[serde(default)]
793    pub description: Option<String>,
794
795    /// Whether this run is for ML training (enables balanced labeling).
796    #[serde(default)]
797    pub ml_training: bool,
798
799    /// Target anomaly class balance for ML training.
800    /// If set, anomalies will be injected to achieve this ratio.
801    #[serde(default)]
802    pub target_anomaly_ratio: Option<f64>,
803
804    /// Custom metadata key-value pairs.
805    #[serde(default)]
806    pub metadata: std::collections::HashMap<String, String>,
807}
808
809/// Temporal drift configuration for simulating distribution changes over time.
810///
811/// This enables generation of data that shows realistic temporal evolution,
812/// useful for training drift detection models and testing temporal robustness.
813#[derive(Debug, Clone, Serialize, Deserialize)]
814pub struct TemporalDriftConfig {
815    /// Enable temporal drift simulation.
816    #[serde(default)]
817    pub enabled: bool,
818
819    /// Amount mean drift per period (e.g., 0.02 = 2% mean shift per month).
820    /// Simulates gradual inflation or business growth.
821    #[serde(default = "default_amount_drift")]
822    pub amount_mean_drift: f64,
823
824    /// Amount variance drift per period (e.g., 0.01 = 1% variance increase per month).
825    /// Simulates increasing volatility over time.
826    #[serde(default)]
827    pub amount_variance_drift: f64,
828
829    /// Anomaly rate drift per period (e.g., 0.001 = 0.1% increase per month).
830    /// Simulates increasing fraud attempts or degrading controls.
831    #[serde(default)]
832    pub anomaly_rate_drift: f64,
833
834    /// Concept drift rate - how quickly feature distributions change (0.0-1.0).
835    /// Higher values cause more rapid distribution shifts.
836    #[serde(default = "default_concept_drift")]
837    pub concept_drift_rate: f64,
838
839    /// Sudden drift events - probability of a sudden distribution shift in any period.
840    #[serde(default)]
841    pub sudden_drift_probability: f64,
842
843    /// Magnitude of sudden drift events when they occur (multiplier).
844    #[serde(default = "default_sudden_drift_magnitude")]
845    pub sudden_drift_magnitude: f64,
846
847    /// Seasonal drift - enable cyclic patterns that repeat annually.
848    #[serde(default)]
849    pub seasonal_drift: bool,
850
851    /// Drift start period (0 = from beginning). Use to simulate stable baseline before drift.
852    #[serde(default)]
853    pub drift_start_period: u32,
854
855    /// Drift type: "gradual", "sudden", "recurring", "mixed"
856    #[serde(default = "default_drift_type")]
857    pub drift_type: DriftType,
858}
859
860fn default_amount_drift() -> f64 {
861    0.02
862}
863
864fn default_concept_drift() -> f64 {
865    0.01
866}
867
868fn default_sudden_drift_magnitude() -> f64 {
869    2.0
870}
871
872fn default_drift_type() -> DriftType {
873    DriftType::Gradual
874}
875
876impl Default for TemporalDriftConfig {
877    fn default() -> Self {
878        Self {
879            enabled: false,
880            amount_mean_drift: 0.02,
881            amount_variance_drift: 0.0,
882            anomaly_rate_drift: 0.0,
883            concept_drift_rate: 0.01,
884            sudden_drift_probability: 0.0,
885            sudden_drift_magnitude: 2.0,
886            seasonal_drift: false,
887            drift_start_period: 0,
888            drift_type: DriftType::Gradual,
889        }
890    }
891}
892
893impl TemporalDriftConfig {
894    /// Convert to core DriftConfig for use in generators.
895    pub fn to_core_config(&self) -> datasynth_core::distributions::DriftConfig {
896        datasynth_core::distributions::DriftConfig {
897            enabled: self.enabled,
898            amount_mean_drift: self.amount_mean_drift,
899            amount_variance_drift: self.amount_variance_drift,
900            anomaly_rate_drift: self.anomaly_rate_drift,
901            concept_drift_rate: self.concept_drift_rate,
902            sudden_drift_probability: self.sudden_drift_probability,
903            sudden_drift_magnitude: self.sudden_drift_magnitude,
904            seasonal_drift: self.seasonal_drift,
905            drift_start_period: self.drift_start_period,
906            drift_type: match self.drift_type {
907                DriftType::Gradual => datasynth_core::distributions::DriftType::Gradual,
908                DriftType::Sudden => datasynth_core::distributions::DriftType::Sudden,
909                DriftType::Recurring => datasynth_core::distributions::DriftType::Recurring,
910                DriftType::Mixed => datasynth_core::distributions::DriftType::Mixed,
911            },
912            regime_changes: Vec::new(),
913            economic_cycle: Default::default(),
914            parameter_drifts: Vec::new(),
915        }
916    }
917}
918
919/// Types of temporal drift patterns.
920#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
921#[serde(rename_all = "snake_case")]
922pub enum DriftType {
923    /// Gradual, continuous drift over time (like inflation).
924    #[default]
925    Gradual,
926    /// Sudden, point-in-time shifts (like policy changes).
927    Sudden,
928    /// Recurring patterns that cycle (like seasonal variations).
929    Recurring,
930    /// Combination of gradual background drift with occasional sudden shifts.
931    Mixed,
932}
933
934// ============================================================================
935// Streaming Output API Configuration (Phase 2)
936// ============================================================================
937
938/// Configuration for streaming output API.
939#[derive(Debug, Clone, Serialize, Deserialize)]
940pub struct StreamingSchemaConfig {
941    /// Enable streaming output.
942    #[serde(default)]
943    pub enabled: bool,
944    /// Target events per second (0 = unlimited, default 0).
945    #[serde(default)]
946    pub events_per_second: f64,
947    /// Token bucket burst size (default 100).
948    #[serde(default = "default_burst_size")]
949    pub burst_size: u32,
950    /// Buffer size for streaming (number of items).
951    #[serde(default = "default_buffer_size")]
952    pub buffer_size: usize,
953    /// Enable progress reporting.
954    #[serde(default = "default_true")]
955    pub enable_progress: bool,
956    /// Progress reporting interval (number of items).
957    #[serde(default = "default_progress_interval")]
958    pub progress_interval: u64,
959    /// Backpressure strategy.
960    #[serde(default)]
961    pub backpressure: BackpressureSchemaStrategy,
962}
963
964fn default_buffer_size() -> usize {
965    1000
966}
967
968fn default_progress_interval() -> u64 {
969    100
970}
971
972impl Default for StreamingSchemaConfig {
973    fn default() -> Self {
974        Self {
975            enabled: false,
976            events_per_second: 0.0,
977            burst_size: 100,
978            buffer_size: 1000,
979            enable_progress: true,
980            progress_interval: 100,
981            backpressure: BackpressureSchemaStrategy::Block,
982        }
983    }
984}
985
986/// Backpressure strategy for streaming output.
987#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
988#[serde(rename_all = "snake_case")]
989pub enum BackpressureSchemaStrategy {
990    /// Block until space is available in the buffer.
991    #[default]
992    Block,
993    /// Drop oldest items when buffer is full.
994    DropOldest,
995    /// Drop newest items when buffer is full.
996    DropNewest,
997    /// Buffer overflow items up to a limit, then block.
998    Buffer,
999}
1000
1001// ============================================================================
1002// Rate Limiting Configuration (Phase 5)
1003// ============================================================================
1004
1005/// Configuration for rate limiting.
1006#[derive(Debug, Clone, Serialize, Deserialize)]
1007pub struct RateLimitSchemaConfig {
1008    /// Enable rate limiting.
1009    #[serde(default)]
1010    pub enabled: bool,
1011    /// Entities per second limit.
1012    #[serde(default = "default_entities_per_second")]
1013    pub entities_per_second: f64,
1014    /// Burst size (number of tokens in bucket).
1015    #[serde(default = "default_burst_size")]
1016    pub burst_size: u32,
1017    /// Backpressure strategy for rate limiting.
1018    #[serde(default)]
1019    pub backpressure: RateLimitBackpressureSchema,
1020}
1021
1022fn default_entities_per_second() -> f64 {
1023    1000.0
1024}
1025
1026fn default_burst_size() -> u32 {
1027    100
1028}
1029
1030impl Default for RateLimitSchemaConfig {
1031    fn default() -> Self {
1032        Self {
1033            enabled: false,
1034            entities_per_second: 1000.0,
1035            burst_size: 100,
1036            backpressure: RateLimitBackpressureSchema::Block,
1037        }
1038    }
1039}
1040
1041/// Backpressure strategy for rate limiting.
1042#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
1043#[serde(rename_all = "snake_case")]
1044pub enum RateLimitBackpressureSchema {
1045    /// Block until rate allows.
1046    #[default]
1047    Block,
1048    /// Drop items that exceed rate.
1049    Drop,
1050    /// Buffer items and process when rate allows.
1051    Buffer,
1052}
1053
1054// ============================================================================
1055// Temporal Attribute Generation Configuration (Phase 3)
1056// ============================================================================
1057
1058/// Configuration for temporal attribute generation.
1059#[derive(Debug, Clone, Serialize, Deserialize)]
1060pub struct TemporalAttributeSchemaConfig {
1061    /// Enable temporal attribute generation.
1062    #[serde(default)]
1063    pub enabled: bool,
1064    /// Valid time configuration.
1065    #[serde(default)]
1066    pub valid_time: ValidTimeSchemaConfig,
1067    /// Transaction time configuration.
1068    #[serde(default)]
1069    pub transaction_time: TransactionTimeSchemaConfig,
1070    /// Generate version chains for entities.
1071    #[serde(default)]
1072    pub generate_version_chains: bool,
1073    /// Average number of versions per entity.
1074    #[serde(default = "default_avg_versions")]
1075    pub avg_versions_per_entity: f64,
1076}
1077
1078fn default_avg_versions() -> f64 {
1079    1.5
1080}
1081
1082impl Default for TemporalAttributeSchemaConfig {
1083    fn default() -> Self {
1084        Self {
1085            enabled: false,
1086            valid_time: ValidTimeSchemaConfig::default(),
1087            transaction_time: TransactionTimeSchemaConfig::default(),
1088            generate_version_chains: false,
1089            avg_versions_per_entity: 1.5,
1090        }
1091    }
1092}
1093
1094/// Configuration for valid time (business time) generation.
1095#[derive(Debug, Clone, Serialize, Deserialize)]
1096pub struct ValidTimeSchemaConfig {
1097    /// Probability that valid_to is set (entity has ended validity).
1098    #[serde(default = "default_closed_probability")]
1099    pub closed_probability: f64,
1100    /// Average validity duration in days.
1101    #[serde(default = "default_avg_validity_days")]
1102    pub avg_validity_days: u32,
1103    /// Standard deviation of validity duration in days.
1104    #[serde(default = "default_validity_stddev")]
1105    pub validity_stddev_days: u32,
1106}
1107
1108fn default_closed_probability() -> f64 {
1109    0.1
1110}
1111
1112fn default_avg_validity_days() -> u32 {
1113    365
1114}
1115
1116fn default_validity_stddev() -> u32 {
1117    90
1118}
1119
1120impl Default for ValidTimeSchemaConfig {
1121    fn default() -> Self {
1122        Self {
1123            closed_probability: 0.1,
1124            avg_validity_days: 365,
1125            validity_stddev_days: 90,
1126        }
1127    }
1128}
1129
1130/// Configuration for transaction time (system time) generation.
1131#[derive(Debug, Clone, Serialize, Deserialize)]
1132pub struct TransactionTimeSchemaConfig {
1133    /// Average recording delay in seconds (0 = immediate).
1134    #[serde(default)]
1135    pub avg_recording_delay_seconds: u32,
1136    /// Allow backdating (recording time before valid time).
1137    #[serde(default)]
1138    pub allow_backdating: bool,
1139    /// Probability of backdating if allowed.
1140    #[serde(default = "default_backdating_probability")]
1141    pub backdating_probability: f64,
1142    /// Maximum backdate days.
1143    #[serde(default = "default_max_backdate_days")]
1144    pub max_backdate_days: u32,
1145}
1146
1147fn default_backdating_probability() -> f64 {
1148    0.01
1149}
1150
1151fn default_max_backdate_days() -> u32 {
1152    30
1153}
1154
1155impl Default for TransactionTimeSchemaConfig {
1156    fn default() -> Self {
1157        Self {
1158            avg_recording_delay_seconds: 0,
1159            allow_backdating: false,
1160            backdating_probability: 0.01,
1161            max_backdate_days: 30,
1162        }
1163    }
1164}
1165
1166// ============================================================================
1167// Relationship Generation Configuration (Phase 4)
1168// ============================================================================
1169
1170/// Configuration for relationship generation.
1171#[derive(Debug, Clone, Serialize, Deserialize)]
1172pub struct RelationshipSchemaConfig {
1173    /// Relationship type definitions.
1174    #[serde(default)]
1175    pub relationship_types: Vec<RelationshipTypeSchemaConfig>,
1176    /// Allow orphan entities (entities with no relationships).
1177    #[serde(default = "default_true")]
1178    pub allow_orphans: bool,
1179    /// Probability of creating an orphan entity.
1180    #[serde(default = "default_orphan_probability")]
1181    pub orphan_probability: f64,
1182    /// Allow circular relationships.
1183    #[serde(default)]
1184    pub allow_circular: bool,
1185    /// Maximum depth for circular relationship detection.
1186    #[serde(default = "default_max_circular_depth")]
1187    pub max_circular_depth: u32,
1188}
1189
1190fn default_orphan_probability() -> f64 {
1191    0.01
1192}
1193
1194fn default_max_circular_depth() -> u32 {
1195    3
1196}
1197
1198impl Default for RelationshipSchemaConfig {
1199    fn default() -> Self {
1200        Self {
1201            relationship_types: Vec::new(),
1202            allow_orphans: true,
1203            orphan_probability: 0.01,
1204            allow_circular: false,
1205            max_circular_depth: 3,
1206        }
1207    }
1208}
1209
1210/// Configuration for a specific relationship type.
1211#[derive(Debug, Clone, Serialize, Deserialize)]
1212pub struct RelationshipTypeSchemaConfig {
1213    /// Name of the relationship type (e.g., "debits", "credits", "created").
1214    pub name: String,
1215    /// Source entity type (e.g., "journal_entry").
1216    pub source_type: String,
1217    /// Target entity type (e.g., "account").
1218    pub target_type: String,
1219    /// Cardinality rule for this relationship.
1220    #[serde(default)]
1221    pub cardinality: CardinalitySchemaRule,
1222    /// Weight for this relationship in random selection.
1223    #[serde(default = "default_relationship_weight")]
1224    pub weight: f64,
1225    /// Whether this relationship is required.
1226    #[serde(default)]
1227    pub required: bool,
1228    /// Whether this relationship is directed.
1229    #[serde(default = "default_true")]
1230    pub directed: bool,
1231}
1232
1233fn default_relationship_weight() -> f64 {
1234    1.0
1235}
1236
1237impl Default for RelationshipTypeSchemaConfig {
1238    fn default() -> Self {
1239        Self {
1240            name: String::new(),
1241            source_type: String::new(),
1242            target_type: String::new(),
1243            cardinality: CardinalitySchemaRule::default(),
1244            weight: 1.0,
1245            required: false,
1246            directed: true,
1247        }
1248    }
1249}
1250
1251/// Cardinality rule for relationships in schema config.
1252#[derive(Debug, Clone, Serialize, Deserialize)]
1253#[serde(rename_all = "snake_case")]
1254pub enum CardinalitySchemaRule {
1255    /// One source to one target.
1256    OneToOne,
1257    /// One source to many targets.
1258    OneToMany {
1259        /// Minimum number of targets.
1260        min: u32,
1261        /// Maximum number of targets.
1262        max: u32,
1263    },
1264    /// Many sources to one target.
1265    ManyToOne {
1266        /// Minimum number of sources.
1267        min: u32,
1268        /// Maximum number of sources.
1269        max: u32,
1270    },
1271    /// Many sources to many targets.
1272    ManyToMany {
1273        /// Minimum targets per source.
1274        min_per_source: u32,
1275        /// Maximum targets per source.
1276        max_per_source: u32,
1277    },
1278}
1279
1280impl Default for CardinalitySchemaRule {
1281    fn default() -> Self {
1282        Self::OneToMany { min: 1, max: 5 }
1283    }
1284}
1285
1286/// Global configuration settings.
1287#[derive(Debug, Clone, Serialize, Deserialize)]
1288pub struct GlobalConfig {
1289    /// Random seed for reproducibility
1290    pub seed: Option<u64>,
1291    /// Industry sector
1292    pub industry: IndustrySector,
1293    /// Simulation start date (YYYY-MM-DD)
1294    pub start_date: String,
1295    /// Simulation period in months
1296    pub period_months: u32,
1297    /// Base currency for group reporting
1298    #[serde(default = "default_currency")]
1299    pub group_currency: String,
1300    /// Presentation currency for consolidated financial statements (ISO 4217).
1301    /// If not set, defaults to `group_currency`.
1302    #[serde(default)]
1303    pub presentation_currency: Option<String>,
1304    /// Enable parallel generation
1305    #[serde(default = "default_true")]
1306    pub parallel: bool,
1307    /// Number of worker threads (0 = auto-detect)
1308    #[serde(default)]
1309    pub worker_threads: usize,
1310    /// Memory limit in MB (0 = unlimited)
1311    #[serde(default)]
1312    pub memory_limit_mb: usize,
1313    /// Fiscal year length in months (defaults to 12 if not set).
1314    /// Used by session-based generation to split the total period into fiscal years.
1315    #[serde(default)]
1316    pub fiscal_year_months: Option<u32>,
1317}
1318
1319fn default_currency() -> String {
1320    "USD".to_string()
1321}
1322fn default_true() -> bool {
1323    true
1324}
1325
1326/// Configuration for generation session behavior.
1327///
1328/// When enabled, the generation pipeline splits the total period into fiscal years
1329/// and generates data period-by-period, carrying forward balance state.
1330#[derive(Debug, Clone, Serialize, Deserialize)]
1331pub struct SessionSchemaConfig {
1332    /// Whether session-based (period-by-period) generation is enabled.
1333    #[serde(default)]
1334    pub enabled: bool,
1335    /// Optional path for saving/loading session checkpoint files.
1336    #[serde(default)]
1337    pub checkpoint_path: Option<String>,
1338    /// Whether to write output files per fiscal period (e.g., `period_01/`).
1339    #[serde(default = "default_true")]
1340    pub per_period_output: bool,
1341    /// Whether to also produce a single consolidated output across all periods.
1342    #[serde(default = "default_true")]
1343    pub consolidated_output: bool,
1344}
1345
1346impl Default for SessionSchemaConfig {
1347    fn default() -> Self {
1348        Self {
1349            enabled: false,
1350            checkpoint_path: None,
1351            per_period_output: true,
1352            consolidated_output: true,
1353        }
1354    }
1355}
1356
1357/// Company code configuration.
1358#[derive(Debug, Clone, Serialize, Deserialize)]
1359pub struct CompanyConfig {
1360    /// Company code identifier
1361    pub code: String,
1362    /// Company name
1363    pub name: String,
1364    /// Local currency (ISO 4217)
1365    pub currency: String,
1366    /// Functional currency for IAS 21 translation (ISO 4217).
1367    /// If not set, defaults to the `currency` field (i.e. local == functional).
1368    #[serde(default)]
1369    pub functional_currency: Option<String>,
1370    /// Country code (ISO 3166-1 alpha-2)
1371    pub country: String,
1372    /// Fiscal year variant
1373    #[serde(default = "default_fiscal_variant")]
1374    pub fiscal_year_variant: String,
1375    /// Transaction volume per year
1376    pub annual_transaction_volume: TransactionVolume,
1377    /// Company-specific transaction weight
1378    #[serde(default = "default_weight")]
1379    pub volume_weight: f64,
1380}
1381
1382fn default_fiscal_variant() -> String {
1383    "K4".to_string()
1384}
1385fn default_weight() -> f64 {
1386    1.0
1387}
1388
1389/// Transaction volume presets.
1390#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1391#[serde(rename_all = "snake_case")]
1392pub enum TransactionVolume {
1393    /// 10,000 transactions per year
1394    TenK,
1395    /// 100,000 transactions per year
1396    HundredK,
1397    /// 1,000,000 transactions per year
1398    OneM,
1399    /// 10,000,000 transactions per year
1400    TenM,
1401    /// 100,000,000 transactions per year
1402    HundredM,
1403    /// Custom count
1404    Custom(u64),
1405}
1406
1407impl TransactionVolume {
1408    /// Get the transaction count.
1409    pub fn count(&self) -> u64 {
1410        match self {
1411            Self::TenK => 10_000,
1412            Self::HundredK => 100_000,
1413            Self::OneM => 1_000_000,
1414            Self::TenM => 10_000_000,
1415            Self::HundredM => 100_000_000,
1416            Self::Custom(n) => *n,
1417        }
1418    }
1419}
1420
1421/// Chart of Accounts configuration.
1422#[derive(Debug, Clone, Serialize, Deserialize)]
1423pub struct ChartOfAccountsConfig {
1424    /// CoA complexity level
1425    pub complexity: CoAComplexity,
1426    /// Use industry-specific accounts
1427    #[serde(default = "default_true")]
1428    pub industry_specific: bool,
1429    /// Custom account definitions file
1430    pub custom_accounts: Option<PathBuf>,
1431    /// Minimum hierarchy depth
1432    #[serde(default = "default_min_depth")]
1433    pub min_hierarchy_depth: u8,
1434    /// Maximum hierarchy depth
1435    #[serde(default = "default_max_depth")]
1436    pub max_hierarchy_depth: u8,
1437}
1438
1439fn default_min_depth() -> u8 {
1440    2
1441}
1442fn default_max_depth() -> u8 {
1443    5
1444}
1445
1446impl Default for ChartOfAccountsConfig {
1447    fn default() -> Self {
1448        Self {
1449            complexity: CoAComplexity::Small,
1450            industry_specific: true,
1451            custom_accounts: None,
1452            min_hierarchy_depth: default_min_depth(),
1453            max_hierarchy_depth: default_max_depth(),
1454        }
1455    }
1456}
1457
1458/// Transaction generation configuration.
1459#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1460pub struct TransactionConfig {
1461    /// Line item distribution
1462    #[serde(default)]
1463    pub line_item_distribution: LineItemDistributionConfig,
1464    /// Debit/credit balance distribution
1465    #[serde(default)]
1466    pub debit_credit_distribution: DebitCreditDistributionConfig,
1467    /// Even/odd line count distribution
1468    #[serde(default)]
1469    pub even_odd_distribution: EvenOddDistributionConfig,
1470    /// Transaction source distribution
1471    #[serde(default)]
1472    pub source_distribution: SourceDistribution,
1473    /// Seasonality configuration
1474    #[serde(default)]
1475    pub seasonality: SeasonalityConfig,
1476    /// Amount distribution
1477    #[serde(default)]
1478    pub amounts: AmountDistributionConfig,
1479    /// Benford's Law compliance configuration
1480    #[serde(default)]
1481    pub benford: BenfordConfig,
1482}
1483
1484/// Benford's Law compliance configuration.
1485#[derive(Debug, Clone, Serialize, Deserialize)]
1486pub struct BenfordConfig {
1487    /// Enable Benford's Law compliance for amount generation
1488    #[serde(default = "default_true")]
1489    pub enabled: bool,
1490    /// Tolerance for deviation from ideal Benford distribution (0.0-1.0)
1491    #[serde(default = "default_benford_tolerance")]
1492    pub tolerance: f64,
1493    /// Transaction sources exempt from Benford's Law (fixed amounts)
1494    #[serde(default)]
1495    pub exempt_sources: Vec<BenfordExemption>,
1496}
1497
1498fn default_benford_tolerance() -> f64 {
1499    0.05
1500}
1501
1502impl Default for BenfordConfig {
1503    fn default() -> Self {
1504        Self {
1505            enabled: true,
1506            tolerance: default_benford_tolerance(),
1507            exempt_sources: vec![BenfordExemption::Recurring, BenfordExemption::Payroll],
1508        }
1509    }
1510}
1511
1512/// Types of transactions exempt from Benford's Law.
1513#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1514#[serde(rename_all = "snake_case")]
1515pub enum BenfordExemption {
1516    /// Recurring fixed amounts (rent, subscriptions)
1517    Recurring,
1518    /// Payroll (standardized salaries)
1519    Payroll,
1520    /// Fixed fees and charges
1521    FixedFees,
1522    /// Round number purchases (often legitimate)
1523    RoundAmounts,
1524}
1525
1526/// Distribution of transaction sources.
1527#[derive(Debug, Clone, Serialize, Deserialize)]
1528pub struct SourceDistribution {
1529    /// Manual entries percentage
1530    pub manual: f64,
1531    /// Automated system entries
1532    pub automated: f64,
1533    /// Recurring entries
1534    pub recurring: f64,
1535    /// Adjustment entries
1536    pub adjustment: f64,
1537}
1538
1539impl Default for SourceDistribution {
1540    fn default() -> Self {
1541        Self {
1542            manual: 0.20,
1543            automated: 0.70,
1544            recurring: 0.07,
1545            adjustment: 0.03,
1546        }
1547    }
1548}
1549
1550/// Output configuration.
1551#[derive(Debug, Clone, Serialize, Deserialize)]
1552pub struct OutputConfig {
1553    /// Output mode
1554    #[serde(default)]
1555    pub mode: OutputMode,
1556    /// Output directory
1557    pub output_directory: PathBuf,
1558    /// File formats to generate
1559    #[serde(default = "default_formats")]
1560    pub formats: Vec<FileFormat>,
1561    /// Compression settings
1562    #[serde(default)]
1563    pub compression: CompressionConfig,
1564    /// Batch size for writes
1565    #[serde(default = "default_batch_size")]
1566    pub batch_size: usize,
1567    /// Include ACDOCA format
1568    #[serde(default = "default_true")]
1569    pub include_acdoca: bool,
1570    /// Include BSEG format
1571    #[serde(default)]
1572    pub include_bseg: bool,
1573    /// Partition by fiscal period
1574    #[serde(default = "default_true")]
1575    pub partition_by_period: bool,
1576    /// Partition by company code
1577    #[serde(default)]
1578    pub partition_by_company: bool,
1579    /// Numeric serialization mode for JSON output.
1580    /// "string" (default): decimals as `"1729237.30"` — lossless precision.
1581    /// "native": decimals as `1729237.30` — friendlier for pandas/analytics.
1582    #[serde(default)]
1583    pub numeric_mode: NumericMode,
1584    /// JSON export layout for journal entries and document flows.
1585    /// "nested" (default): `{"header": {...}, "lines": [...]}` — natural ERP structure.
1586    /// "flat": header fields repeated on every line — friendlier for analytics/ML.
1587    #[serde(default)]
1588    pub export_layout: ExportLayout,
1589}
1590
1591fn default_formats() -> Vec<FileFormat> {
1592    vec![FileFormat::Parquet]
1593}
1594fn default_batch_size() -> usize {
1595    100_000
1596}
1597
1598impl Default for OutputConfig {
1599    fn default() -> Self {
1600        Self {
1601            mode: OutputMode::FlatFile,
1602            output_directory: PathBuf::from("./output"),
1603            formats: default_formats(),
1604            compression: CompressionConfig::default(),
1605            batch_size: default_batch_size(),
1606            include_acdoca: true,
1607            include_bseg: false,
1608            partition_by_period: true,
1609            partition_by_company: false,
1610            numeric_mode: NumericMode::default(),
1611            export_layout: ExportLayout::default(),
1612        }
1613    }
1614}
1615
1616/// Numeric serialization mode for JSON decimal fields.
1617#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
1618#[serde(rename_all = "snake_case")]
1619pub enum NumericMode {
1620    /// Decimals as JSON strings (e.g. `"1729237.30"`). Preserves full precision.
1621    #[default]
1622    String,
1623    /// Decimals as JSON numbers (e.g. `1729237.30`). Friendlier for pandas/analytics.
1624    Native,
1625}
1626
1627/// JSON export layout for nested structures (journal entries, document flows).
1628#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
1629#[serde(rename_all = "snake_case")]
1630pub enum ExportLayout {
1631    /// Nested structure: `{"header": {...}, "lines": [...]}`. Natural ERP format.
1632    #[default]
1633    Nested,
1634    /// Flat structure: header fields repeated on every line. Analytics-friendly.
1635    Flat,
1636}
1637
1638/// Output mode.
1639#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1640#[serde(rename_all = "snake_case")]
1641pub enum OutputMode {
1642    /// Stream records as generated
1643    Streaming,
1644    /// Write to flat files
1645    #[default]
1646    FlatFile,
1647    /// Both streaming and flat file
1648    Both,
1649}
1650
1651/// Supported file formats.
1652#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1653#[serde(rename_all = "snake_case")]
1654pub enum FileFormat {
1655    Csv,
1656    Parquet,
1657    Json,
1658    JsonLines,
1659}
1660
1661/// Compression configuration.
1662#[derive(Debug, Clone, Serialize, Deserialize)]
1663pub struct CompressionConfig {
1664    /// Enable compression
1665    #[serde(default = "default_true")]
1666    pub enabled: bool,
1667    /// Compression algorithm
1668    #[serde(default)]
1669    pub algorithm: CompressionAlgorithm,
1670    /// Compression level (1-9)
1671    #[serde(default = "default_compression_level")]
1672    pub level: u8,
1673}
1674
1675fn default_compression_level() -> u8 {
1676    3
1677}
1678
1679impl Default for CompressionConfig {
1680    fn default() -> Self {
1681        Self {
1682            enabled: true,
1683            algorithm: CompressionAlgorithm::default(),
1684            level: default_compression_level(),
1685        }
1686    }
1687}
1688
1689/// Compression algorithms.
1690#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1691#[serde(rename_all = "snake_case")]
1692pub enum CompressionAlgorithm {
1693    Gzip,
1694    #[default]
1695    Zstd,
1696    Lz4,
1697    Snappy,
1698}
1699
1700/// Fraud simulation configuration.
1701///
1702/// ## Document-level vs. line-level fraud
1703///
1704/// `fraud_rate` applies to individual journal-entry lines (line-level).
1705/// `document_fraud_rate` (optional) applies to source documents
1706/// (purchase orders, vendor invoices, customer invoices, payments), and when
1707/// `propagate_to_lines` is true, every JE derived from a fraudulent document
1708/// also gets `is_fraud = true`. This lets users express either:
1709///
1710///  * pure line-level fraud (`document_fraud_rate = None`): legacy behaviour;
1711///  * pure document-level fraud (`fraud_rate ≈ 0` and `document_fraud_rate` set):
1712///    fraud rings expressed at document granularity — realistic for PO/invoice
1713///    fraud schemes where one fraudulent document spawns multiple derived JEs;
1714///  * hybrid (both set): document-level scheme fraud plus unrelated line-level
1715///    slip-ups.
1716///
1717/// `propagate_to_document` does the inverse: when a JE is tagged as fraud by
1718/// the anomaly injector, its source document is also marked fraudulent.
1719#[derive(Debug, Clone, Serialize, Deserialize)]
1720pub struct FraudConfig {
1721    /// Enable fraud scenario generation
1722    #[serde(default)]
1723    pub enabled: bool,
1724    /// Line-level fraud rate: fraction of individual JE lines flagged as fraud (0.0 to 1.0).
1725    #[serde(default = "default_fraud_rate")]
1726    pub fraud_rate: f64,
1727    /// Document-level fraud rate: fraction of source documents (PO, vendor
1728    /// invoice, customer invoice, payment) flagged as fraud. `None` disables
1729    /// document-level injection; `Some(r)` marks ~r × document-count as fraud
1730    /// independently of the line-level rate.
1731    #[serde(default)]
1732    pub document_fraud_rate: Option<f64>,
1733    /// When true, flagging a document as fraudulent cascades `is_fraud = true`
1734    /// and `fraud_type` to every journal entry derived from that document,
1735    /// and records `fraud_source_document_id` on the JE header.
1736    /// Default: `true`.
1737    #[serde(default = "default_true")]
1738    pub propagate_to_lines: bool,
1739    /// When true, tagging a JE as fraud via line-level anomaly injection also
1740    /// marks the JE's source document as fraudulent (if it can be resolved).
1741    /// Default: `true`.
1742    #[serde(default = "default_true")]
1743    pub propagate_to_document: bool,
1744    /// Fraud type distribution
1745    #[serde(default)]
1746    pub fraud_type_distribution: FraudTypeDistribution,
1747    /// Enable fraud clustering
1748    #[serde(default)]
1749    pub clustering_enabled: bool,
1750    /// Clustering factor
1751    #[serde(default = "default_clustering_factor")]
1752    pub clustering_factor: f64,
1753    /// Approval thresholds for threshold-adjacent fraud pattern
1754    #[serde(default = "default_approval_thresholds")]
1755    pub approval_thresholds: Vec<f64>,
1756}
1757
1758fn default_approval_thresholds() -> Vec<f64> {
1759    vec![1000.0, 5000.0, 10000.0, 25000.0, 50000.0, 100000.0]
1760}
1761
1762fn default_fraud_rate() -> f64 {
1763    0.005
1764}
1765fn default_clustering_factor() -> f64 {
1766    3.0
1767}
1768
1769impl Default for FraudConfig {
1770    fn default() -> Self {
1771        Self {
1772            enabled: false,
1773            fraud_rate: default_fraud_rate(),
1774            document_fraud_rate: None,
1775            propagate_to_lines: true,
1776            propagate_to_document: true,
1777            fraud_type_distribution: FraudTypeDistribution::default(),
1778            clustering_enabled: false,
1779            clustering_factor: default_clustering_factor(),
1780            approval_thresholds: default_approval_thresholds(),
1781        }
1782    }
1783}
1784
1785/// Distribution of fraud types.
1786#[derive(Debug, Clone, Serialize, Deserialize)]
1787pub struct FraudTypeDistribution {
1788    pub suspense_account_abuse: f64,
1789    pub fictitious_transaction: f64,
1790    pub revenue_manipulation: f64,
1791    pub expense_capitalization: f64,
1792    pub split_transaction: f64,
1793    pub timing_anomaly: f64,
1794    pub unauthorized_access: f64,
1795    pub duplicate_payment: f64,
1796}
1797
1798impl Default for FraudTypeDistribution {
1799    fn default() -> Self {
1800        Self {
1801            suspense_account_abuse: 0.25,
1802            fictitious_transaction: 0.15,
1803            revenue_manipulation: 0.10,
1804            expense_capitalization: 0.10,
1805            split_transaction: 0.15,
1806            timing_anomaly: 0.10,
1807            unauthorized_access: 0.10,
1808            duplicate_payment: 0.05,
1809        }
1810    }
1811}
1812
1813/// Internal Controls System (ICS) configuration.
1814#[derive(Debug, Clone, Serialize, Deserialize)]
1815pub struct InternalControlsConfig {
1816    /// Enable internal controls system
1817    #[serde(default)]
1818    pub enabled: bool,
1819    /// Rate at which controls result in exceptions (0.0 - 1.0)
1820    #[serde(default = "default_exception_rate")]
1821    pub exception_rate: f64,
1822    /// Rate at which SoD violations occur (0.0 - 1.0)
1823    #[serde(default = "default_sod_violation_rate")]
1824    pub sod_violation_rate: f64,
1825    /// Export control master data to separate files
1826    #[serde(default = "default_true")]
1827    pub export_control_master_data: bool,
1828    /// SOX materiality threshold for marking transactions as SOX-relevant
1829    #[serde(default = "default_sox_materiality_threshold")]
1830    pub sox_materiality_threshold: f64,
1831    /// Enable COSO 2013 framework integration
1832    #[serde(default = "default_true")]
1833    pub coso_enabled: bool,
1834    /// Include entity-level controls in generation
1835    #[serde(default)]
1836    pub include_entity_level_controls: bool,
1837    /// Target maturity level for controls
1838    /// Valid values: "ad_hoc", "repeatable", "defined", "managed", "optimized", "mixed"
1839    #[serde(default = "default_target_maturity_level")]
1840    pub target_maturity_level: String,
1841}
1842
1843fn default_exception_rate() -> f64 {
1844    0.02
1845}
1846
1847fn default_sod_violation_rate() -> f64 {
1848    0.01
1849}
1850
1851fn default_sox_materiality_threshold() -> f64 {
1852    10000.0
1853}
1854
1855fn default_target_maturity_level() -> String {
1856    "mixed".to_string()
1857}
1858
1859impl Default for InternalControlsConfig {
1860    fn default() -> Self {
1861        Self {
1862            enabled: false,
1863            exception_rate: default_exception_rate(),
1864            sod_violation_rate: default_sod_violation_rate(),
1865            export_control_master_data: true,
1866            sox_materiality_threshold: default_sox_materiality_threshold(),
1867            coso_enabled: true,
1868            include_entity_level_controls: false,
1869            target_maturity_level: default_target_maturity_level(),
1870        }
1871    }
1872}
1873
1874/// Business process configuration.
1875#[derive(Debug, Clone, Serialize, Deserialize)]
1876pub struct BusinessProcessConfig {
1877    /// Order-to-Cash weight
1878    #[serde(default = "default_o2c")]
1879    pub o2c_weight: f64,
1880    /// Procure-to-Pay weight
1881    #[serde(default = "default_p2p")]
1882    pub p2p_weight: f64,
1883    /// Record-to-Report weight
1884    #[serde(default = "default_r2r")]
1885    pub r2r_weight: f64,
1886    /// Hire-to-Retire weight
1887    #[serde(default = "default_h2r")]
1888    pub h2r_weight: f64,
1889    /// Acquire-to-Retire weight
1890    #[serde(default = "default_a2r")]
1891    pub a2r_weight: f64,
1892}
1893
1894fn default_o2c() -> f64 {
1895    0.35
1896}
1897fn default_p2p() -> f64 {
1898    0.30
1899}
1900fn default_r2r() -> f64 {
1901    0.20
1902}
1903fn default_h2r() -> f64 {
1904    0.10
1905}
1906fn default_a2r() -> f64 {
1907    0.05
1908}
1909
1910impl Default for BusinessProcessConfig {
1911    fn default() -> Self {
1912        Self {
1913            o2c_weight: default_o2c(),
1914            p2p_weight: default_p2p(),
1915            r2r_weight: default_r2r(),
1916            h2r_weight: default_h2r(),
1917            a2r_weight: default_a2r(),
1918        }
1919    }
1920}
1921
1922/// User persona configuration.
1923#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1924pub struct UserPersonaConfig {
1925    /// Distribution of user personas
1926    #[serde(default)]
1927    pub persona_distribution: PersonaDistribution,
1928    /// Users per persona type
1929    #[serde(default)]
1930    pub users_per_persona: UsersPerPersona,
1931}
1932
1933/// Distribution of user personas for transaction generation.
1934#[derive(Debug, Clone, Serialize, Deserialize)]
1935pub struct PersonaDistribution {
1936    pub junior_accountant: f64,
1937    pub senior_accountant: f64,
1938    pub controller: f64,
1939    pub manager: f64,
1940    pub automated_system: f64,
1941}
1942
1943impl Default for PersonaDistribution {
1944    fn default() -> Self {
1945        Self {
1946            junior_accountant: 0.15,
1947            senior_accountant: 0.15,
1948            controller: 0.05,
1949            manager: 0.05,
1950            automated_system: 0.60,
1951        }
1952    }
1953}
1954
1955/// Number of users per persona type.
1956#[derive(Debug, Clone, Serialize, Deserialize)]
1957pub struct UsersPerPersona {
1958    pub junior_accountant: usize,
1959    pub senior_accountant: usize,
1960    pub controller: usize,
1961    pub manager: usize,
1962    pub automated_system: usize,
1963}
1964
1965impl Default for UsersPerPersona {
1966    fn default() -> Self {
1967        Self {
1968            junior_accountant: 10,
1969            senior_accountant: 5,
1970            controller: 2,
1971            manager: 3,
1972            automated_system: 20,
1973        }
1974    }
1975}
1976
1977/// Template configuration for realistic data generation.
1978#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1979pub struct TemplateConfig {
1980    /// Name generation settings
1981    #[serde(default)]
1982    pub names: NameTemplateConfig,
1983    /// Description generation settings
1984    #[serde(default)]
1985    pub descriptions: DescriptionTemplateConfig,
1986    /// Reference number settings
1987    #[serde(default)]
1988    pub references: ReferenceTemplateConfig,
1989}
1990
1991/// Name template configuration.
1992#[derive(Debug, Clone, Serialize, Deserialize)]
1993pub struct NameTemplateConfig {
1994    /// Distribution of name cultures
1995    #[serde(default)]
1996    pub culture_distribution: CultureDistribution,
1997    /// Email domain for generated users
1998    #[serde(default = "default_email_domain")]
1999    pub email_domain: String,
2000    /// Generate realistic display names
2001    #[serde(default = "default_true")]
2002    pub generate_realistic_names: bool,
2003}
2004
2005fn default_email_domain() -> String {
2006    "company.com".to_string()
2007}
2008
2009impl Default for NameTemplateConfig {
2010    fn default() -> Self {
2011        Self {
2012            culture_distribution: CultureDistribution::default(),
2013            email_domain: default_email_domain(),
2014            generate_realistic_names: true,
2015        }
2016    }
2017}
2018
2019/// Distribution of name cultures for generation.
2020#[derive(Debug, Clone, Serialize, Deserialize)]
2021pub struct CultureDistribution {
2022    pub western_us: f64,
2023    pub hispanic: f64,
2024    pub german: f64,
2025    pub french: f64,
2026    pub chinese: f64,
2027    pub japanese: f64,
2028    pub indian: f64,
2029}
2030
2031impl Default for CultureDistribution {
2032    fn default() -> Self {
2033        Self {
2034            western_us: 0.40,
2035            hispanic: 0.20,
2036            german: 0.10,
2037            french: 0.05,
2038            chinese: 0.10,
2039            japanese: 0.05,
2040            indian: 0.10,
2041        }
2042    }
2043}
2044
2045/// Description template configuration.
2046#[derive(Debug, Clone, Serialize, Deserialize)]
2047pub struct DescriptionTemplateConfig {
2048    /// Generate header text for journal entries
2049    #[serde(default = "default_true")]
2050    pub generate_header_text: bool,
2051    /// Generate line text for journal entry lines
2052    #[serde(default = "default_true")]
2053    pub generate_line_text: bool,
2054}
2055
2056impl Default for DescriptionTemplateConfig {
2057    fn default() -> Self {
2058        Self {
2059            generate_header_text: true,
2060            generate_line_text: true,
2061        }
2062    }
2063}
2064
2065/// Reference number template configuration.
2066#[derive(Debug, Clone, Serialize, Deserialize)]
2067pub struct ReferenceTemplateConfig {
2068    /// Generate reference numbers
2069    #[serde(default = "default_true")]
2070    pub generate_references: bool,
2071    /// Invoice prefix
2072    #[serde(default = "default_invoice_prefix")]
2073    pub invoice_prefix: String,
2074    /// Purchase order prefix
2075    #[serde(default = "default_po_prefix")]
2076    pub po_prefix: String,
2077    /// Sales order prefix
2078    #[serde(default = "default_so_prefix")]
2079    pub so_prefix: String,
2080}
2081
2082fn default_invoice_prefix() -> String {
2083    "INV".to_string()
2084}
2085fn default_po_prefix() -> String {
2086    "PO".to_string()
2087}
2088fn default_so_prefix() -> String {
2089    "SO".to_string()
2090}
2091
2092impl Default for ReferenceTemplateConfig {
2093    fn default() -> Self {
2094        Self {
2095            generate_references: true,
2096            invoice_prefix: default_invoice_prefix(),
2097            po_prefix: default_po_prefix(),
2098            so_prefix: default_so_prefix(),
2099        }
2100    }
2101}
2102
2103/// Approval workflow configuration.
2104#[derive(Debug, Clone, Serialize, Deserialize)]
2105pub struct ApprovalConfig {
2106    /// Enable approval workflow generation
2107    #[serde(default)]
2108    pub enabled: bool,
2109    /// Threshold below which transactions are auto-approved
2110    #[serde(default = "default_auto_approve_threshold")]
2111    pub auto_approve_threshold: f64,
2112    /// Rate at which approvals are rejected (0.0 to 1.0)
2113    #[serde(default = "default_rejection_rate")]
2114    pub rejection_rate: f64,
2115    /// Rate at which approvals require revision (0.0 to 1.0)
2116    #[serde(default = "default_revision_rate")]
2117    pub revision_rate: f64,
2118    /// Average delay in hours for approval processing
2119    #[serde(default = "default_approval_delay_hours")]
2120    pub average_approval_delay_hours: f64,
2121    /// Approval chain thresholds
2122    #[serde(default)]
2123    pub thresholds: Vec<ApprovalThresholdConfig>,
2124}
2125
2126fn default_auto_approve_threshold() -> f64 {
2127    1000.0
2128}
2129fn default_rejection_rate() -> f64 {
2130    0.02
2131}
2132fn default_revision_rate() -> f64 {
2133    0.05
2134}
2135fn default_approval_delay_hours() -> f64 {
2136    4.0
2137}
2138
2139impl Default for ApprovalConfig {
2140    fn default() -> Self {
2141        Self {
2142            enabled: false,
2143            auto_approve_threshold: default_auto_approve_threshold(),
2144            rejection_rate: default_rejection_rate(),
2145            revision_rate: default_revision_rate(),
2146            average_approval_delay_hours: default_approval_delay_hours(),
2147            thresholds: vec![
2148                ApprovalThresholdConfig {
2149                    amount: 1000.0,
2150                    level: 1,
2151                    roles: vec!["senior_accountant".to_string()],
2152                },
2153                ApprovalThresholdConfig {
2154                    amount: 10000.0,
2155                    level: 2,
2156                    roles: vec!["senior_accountant".to_string(), "controller".to_string()],
2157                },
2158                ApprovalThresholdConfig {
2159                    amount: 100000.0,
2160                    level: 3,
2161                    roles: vec![
2162                        "senior_accountant".to_string(),
2163                        "controller".to_string(),
2164                        "manager".to_string(),
2165                    ],
2166                },
2167                ApprovalThresholdConfig {
2168                    amount: 500000.0,
2169                    level: 4,
2170                    roles: vec![
2171                        "senior_accountant".to_string(),
2172                        "controller".to_string(),
2173                        "manager".to_string(),
2174                        "executive".to_string(),
2175                    ],
2176                },
2177            ],
2178        }
2179    }
2180}
2181
2182/// Configuration for a single approval threshold.
2183#[derive(Debug, Clone, Serialize, Deserialize)]
2184pub struct ApprovalThresholdConfig {
2185    /// Amount threshold
2186    pub amount: f64,
2187    /// Approval level required
2188    pub level: u8,
2189    /// Roles that can approve at this level
2190    pub roles: Vec<String>,
2191}
2192
2193/// Department configuration.
2194#[derive(Debug, Clone, Serialize, Deserialize)]
2195pub struct DepartmentConfig {
2196    /// Enable department assignment
2197    #[serde(default)]
2198    pub enabled: bool,
2199    /// Multiplier for department headcounts
2200    #[serde(default = "default_headcount_multiplier")]
2201    pub headcount_multiplier: f64,
2202    /// Custom department definitions (optional)
2203    #[serde(default)]
2204    pub custom_departments: Vec<CustomDepartmentConfig>,
2205}
2206
2207fn default_headcount_multiplier() -> f64 {
2208    1.0
2209}
2210
2211impl Default for DepartmentConfig {
2212    fn default() -> Self {
2213        Self {
2214            enabled: false,
2215            headcount_multiplier: default_headcount_multiplier(),
2216            custom_departments: Vec::new(),
2217        }
2218    }
2219}
2220
2221/// Custom department definition.
2222#[derive(Debug, Clone, Serialize, Deserialize)]
2223pub struct CustomDepartmentConfig {
2224    /// Department code
2225    pub code: String,
2226    /// Department name
2227    pub name: String,
2228    /// Associated cost center
2229    #[serde(default)]
2230    pub cost_center: Option<String>,
2231    /// Primary business processes
2232    #[serde(default)]
2233    pub primary_processes: Vec<String>,
2234    /// Parent department code
2235    #[serde(default)]
2236    pub parent_code: Option<String>,
2237}
2238
2239// ============================================================================
2240// Master Data Configuration
2241// ============================================================================
2242
2243/// Master data generation configuration.
2244#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2245pub struct MasterDataConfig {
2246    /// Vendor master data settings
2247    #[serde(default)]
2248    pub vendors: VendorMasterConfig,
2249    /// Customer master data settings
2250    #[serde(default)]
2251    pub customers: CustomerMasterConfig,
2252    /// Material master data settings
2253    #[serde(default)]
2254    pub materials: MaterialMasterConfig,
2255    /// Fixed asset master data settings
2256    #[serde(default)]
2257    pub fixed_assets: FixedAssetMasterConfig,
2258    /// Employee master data settings
2259    #[serde(default)]
2260    pub employees: EmployeeMasterConfig,
2261    /// Cost center master data settings
2262    #[serde(default)]
2263    pub cost_centers: CostCenterMasterConfig,
2264}
2265
2266/// Vendor master data configuration.
2267#[derive(Debug, Clone, Serialize, Deserialize)]
2268pub struct VendorMasterConfig {
2269    /// Number of vendors to generate
2270    #[serde(default = "default_vendor_count")]
2271    pub count: usize,
2272    /// Percentage of vendors that are intercompany (0.0 to 1.0)
2273    #[serde(default = "default_intercompany_percent")]
2274    pub intercompany_percent: f64,
2275    /// Payment terms distribution
2276    #[serde(default)]
2277    pub payment_terms_distribution: PaymentTermsDistribution,
2278    /// Vendor behavior distribution
2279    #[serde(default)]
2280    pub behavior_distribution: VendorBehaviorDistribution,
2281    /// Generate bank account details
2282    #[serde(default = "default_true")]
2283    pub generate_bank_accounts: bool,
2284    /// Generate tax IDs
2285    #[serde(default = "default_true")]
2286    pub generate_tax_ids: bool,
2287}
2288
2289fn default_vendor_count() -> usize {
2290    500
2291}
2292
2293fn default_intercompany_percent() -> f64 {
2294    0.05
2295}
2296
2297impl Default for VendorMasterConfig {
2298    fn default() -> Self {
2299        Self {
2300            count: default_vendor_count(),
2301            intercompany_percent: default_intercompany_percent(),
2302            payment_terms_distribution: PaymentTermsDistribution::default(),
2303            behavior_distribution: VendorBehaviorDistribution::default(),
2304            generate_bank_accounts: true,
2305            generate_tax_ids: true,
2306        }
2307    }
2308}
2309
2310/// Payment terms distribution for vendors.
2311#[derive(Debug, Clone, Serialize, Deserialize)]
2312pub struct PaymentTermsDistribution {
2313    /// Net 30 days
2314    pub net_30: f64,
2315    /// Net 60 days
2316    pub net_60: f64,
2317    /// Net 90 days
2318    pub net_90: f64,
2319    /// 2% 10 Net 30 (early payment discount)
2320    pub two_ten_net_30: f64,
2321    /// Due on receipt
2322    pub due_on_receipt: f64,
2323    /// End of month
2324    pub end_of_month: f64,
2325}
2326
2327impl Default for PaymentTermsDistribution {
2328    fn default() -> Self {
2329        Self {
2330            net_30: 0.40,
2331            net_60: 0.20,
2332            net_90: 0.10,
2333            two_ten_net_30: 0.15,
2334            due_on_receipt: 0.05,
2335            end_of_month: 0.10,
2336        }
2337    }
2338}
2339
2340/// Vendor behavior distribution.
2341#[derive(Debug, Clone, Serialize, Deserialize)]
2342pub struct VendorBehaviorDistribution {
2343    /// Reliable vendors (consistent delivery, quality)
2344    pub reliable: f64,
2345    /// Sometimes late vendors
2346    pub sometimes_late: f64,
2347    /// Inconsistent quality vendors
2348    pub inconsistent_quality: f64,
2349    /// Premium vendors (high quality, premium pricing)
2350    pub premium: f64,
2351    /// Budget vendors (lower quality, lower pricing)
2352    pub budget: f64,
2353}
2354
2355impl Default for VendorBehaviorDistribution {
2356    fn default() -> Self {
2357        Self {
2358            reliable: 0.50,
2359            sometimes_late: 0.20,
2360            inconsistent_quality: 0.10,
2361            premium: 0.10,
2362            budget: 0.10,
2363        }
2364    }
2365}
2366
2367/// Customer master data configuration.
2368#[derive(Debug, Clone, Serialize, Deserialize)]
2369pub struct CustomerMasterConfig {
2370    /// Number of customers to generate
2371    #[serde(default = "default_customer_count")]
2372    pub count: usize,
2373    /// Percentage of customers that are intercompany (0.0 to 1.0)
2374    #[serde(default = "default_intercompany_percent")]
2375    pub intercompany_percent: f64,
2376    /// Credit rating distribution
2377    #[serde(default)]
2378    pub credit_rating_distribution: CreditRatingDistribution,
2379    /// Payment behavior distribution
2380    #[serde(default)]
2381    pub payment_behavior_distribution: PaymentBehaviorDistribution,
2382    /// Generate credit limits based on rating
2383    #[serde(default = "default_true")]
2384    pub generate_credit_limits: bool,
2385}
2386
2387fn default_customer_count() -> usize {
2388    2000
2389}
2390
2391impl Default for CustomerMasterConfig {
2392    fn default() -> Self {
2393        Self {
2394            count: default_customer_count(),
2395            intercompany_percent: default_intercompany_percent(),
2396            credit_rating_distribution: CreditRatingDistribution::default(),
2397            payment_behavior_distribution: PaymentBehaviorDistribution::default(),
2398            generate_credit_limits: true,
2399        }
2400    }
2401}
2402
2403/// Credit rating distribution for customers.
2404#[derive(Debug, Clone, Serialize, Deserialize)]
2405pub struct CreditRatingDistribution {
2406    /// AAA rating
2407    pub aaa: f64,
2408    /// AA rating
2409    pub aa: f64,
2410    /// A rating
2411    pub a: f64,
2412    /// BBB rating
2413    pub bbb: f64,
2414    /// BB rating
2415    pub bb: f64,
2416    /// B rating
2417    pub b: f64,
2418    /// Below B rating
2419    pub below_b: f64,
2420}
2421
2422impl Default for CreditRatingDistribution {
2423    fn default() -> Self {
2424        Self {
2425            aaa: 0.05,
2426            aa: 0.10,
2427            a: 0.20,
2428            bbb: 0.30,
2429            bb: 0.20,
2430            b: 0.10,
2431            below_b: 0.05,
2432        }
2433    }
2434}
2435
2436/// Payment behavior distribution for customers.
2437#[derive(Debug, Clone, Serialize, Deserialize)]
2438pub struct PaymentBehaviorDistribution {
2439    /// Always pays early
2440    pub early_payer: f64,
2441    /// Pays on time
2442    pub on_time: f64,
2443    /// Occasionally late
2444    pub occasional_late: f64,
2445    /// Frequently late
2446    pub frequent_late: f64,
2447    /// Takes early payment discounts
2448    pub discount_taker: f64,
2449}
2450
2451impl Default for PaymentBehaviorDistribution {
2452    fn default() -> Self {
2453        Self {
2454            early_payer: 0.10,
2455            on_time: 0.50,
2456            occasional_late: 0.25,
2457            frequent_late: 0.10,
2458            discount_taker: 0.05,
2459        }
2460    }
2461}
2462
2463/// Material master data configuration.
2464#[derive(Debug, Clone, Serialize, Deserialize)]
2465pub struct MaterialMasterConfig {
2466    /// Number of materials to generate
2467    #[serde(default = "default_material_count")]
2468    pub count: usize,
2469    /// Material type distribution
2470    #[serde(default)]
2471    pub type_distribution: MaterialTypeDistribution,
2472    /// Valuation method distribution
2473    #[serde(default)]
2474    pub valuation_distribution: ValuationMethodDistribution,
2475    /// Percentage of materials with BOM (bill of materials)
2476    #[serde(default = "default_bom_percent")]
2477    pub bom_percent: f64,
2478    /// Maximum BOM depth
2479    #[serde(default = "default_max_bom_depth")]
2480    pub max_bom_depth: u8,
2481}
2482
2483fn default_material_count() -> usize {
2484    5000
2485}
2486
2487fn default_bom_percent() -> f64 {
2488    0.20
2489}
2490
2491fn default_max_bom_depth() -> u8 {
2492    3
2493}
2494
2495impl Default for MaterialMasterConfig {
2496    fn default() -> Self {
2497        Self {
2498            count: default_material_count(),
2499            type_distribution: MaterialTypeDistribution::default(),
2500            valuation_distribution: ValuationMethodDistribution::default(),
2501            bom_percent: default_bom_percent(),
2502            max_bom_depth: default_max_bom_depth(),
2503        }
2504    }
2505}
2506
2507/// Material type distribution.
2508#[derive(Debug, Clone, Serialize, Deserialize)]
2509pub struct MaterialTypeDistribution {
2510    /// Raw materials
2511    pub raw_material: f64,
2512    /// Semi-finished goods
2513    pub semi_finished: f64,
2514    /// Finished goods
2515    pub finished_good: f64,
2516    /// Trading goods (purchased for resale)
2517    pub trading_good: f64,
2518    /// Operating supplies
2519    pub operating_supply: f64,
2520    /// Services
2521    pub service: f64,
2522}
2523
2524impl Default for MaterialTypeDistribution {
2525    fn default() -> Self {
2526        Self {
2527            raw_material: 0.30,
2528            semi_finished: 0.15,
2529            finished_good: 0.25,
2530            trading_good: 0.15,
2531            operating_supply: 0.10,
2532            service: 0.05,
2533        }
2534    }
2535}
2536
2537/// Valuation method distribution for materials.
2538#[derive(Debug, Clone, Serialize, Deserialize)]
2539pub struct ValuationMethodDistribution {
2540    /// Standard cost
2541    pub standard_cost: f64,
2542    /// Moving average
2543    pub moving_average: f64,
2544    /// FIFO (First In, First Out)
2545    pub fifo: f64,
2546    /// LIFO (Last In, First Out)
2547    pub lifo: f64,
2548}
2549
2550impl Default for ValuationMethodDistribution {
2551    fn default() -> Self {
2552        Self {
2553            standard_cost: 0.50,
2554            moving_average: 0.30,
2555            fifo: 0.15,
2556            lifo: 0.05,
2557        }
2558    }
2559}
2560
2561/// Fixed asset master data configuration.
2562#[derive(Debug, Clone, Serialize, Deserialize)]
2563pub struct FixedAssetMasterConfig {
2564    /// Number of fixed assets to generate
2565    #[serde(default = "default_asset_count")]
2566    pub count: usize,
2567    /// Asset class distribution
2568    #[serde(default)]
2569    pub class_distribution: AssetClassDistribution,
2570    /// Depreciation method distribution
2571    #[serde(default)]
2572    pub depreciation_distribution: DepreciationMethodDistribution,
2573    /// Percentage of assets that are fully depreciated
2574    #[serde(default = "default_fully_depreciated_percent")]
2575    pub fully_depreciated_percent: f64,
2576    /// Generate acquisition history
2577    #[serde(default = "default_true")]
2578    pub generate_acquisition_history: bool,
2579}
2580
2581fn default_asset_count() -> usize {
2582    800
2583}
2584
2585fn default_fully_depreciated_percent() -> f64 {
2586    0.15
2587}
2588
2589impl Default for FixedAssetMasterConfig {
2590    fn default() -> Self {
2591        Self {
2592            count: default_asset_count(),
2593            class_distribution: AssetClassDistribution::default(),
2594            depreciation_distribution: DepreciationMethodDistribution::default(),
2595            fully_depreciated_percent: default_fully_depreciated_percent(),
2596            generate_acquisition_history: true,
2597        }
2598    }
2599}
2600
2601/// Asset class distribution.
2602#[derive(Debug, Clone, Serialize, Deserialize)]
2603pub struct AssetClassDistribution {
2604    /// Buildings and structures
2605    pub buildings: f64,
2606    /// Machinery and equipment
2607    pub machinery: f64,
2608    /// Vehicles
2609    pub vehicles: f64,
2610    /// IT equipment
2611    pub it_equipment: f64,
2612    /// Furniture and fixtures
2613    pub furniture: f64,
2614    /// Land (non-depreciable)
2615    pub land: f64,
2616    /// Leasehold improvements
2617    pub leasehold: f64,
2618}
2619
2620impl Default for AssetClassDistribution {
2621    fn default() -> Self {
2622        Self {
2623            buildings: 0.15,
2624            machinery: 0.30,
2625            vehicles: 0.15,
2626            it_equipment: 0.20,
2627            furniture: 0.10,
2628            land: 0.05,
2629            leasehold: 0.05,
2630        }
2631    }
2632}
2633
2634/// Depreciation method distribution.
2635#[derive(Debug, Clone, Serialize, Deserialize)]
2636pub struct DepreciationMethodDistribution {
2637    /// Straight line
2638    pub straight_line: f64,
2639    /// Declining balance
2640    pub declining_balance: f64,
2641    /// Double declining balance
2642    pub double_declining: f64,
2643    /// Sum of years' digits
2644    pub sum_of_years: f64,
2645    /// Units of production
2646    pub units_of_production: f64,
2647}
2648
2649impl Default for DepreciationMethodDistribution {
2650    fn default() -> Self {
2651        Self {
2652            straight_line: 0.60,
2653            declining_balance: 0.20,
2654            double_declining: 0.10,
2655            sum_of_years: 0.05,
2656            units_of_production: 0.05,
2657        }
2658    }
2659}
2660
2661/// Employee master data configuration.
2662#[derive(Debug, Clone, Serialize, Deserialize)]
2663pub struct EmployeeMasterConfig {
2664    /// Number of employees to generate
2665    #[serde(default = "default_employee_count")]
2666    pub count: usize,
2667    /// Generate organizational hierarchy
2668    #[serde(default = "default_true")]
2669    pub generate_hierarchy: bool,
2670    /// Maximum hierarchy depth
2671    #[serde(default = "default_hierarchy_depth")]
2672    pub max_hierarchy_depth: u8,
2673    /// Average span of control (direct reports per manager)
2674    #[serde(default = "default_span_of_control")]
2675    pub average_span_of_control: f64,
2676    /// Approval limit distribution by job level
2677    #[serde(default)]
2678    pub approval_limits: ApprovalLimitDistribution,
2679    /// Department distribution
2680    #[serde(default)]
2681    pub department_distribution: EmployeeDepartmentDistribution,
2682}
2683
2684fn default_employee_count() -> usize {
2685    1500
2686}
2687
2688fn default_hierarchy_depth() -> u8 {
2689    6
2690}
2691
2692fn default_span_of_control() -> f64 {
2693    5.0
2694}
2695
2696impl Default for EmployeeMasterConfig {
2697    fn default() -> Self {
2698        Self {
2699            count: default_employee_count(),
2700            generate_hierarchy: true,
2701            max_hierarchy_depth: default_hierarchy_depth(),
2702            average_span_of_control: default_span_of_control(),
2703            approval_limits: ApprovalLimitDistribution::default(),
2704            department_distribution: EmployeeDepartmentDistribution::default(),
2705        }
2706    }
2707}
2708
2709/// Approval limit distribution by job level.
2710#[derive(Debug, Clone, Serialize, Deserialize)]
2711pub struct ApprovalLimitDistribution {
2712    /// Staff level approval limit
2713    #[serde(default = "default_staff_limit")]
2714    pub staff: f64,
2715    /// Senior staff approval limit
2716    #[serde(default = "default_senior_limit")]
2717    pub senior: f64,
2718    /// Manager approval limit
2719    #[serde(default = "default_manager_limit")]
2720    pub manager: f64,
2721    /// Director approval limit
2722    #[serde(default = "default_director_limit")]
2723    pub director: f64,
2724    /// VP approval limit
2725    #[serde(default = "default_vp_limit")]
2726    pub vp: f64,
2727    /// Executive approval limit
2728    #[serde(default = "default_executive_limit")]
2729    pub executive: f64,
2730}
2731
2732fn default_staff_limit() -> f64 {
2733    1000.0
2734}
2735fn default_senior_limit() -> f64 {
2736    5000.0
2737}
2738fn default_manager_limit() -> f64 {
2739    25000.0
2740}
2741fn default_director_limit() -> f64 {
2742    100000.0
2743}
2744fn default_vp_limit() -> f64 {
2745    500000.0
2746}
2747fn default_executive_limit() -> f64 {
2748    f64::INFINITY
2749}
2750
2751impl Default for ApprovalLimitDistribution {
2752    fn default() -> Self {
2753        Self {
2754            staff: default_staff_limit(),
2755            senior: default_senior_limit(),
2756            manager: default_manager_limit(),
2757            director: default_director_limit(),
2758            vp: default_vp_limit(),
2759            executive: default_executive_limit(),
2760        }
2761    }
2762}
2763
2764/// Employee distribution across departments.
2765#[derive(Debug, Clone, Serialize, Deserialize)]
2766pub struct EmployeeDepartmentDistribution {
2767    /// Finance and Accounting
2768    pub finance: f64,
2769    /// Procurement
2770    pub procurement: f64,
2771    /// Sales
2772    pub sales: f64,
2773    /// Warehouse and Logistics
2774    pub warehouse: f64,
2775    /// IT
2776    pub it: f64,
2777    /// Human Resources
2778    pub hr: f64,
2779    /// Operations
2780    pub operations: f64,
2781    /// Executive
2782    pub executive: f64,
2783}
2784
2785impl Default for EmployeeDepartmentDistribution {
2786    fn default() -> Self {
2787        Self {
2788            finance: 0.12,
2789            procurement: 0.10,
2790            sales: 0.25,
2791            warehouse: 0.15,
2792            it: 0.10,
2793            hr: 0.05,
2794            operations: 0.20,
2795            executive: 0.03,
2796        }
2797    }
2798}
2799
2800/// Cost center master data configuration.
2801#[derive(Debug, Clone, Serialize, Deserialize)]
2802pub struct CostCenterMasterConfig {
2803    /// Number of cost centers to generate
2804    #[serde(default = "default_cost_center_count")]
2805    pub count: usize,
2806    /// Generate cost center hierarchy
2807    #[serde(default = "default_true")]
2808    pub generate_hierarchy: bool,
2809    /// Maximum hierarchy depth
2810    #[serde(default = "default_cc_hierarchy_depth")]
2811    pub max_hierarchy_depth: u8,
2812}
2813
2814fn default_cost_center_count() -> usize {
2815    50
2816}
2817
2818fn default_cc_hierarchy_depth() -> u8 {
2819    3
2820}
2821
2822impl Default for CostCenterMasterConfig {
2823    fn default() -> Self {
2824        Self {
2825            count: default_cost_center_count(),
2826            generate_hierarchy: true,
2827            max_hierarchy_depth: default_cc_hierarchy_depth(),
2828        }
2829    }
2830}
2831
2832// ============================================================================
2833// Document Flow Configuration
2834// ============================================================================
2835
2836/// Document flow generation configuration.
2837#[derive(Debug, Clone, Serialize, Deserialize)]
2838pub struct DocumentFlowConfig {
2839    /// P2P (Procure-to-Pay) flow configuration
2840    #[serde(default)]
2841    pub p2p: P2PFlowConfig,
2842    /// O2C (Order-to-Cash) flow configuration
2843    #[serde(default)]
2844    pub o2c: O2CFlowConfig,
2845    /// Generate document reference chains
2846    #[serde(default = "default_true")]
2847    pub generate_document_references: bool,
2848    /// Export document flow graph
2849    #[serde(default)]
2850    pub export_flow_graph: bool,
2851}
2852
2853impl Default for DocumentFlowConfig {
2854    fn default() -> Self {
2855        Self {
2856            p2p: P2PFlowConfig::default(),
2857            o2c: O2CFlowConfig::default(),
2858            generate_document_references: true,
2859            export_flow_graph: false,
2860        }
2861    }
2862}
2863
2864/// P2P (Procure-to-Pay) flow configuration.
2865#[derive(Debug, Clone, Serialize, Deserialize)]
2866pub struct P2PFlowConfig {
2867    /// Enable P2P document flow generation
2868    #[serde(default = "default_true")]
2869    pub enabled: bool,
2870    /// Three-way match success rate (PO-GR-Invoice)
2871    #[serde(default = "default_three_way_match_rate")]
2872    pub three_way_match_rate: f64,
2873    /// Rate of partial deliveries
2874    #[serde(default = "default_partial_delivery_rate")]
2875    pub partial_delivery_rate: f64,
2876    /// Rate of price variances between PO and Invoice
2877    #[serde(default = "default_price_variance_rate")]
2878    pub price_variance_rate: f64,
2879    /// Maximum price variance percentage
2880    #[serde(default = "default_max_price_variance")]
2881    pub max_price_variance_percent: f64,
2882    /// Rate of quantity variances between PO/GR and Invoice
2883    #[serde(default = "default_quantity_variance_rate")]
2884    pub quantity_variance_rate: f64,
2885    /// Average days from PO to goods receipt
2886    #[serde(default = "default_po_to_gr_days")]
2887    pub average_po_to_gr_days: u32,
2888    /// Average days from GR to invoice
2889    #[serde(default = "default_gr_to_invoice_days")]
2890    pub average_gr_to_invoice_days: u32,
2891    /// Average days from invoice to payment
2892    #[serde(default = "default_invoice_to_payment_days")]
2893    pub average_invoice_to_payment_days: u32,
2894    /// PO line count distribution
2895    #[serde(default)]
2896    pub line_count_distribution: DocumentLineCountDistribution,
2897    /// Payment behavior configuration
2898    #[serde(default)]
2899    pub payment_behavior: P2PPaymentBehaviorConfig,
2900    /// Rate of over-deliveries (quantity received exceeds PO quantity)
2901    #[serde(default)]
2902    pub over_delivery_rate: Option<f64>,
2903    /// Rate of early payment discounts being taken
2904    #[serde(default)]
2905    pub early_payment_discount_rate: Option<f64>,
2906}
2907
2908fn default_three_way_match_rate() -> f64 {
2909    0.95
2910}
2911
2912fn default_partial_delivery_rate() -> f64 {
2913    0.15
2914}
2915
2916fn default_price_variance_rate() -> f64 {
2917    0.08
2918}
2919
2920fn default_max_price_variance() -> f64 {
2921    0.05
2922}
2923
2924fn default_quantity_variance_rate() -> f64 {
2925    0.05
2926}
2927
2928fn default_po_to_gr_days() -> u32 {
2929    14
2930}
2931
2932fn default_gr_to_invoice_days() -> u32 {
2933    5
2934}
2935
2936fn default_invoice_to_payment_days() -> u32 {
2937    30
2938}
2939
2940impl Default for P2PFlowConfig {
2941    fn default() -> Self {
2942        Self {
2943            enabled: true,
2944            three_way_match_rate: default_three_way_match_rate(),
2945            partial_delivery_rate: default_partial_delivery_rate(),
2946            price_variance_rate: default_price_variance_rate(),
2947            max_price_variance_percent: default_max_price_variance(),
2948            quantity_variance_rate: default_quantity_variance_rate(),
2949            average_po_to_gr_days: default_po_to_gr_days(),
2950            average_gr_to_invoice_days: default_gr_to_invoice_days(),
2951            average_invoice_to_payment_days: default_invoice_to_payment_days(),
2952            line_count_distribution: DocumentLineCountDistribution::default(),
2953            payment_behavior: P2PPaymentBehaviorConfig::default(),
2954            over_delivery_rate: None,
2955            early_payment_discount_rate: None,
2956        }
2957    }
2958}
2959
2960// ============================================================================
2961// P2P Payment Behavior Configuration
2962// ============================================================================
2963
2964/// P2P payment behavior configuration.
2965#[derive(Debug, Clone, Serialize, Deserialize)]
2966pub struct P2PPaymentBehaviorConfig {
2967    /// Rate of late payments (beyond due date)
2968    #[serde(default = "default_p2p_late_payment_rate")]
2969    pub late_payment_rate: f64,
2970    /// Distribution of late payment days
2971    #[serde(default)]
2972    pub late_payment_days_distribution: LatePaymentDaysDistribution,
2973    /// Rate of partial payments
2974    #[serde(default = "default_p2p_partial_payment_rate")]
2975    pub partial_payment_rate: f64,
2976    /// Rate of payment corrections (NSF, chargebacks, reversals)
2977    #[serde(default = "default_p2p_payment_correction_rate")]
2978    pub payment_correction_rate: f64,
2979    /// Average days until partial payment remainder is paid
2980    #[serde(default = "default_p2p_avg_days_until_remainder")]
2981    pub avg_days_until_remainder: u32,
2982}
2983
2984fn default_p2p_late_payment_rate() -> f64 {
2985    0.15
2986}
2987
2988fn default_p2p_partial_payment_rate() -> f64 {
2989    0.05
2990}
2991
2992fn default_p2p_payment_correction_rate() -> f64 {
2993    0.02
2994}
2995
2996fn default_p2p_avg_days_until_remainder() -> u32 {
2997    30
2998}
2999
3000impl Default for P2PPaymentBehaviorConfig {
3001    fn default() -> Self {
3002        Self {
3003            late_payment_rate: default_p2p_late_payment_rate(),
3004            late_payment_days_distribution: LatePaymentDaysDistribution::default(),
3005            partial_payment_rate: default_p2p_partial_payment_rate(),
3006            payment_correction_rate: default_p2p_payment_correction_rate(),
3007            avg_days_until_remainder: default_p2p_avg_days_until_remainder(),
3008        }
3009    }
3010}
3011
3012/// Distribution of late payment days for P2P.
3013#[derive(Debug, Clone, Serialize, Deserialize)]
3014pub struct LatePaymentDaysDistribution {
3015    /// 1-7 days late (slightly late)
3016    #[serde(default = "default_slightly_late")]
3017    pub slightly_late_1_to_7: f64,
3018    /// 8-14 days late
3019    #[serde(default = "default_late_8_14")]
3020    pub late_8_to_14: f64,
3021    /// 15-30 days late (very late)
3022    #[serde(default = "default_very_late")]
3023    pub very_late_15_to_30: f64,
3024    /// 31-60 days late (severely late)
3025    #[serde(default = "default_severely_late")]
3026    pub severely_late_31_to_60: f64,
3027    /// Over 60 days late (extremely late)
3028    #[serde(default = "default_extremely_late")]
3029    pub extremely_late_over_60: f64,
3030}
3031
3032fn default_slightly_late() -> f64 {
3033    0.50
3034}
3035
3036fn default_late_8_14() -> f64 {
3037    0.25
3038}
3039
3040fn default_very_late() -> f64 {
3041    0.15
3042}
3043
3044fn default_severely_late() -> f64 {
3045    0.07
3046}
3047
3048fn default_extremely_late() -> f64 {
3049    0.03
3050}
3051
3052impl Default for LatePaymentDaysDistribution {
3053    fn default() -> Self {
3054        Self {
3055            slightly_late_1_to_7: default_slightly_late(),
3056            late_8_to_14: default_late_8_14(),
3057            very_late_15_to_30: default_very_late(),
3058            severely_late_31_to_60: default_severely_late(),
3059            extremely_late_over_60: default_extremely_late(),
3060        }
3061    }
3062}
3063
3064/// O2C (Order-to-Cash) flow configuration.
3065#[derive(Debug, Clone, Serialize, Deserialize)]
3066pub struct O2CFlowConfig {
3067    /// Enable O2C document flow generation
3068    #[serde(default = "default_true")]
3069    pub enabled: bool,
3070    /// Credit check failure rate
3071    #[serde(default = "default_credit_check_failure_rate")]
3072    pub credit_check_failure_rate: f64,
3073    /// Rate of partial shipments
3074    #[serde(default = "default_partial_shipment_rate")]
3075    pub partial_shipment_rate: f64,
3076    /// Rate of returns
3077    #[serde(default = "default_return_rate")]
3078    pub return_rate: f64,
3079    /// Bad debt write-off rate
3080    #[serde(default = "default_bad_debt_rate")]
3081    pub bad_debt_rate: f64,
3082    /// Average days from SO to delivery
3083    #[serde(default = "default_so_to_delivery_days")]
3084    pub average_so_to_delivery_days: u32,
3085    /// Average days from delivery to invoice
3086    #[serde(default = "default_delivery_to_invoice_days")]
3087    pub average_delivery_to_invoice_days: u32,
3088    /// Average days from invoice to receipt
3089    #[serde(default = "default_invoice_to_receipt_days")]
3090    pub average_invoice_to_receipt_days: u32,
3091    /// SO line count distribution
3092    #[serde(default)]
3093    pub line_count_distribution: DocumentLineCountDistribution,
3094    /// Cash discount configuration
3095    #[serde(default)]
3096    pub cash_discount: CashDiscountConfig,
3097    /// Payment behavior configuration
3098    #[serde(default)]
3099    pub payment_behavior: O2CPaymentBehaviorConfig,
3100    /// Rate of late payments
3101    #[serde(default)]
3102    pub late_payment_rate: Option<f64>,
3103}
3104
3105fn default_credit_check_failure_rate() -> f64 {
3106    0.02
3107}
3108
3109fn default_partial_shipment_rate() -> f64 {
3110    0.10
3111}
3112
3113fn default_return_rate() -> f64 {
3114    0.03
3115}
3116
3117fn default_bad_debt_rate() -> f64 {
3118    0.01
3119}
3120
3121fn default_so_to_delivery_days() -> u32 {
3122    7
3123}
3124
3125fn default_delivery_to_invoice_days() -> u32 {
3126    1
3127}
3128
3129fn default_invoice_to_receipt_days() -> u32 {
3130    45
3131}
3132
3133impl Default for O2CFlowConfig {
3134    fn default() -> Self {
3135        Self {
3136            enabled: true,
3137            credit_check_failure_rate: default_credit_check_failure_rate(),
3138            partial_shipment_rate: default_partial_shipment_rate(),
3139            return_rate: default_return_rate(),
3140            bad_debt_rate: default_bad_debt_rate(),
3141            average_so_to_delivery_days: default_so_to_delivery_days(),
3142            average_delivery_to_invoice_days: default_delivery_to_invoice_days(),
3143            average_invoice_to_receipt_days: default_invoice_to_receipt_days(),
3144            line_count_distribution: DocumentLineCountDistribution::default(),
3145            cash_discount: CashDiscountConfig::default(),
3146            payment_behavior: O2CPaymentBehaviorConfig::default(),
3147            late_payment_rate: None,
3148        }
3149    }
3150}
3151
3152// ============================================================================
3153// O2C Payment Behavior Configuration
3154// ============================================================================
3155
3156/// O2C payment behavior configuration.
3157#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3158pub struct O2CPaymentBehaviorConfig {
3159    /// Dunning (Mahnung) configuration
3160    #[serde(default)]
3161    pub dunning: DunningConfig,
3162    /// Partial payment configuration
3163    #[serde(default)]
3164    pub partial_payments: PartialPaymentConfig,
3165    /// Short payment configuration (unauthorized deductions)
3166    #[serde(default)]
3167    pub short_payments: ShortPaymentConfig,
3168    /// On-account payment configuration (unapplied payments)
3169    #[serde(default)]
3170    pub on_account_payments: OnAccountPaymentConfig,
3171    /// Payment correction configuration (NSF, chargebacks)
3172    #[serde(default)]
3173    pub payment_corrections: PaymentCorrectionConfig,
3174}
3175
3176/// Dunning (Mahnungen) configuration for AR collections.
3177#[derive(Debug, Clone, Serialize, Deserialize)]
3178pub struct DunningConfig {
3179    /// Enable dunning process
3180    #[serde(default)]
3181    pub enabled: bool,
3182    /// Days overdue for level 1 dunning (1st reminder)
3183    #[serde(default = "default_dunning_level_1_days")]
3184    pub level_1_days_overdue: u32,
3185    /// Days overdue for level 2 dunning (2nd reminder)
3186    #[serde(default = "default_dunning_level_2_days")]
3187    pub level_2_days_overdue: u32,
3188    /// Days overdue for level 3 dunning (final notice)
3189    #[serde(default = "default_dunning_level_3_days")]
3190    pub level_3_days_overdue: u32,
3191    /// Days overdue for collection handover
3192    #[serde(default = "default_collection_days")]
3193    pub collection_days_overdue: u32,
3194    /// Payment rates after each dunning level
3195    #[serde(default)]
3196    pub payment_after_dunning_rates: DunningPaymentRates,
3197    /// Rate of invoices blocked from dunning (disputes)
3198    #[serde(default = "default_dunning_block_rate")]
3199    pub dunning_block_rate: f64,
3200    /// Interest rate per year for overdue amounts
3201    #[serde(default = "default_dunning_interest_rate")]
3202    pub interest_rate_per_year: f64,
3203    /// Fixed dunning charge per letter
3204    #[serde(default = "default_dunning_charge")]
3205    pub dunning_charge: f64,
3206}
3207
3208fn default_dunning_level_1_days() -> u32 {
3209    14
3210}
3211
3212fn default_dunning_level_2_days() -> u32 {
3213    28
3214}
3215
3216fn default_dunning_level_3_days() -> u32 {
3217    42
3218}
3219
3220fn default_collection_days() -> u32 {
3221    60
3222}
3223
3224fn default_dunning_block_rate() -> f64 {
3225    0.05
3226}
3227
3228fn default_dunning_interest_rate() -> f64 {
3229    0.09
3230}
3231
3232fn default_dunning_charge() -> f64 {
3233    25.0
3234}
3235
3236impl Default for DunningConfig {
3237    fn default() -> Self {
3238        Self {
3239            enabled: false,
3240            level_1_days_overdue: default_dunning_level_1_days(),
3241            level_2_days_overdue: default_dunning_level_2_days(),
3242            level_3_days_overdue: default_dunning_level_3_days(),
3243            collection_days_overdue: default_collection_days(),
3244            payment_after_dunning_rates: DunningPaymentRates::default(),
3245            dunning_block_rate: default_dunning_block_rate(),
3246            interest_rate_per_year: default_dunning_interest_rate(),
3247            dunning_charge: default_dunning_charge(),
3248        }
3249    }
3250}
3251
3252/// Payment rates after each dunning level.
3253#[derive(Debug, Clone, Serialize, Deserialize)]
3254pub struct DunningPaymentRates {
3255    /// Rate that pays after level 1 reminder
3256    #[serde(default = "default_after_level_1")]
3257    pub after_level_1: f64,
3258    /// Rate that pays after level 2 reminder
3259    #[serde(default = "default_after_level_2")]
3260    pub after_level_2: f64,
3261    /// Rate that pays after level 3 final notice
3262    #[serde(default = "default_after_level_3")]
3263    pub after_level_3: f64,
3264    /// Rate that pays during collection
3265    #[serde(default = "default_during_collection")]
3266    pub during_collection: f64,
3267    /// Rate that never pays (becomes bad debt)
3268    #[serde(default = "default_never_pay")]
3269    pub never_pay: f64,
3270}
3271
3272fn default_after_level_1() -> f64 {
3273    0.40
3274}
3275
3276fn default_after_level_2() -> f64 {
3277    0.30
3278}
3279
3280fn default_after_level_3() -> f64 {
3281    0.15
3282}
3283
3284fn default_during_collection() -> f64 {
3285    0.05
3286}
3287
3288fn default_never_pay() -> f64 {
3289    0.10
3290}
3291
3292impl Default for DunningPaymentRates {
3293    fn default() -> Self {
3294        Self {
3295            after_level_1: default_after_level_1(),
3296            after_level_2: default_after_level_2(),
3297            after_level_3: default_after_level_3(),
3298            during_collection: default_during_collection(),
3299            never_pay: default_never_pay(),
3300        }
3301    }
3302}
3303
3304/// Partial payment configuration.
3305#[derive(Debug, Clone, Serialize, Deserialize)]
3306pub struct PartialPaymentConfig {
3307    /// Rate of invoices paid partially
3308    #[serde(default = "default_partial_payment_rate")]
3309    pub rate: f64,
3310    /// Distribution of partial payment percentages
3311    #[serde(default)]
3312    pub percentage_distribution: PartialPaymentPercentageDistribution,
3313    /// Average days until remainder is paid
3314    #[serde(default = "default_avg_days_until_remainder")]
3315    pub avg_days_until_remainder: u32,
3316}
3317
3318fn default_partial_payment_rate() -> f64 {
3319    0.08
3320}
3321
3322fn default_avg_days_until_remainder() -> u32 {
3323    30
3324}
3325
3326impl Default for PartialPaymentConfig {
3327    fn default() -> Self {
3328        Self {
3329            rate: default_partial_payment_rate(),
3330            percentage_distribution: PartialPaymentPercentageDistribution::default(),
3331            avg_days_until_remainder: default_avg_days_until_remainder(),
3332        }
3333    }
3334}
3335
3336/// Distribution of partial payment percentages.
3337#[derive(Debug, Clone, Serialize, Deserialize)]
3338pub struct PartialPaymentPercentageDistribution {
3339    /// Pay 25% of invoice
3340    #[serde(default = "default_partial_25")]
3341    pub pay_25_percent: f64,
3342    /// Pay 50% of invoice
3343    #[serde(default = "default_partial_50")]
3344    pub pay_50_percent: f64,
3345    /// Pay 75% of invoice
3346    #[serde(default = "default_partial_75")]
3347    pub pay_75_percent: f64,
3348    /// Pay random percentage
3349    #[serde(default = "default_partial_random")]
3350    pub pay_random_percent: f64,
3351}
3352
3353fn default_partial_25() -> f64 {
3354    0.15
3355}
3356
3357fn default_partial_50() -> f64 {
3358    0.50
3359}
3360
3361fn default_partial_75() -> f64 {
3362    0.25
3363}
3364
3365fn default_partial_random() -> f64 {
3366    0.10
3367}
3368
3369impl Default for PartialPaymentPercentageDistribution {
3370    fn default() -> Self {
3371        Self {
3372            pay_25_percent: default_partial_25(),
3373            pay_50_percent: default_partial_50(),
3374            pay_75_percent: default_partial_75(),
3375            pay_random_percent: default_partial_random(),
3376        }
3377    }
3378}
3379
3380/// Short payment configuration (unauthorized deductions).
3381#[derive(Debug, Clone, Serialize, Deserialize)]
3382pub struct ShortPaymentConfig {
3383    /// Rate of payments that are short
3384    #[serde(default = "default_short_payment_rate")]
3385    pub rate: f64,
3386    /// Distribution of short payment reasons
3387    #[serde(default)]
3388    pub reason_distribution: ShortPaymentReasonDistribution,
3389    /// Maximum percentage that can be short
3390    #[serde(default = "default_max_short_percent")]
3391    pub max_short_percent: f64,
3392}
3393
3394fn default_short_payment_rate() -> f64 {
3395    0.03
3396}
3397
3398fn default_max_short_percent() -> f64 {
3399    0.10
3400}
3401
3402impl Default for ShortPaymentConfig {
3403    fn default() -> Self {
3404        Self {
3405            rate: default_short_payment_rate(),
3406            reason_distribution: ShortPaymentReasonDistribution::default(),
3407            max_short_percent: default_max_short_percent(),
3408        }
3409    }
3410}
3411
3412/// Distribution of short payment reasons.
3413#[derive(Debug, Clone, Serialize, Deserialize)]
3414pub struct ShortPaymentReasonDistribution {
3415    /// Pricing dispute
3416    #[serde(default = "default_pricing_dispute")]
3417    pub pricing_dispute: f64,
3418    /// Quality issue
3419    #[serde(default = "default_quality_issue")]
3420    pub quality_issue: f64,
3421    /// Quantity discrepancy
3422    #[serde(default = "default_quantity_discrepancy")]
3423    pub quantity_discrepancy: f64,
3424    /// Unauthorized deduction
3425    #[serde(default = "default_unauthorized_deduction")]
3426    pub unauthorized_deduction: f64,
3427    /// Early payment discount taken incorrectly
3428    #[serde(default = "default_incorrect_discount")]
3429    pub incorrect_discount: f64,
3430}
3431
3432fn default_pricing_dispute() -> f64 {
3433    0.30
3434}
3435
3436fn default_quality_issue() -> f64 {
3437    0.20
3438}
3439
3440fn default_quantity_discrepancy() -> f64 {
3441    0.20
3442}
3443
3444fn default_unauthorized_deduction() -> f64 {
3445    0.15
3446}
3447
3448fn default_incorrect_discount() -> f64 {
3449    0.15
3450}
3451
3452impl Default for ShortPaymentReasonDistribution {
3453    fn default() -> Self {
3454        Self {
3455            pricing_dispute: default_pricing_dispute(),
3456            quality_issue: default_quality_issue(),
3457            quantity_discrepancy: default_quantity_discrepancy(),
3458            unauthorized_deduction: default_unauthorized_deduction(),
3459            incorrect_discount: default_incorrect_discount(),
3460        }
3461    }
3462}
3463
3464/// On-account payment configuration (unapplied payments).
3465#[derive(Debug, Clone, Serialize, Deserialize)]
3466pub struct OnAccountPaymentConfig {
3467    /// Rate of payments that are on-account (unapplied)
3468    #[serde(default = "default_on_account_rate")]
3469    pub rate: f64,
3470    /// Average days until on-account payments are applied
3471    #[serde(default = "default_avg_days_until_applied")]
3472    pub avg_days_until_applied: u32,
3473}
3474
3475fn default_on_account_rate() -> f64 {
3476    0.02
3477}
3478
3479fn default_avg_days_until_applied() -> u32 {
3480    14
3481}
3482
3483impl Default for OnAccountPaymentConfig {
3484    fn default() -> Self {
3485        Self {
3486            rate: default_on_account_rate(),
3487            avg_days_until_applied: default_avg_days_until_applied(),
3488        }
3489    }
3490}
3491
3492/// Payment correction configuration.
3493#[derive(Debug, Clone, Serialize, Deserialize)]
3494pub struct PaymentCorrectionConfig {
3495    /// Rate of payments requiring correction
3496    #[serde(default = "default_payment_correction_rate")]
3497    pub rate: f64,
3498    /// Distribution of correction types
3499    #[serde(default)]
3500    pub type_distribution: PaymentCorrectionTypeDistribution,
3501}
3502
3503fn default_payment_correction_rate() -> f64 {
3504    0.02
3505}
3506
3507impl Default for PaymentCorrectionConfig {
3508    fn default() -> Self {
3509        Self {
3510            rate: default_payment_correction_rate(),
3511            type_distribution: PaymentCorrectionTypeDistribution::default(),
3512        }
3513    }
3514}
3515
3516/// Distribution of payment correction types.
3517#[derive(Debug, Clone, Serialize, Deserialize)]
3518pub struct PaymentCorrectionTypeDistribution {
3519    /// NSF (Non-sufficient funds) / bounced check
3520    #[serde(default = "default_nsf_rate")]
3521    pub nsf: f64,
3522    /// Chargeback
3523    #[serde(default = "default_chargeback_rate")]
3524    pub chargeback: f64,
3525    /// Wrong amount applied
3526    #[serde(default = "default_wrong_amount_rate")]
3527    pub wrong_amount: f64,
3528    /// Wrong customer applied
3529    #[serde(default = "default_wrong_customer_rate")]
3530    pub wrong_customer: f64,
3531    /// Duplicate payment
3532    #[serde(default = "default_duplicate_payment_rate")]
3533    pub duplicate_payment: f64,
3534}
3535
3536fn default_nsf_rate() -> f64 {
3537    0.30
3538}
3539
3540fn default_chargeback_rate() -> f64 {
3541    0.20
3542}
3543
3544fn default_wrong_amount_rate() -> f64 {
3545    0.20
3546}
3547
3548fn default_wrong_customer_rate() -> f64 {
3549    0.15
3550}
3551
3552fn default_duplicate_payment_rate() -> f64 {
3553    0.15
3554}
3555
3556impl Default for PaymentCorrectionTypeDistribution {
3557    fn default() -> Self {
3558        Self {
3559            nsf: default_nsf_rate(),
3560            chargeback: default_chargeback_rate(),
3561            wrong_amount: default_wrong_amount_rate(),
3562            wrong_customer: default_wrong_customer_rate(),
3563            duplicate_payment: default_duplicate_payment_rate(),
3564        }
3565    }
3566}
3567
3568/// Document line count distribution.
3569#[derive(Debug, Clone, Serialize, Deserialize)]
3570pub struct DocumentLineCountDistribution {
3571    /// Minimum number of lines
3572    #[serde(default = "default_min_lines")]
3573    pub min_lines: u32,
3574    /// Maximum number of lines
3575    #[serde(default = "default_max_lines")]
3576    pub max_lines: u32,
3577    /// Most common line count (mode)
3578    #[serde(default = "default_mode_lines")]
3579    pub mode_lines: u32,
3580}
3581
3582fn default_min_lines() -> u32 {
3583    1
3584}
3585
3586fn default_max_lines() -> u32 {
3587    20
3588}
3589
3590fn default_mode_lines() -> u32 {
3591    3
3592}
3593
3594impl Default for DocumentLineCountDistribution {
3595    fn default() -> Self {
3596        Self {
3597            min_lines: default_min_lines(),
3598            max_lines: default_max_lines(),
3599            mode_lines: default_mode_lines(),
3600        }
3601    }
3602}
3603
3604/// Cash discount configuration.
3605#[derive(Debug, Clone, Serialize, Deserialize)]
3606pub struct CashDiscountConfig {
3607    /// Percentage of invoices eligible for cash discount
3608    #[serde(default = "default_discount_eligible_rate")]
3609    pub eligible_rate: f64,
3610    /// Rate at which customers take the discount
3611    #[serde(default = "default_discount_taken_rate")]
3612    pub taken_rate: f64,
3613    /// Standard discount percentage
3614    #[serde(default = "default_discount_percent")]
3615    pub discount_percent: f64,
3616    /// Days within which discount must be taken
3617    #[serde(default = "default_discount_days")]
3618    pub discount_days: u32,
3619}
3620
3621fn default_discount_eligible_rate() -> f64 {
3622    0.30
3623}
3624
3625fn default_discount_taken_rate() -> f64 {
3626    0.60
3627}
3628
3629fn default_discount_percent() -> f64 {
3630    0.02
3631}
3632
3633fn default_discount_days() -> u32 {
3634    10
3635}
3636
3637impl Default for CashDiscountConfig {
3638    fn default() -> Self {
3639        Self {
3640            eligible_rate: default_discount_eligible_rate(),
3641            taken_rate: default_discount_taken_rate(),
3642            discount_percent: default_discount_percent(),
3643            discount_days: default_discount_days(),
3644        }
3645    }
3646}
3647
3648// ============================================================================
3649// Intercompany Configuration
3650// ============================================================================
3651
3652/// Intercompany transaction configuration.
3653#[derive(Debug, Clone, Serialize, Deserialize)]
3654pub struct IntercompanyConfig {
3655    /// Enable intercompany transaction generation
3656    #[serde(default)]
3657    pub enabled: bool,
3658    /// Rate of transactions that are intercompany
3659    #[serde(default = "default_ic_transaction_rate")]
3660    pub ic_transaction_rate: f64,
3661    /// Transfer pricing method
3662    #[serde(default)]
3663    pub transfer_pricing_method: TransferPricingMethod,
3664    /// Transfer pricing markup percentage (for cost-plus)
3665    #[serde(default = "default_markup_percent")]
3666    pub markup_percent: f64,
3667    /// Generate matched IC pairs (offsetting entries)
3668    #[serde(default = "default_true")]
3669    pub generate_matched_pairs: bool,
3670    /// IC transaction type distribution
3671    #[serde(default)]
3672    pub transaction_type_distribution: ICTransactionTypeDistribution,
3673    /// Generate elimination entries for consolidation
3674    #[serde(default)]
3675    pub generate_eliminations: bool,
3676}
3677
3678fn default_ic_transaction_rate() -> f64 {
3679    0.15
3680}
3681
3682fn default_markup_percent() -> f64 {
3683    0.05
3684}
3685
3686impl Default for IntercompanyConfig {
3687    fn default() -> Self {
3688        Self {
3689            enabled: false,
3690            ic_transaction_rate: default_ic_transaction_rate(),
3691            transfer_pricing_method: TransferPricingMethod::default(),
3692            markup_percent: default_markup_percent(),
3693            generate_matched_pairs: true,
3694            transaction_type_distribution: ICTransactionTypeDistribution::default(),
3695            generate_eliminations: false,
3696        }
3697    }
3698}
3699
3700/// Transfer pricing method.
3701#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
3702#[serde(rename_all = "snake_case")]
3703pub enum TransferPricingMethod {
3704    /// Cost plus a markup
3705    #[default]
3706    CostPlus,
3707    /// Comparable uncontrolled price
3708    ComparableUncontrolled,
3709    /// Resale price method
3710    ResalePrice,
3711    /// Transactional net margin method
3712    TransactionalNetMargin,
3713    /// Profit split method
3714    ProfitSplit,
3715}
3716
3717/// IC transaction type distribution.
3718#[derive(Debug, Clone, Serialize, Deserialize)]
3719pub struct ICTransactionTypeDistribution {
3720    /// Goods sales between entities
3721    pub goods_sale: f64,
3722    /// Services provided
3723    pub service_provided: f64,
3724    /// Intercompany loans
3725    pub loan: f64,
3726    /// Dividends
3727    pub dividend: f64,
3728    /// Management fees
3729    pub management_fee: f64,
3730    /// Royalties
3731    pub royalty: f64,
3732    /// Cost sharing
3733    pub cost_sharing: f64,
3734}
3735
3736impl Default for ICTransactionTypeDistribution {
3737    fn default() -> Self {
3738        Self {
3739            goods_sale: 0.35,
3740            service_provided: 0.20,
3741            loan: 0.10,
3742            dividend: 0.05,
3743            management_fee: 0.15,
3744            royalty: 0.10,
3745            cost_sharing: 0.05,
3746        }
3747    }
3748}
3749
3750// ============================================================================
3751// Balance Configuration
3752// ============================================================================
3753
3754/// Balance and trial balance configuration.
3755#[derive(Debug, Clone, Serialize, Deserialize)]
3756pub struct BalanceConfig {
3757    /// Generate opening balances
3758    #[serde(default)]
3759    pub generate_opening_balances: bool,
3760    /// Generate trial balances
3761    #[serde(default = "default_true")]
3762    pub generate_trial_balances: bool,
3763    /// Target gross margin (for revenue/COGS coherence)
3764    #[serde(default = "default_gross_margin")]
3765    pub target_gross_margin: f64,
3766    /// Target DSO (Days Sales Outstanding)
3767    #[serde(default = "default_dso")]
3768    pub target_dso_days: u32,
3769    /// Target DPO (Days Payable Outstanding)
3770    #[serde(default = "default_dpo")]
3771    pub target_dpo_days: u32,
3772    /// Target current ratio
3773    #[serde(default = "default_current_ratio")]
3774    pub target_current_ratio: f64,
3775    /// Target debt-to-equity ratio
3776    #[serde(default = "default_debt_equity")]
3777    pub target_debt_to_equity: f64,
3778    /// Validate balance sheet equation (A = L + E)
3779    #[serde(default = "default_true")]
3780    pub validate_balance_equation: bool,
3781    /// Reconcile subledgers to GL control accounts
3782    #[serde(default = "default_true")]
3783    pub reconcile_subledgers: bool,
3784}
3785
3786fn default_gross_margin() -> f64 {
3787    0.35
3788}
3789
3790fn default_dso() -> u32 {
3791    45
3792}
3793
3794fn default_dpo() -> u32 {
3795    30
3796}
3797
3798fn default_current_ratio() -> f64 {
3799    1.5
3800}
3801
3802fn default_debt_equity() -> f64 {
3803    0.5
3804}
3805
3806impl Default for BalanceConfig {
3807    fn default() -> Self {
3808        Self {
3809            generate_opening_balances: false,
3810            generate_trial_balances: true,
3811            target_gross_margin: default_gross_margin(),
3812            target_dso_days: default_dso(),
3813            target_dpo_days: default_dpo(),
3814            target_current_ratio: default_current_ratio(),
3815            target_debt_to_equity: default_debt_equity(),
3816            validate_balance_equation: true,
3817            reconcile_subledgers: true,
3818        }
3819    }
3820}
3821
3822// ==========================================================================
3823// OCPM (Object-Centric Process Mining) Configuration
3824// ==========================================================================
3825
3826/// OCPM (Object-Centric Process Mining) configuration.
3827///
3828/// Controls generation of OCEL 2.0 compatible event logs with
3829/// many-to-many event-to-object relationships.
3830#[derive(Debug, Clone, Serialize, Deserialize)]
3831pub struct OcpmConfig {
3832    /// Enable OCPM event log generation
3833    #[serde(default)]
3834    pub enabled: bool,
3835
3836    /// Generate lifecycle events (Start/Complete pairs vs atomic events)
3837    #[serde(default = "default_true")]
3838    pub generate_lifecycle_events: bool,
3839
3840    /// Include object-to-object relationships in output
3841    #[serde(default = "default_true")]
3842    pub include_object_relationships: bool,
3843
3844    /// Compute and export process variants
3845    #[serde(default = "default_true")]
3846    pub compute_variants: bool,
3847
3848    /// Maximum variants to track (0 = unlimited)
3849    #[serde(default)]
3850    pub max_variants: usize,
3851
3852    /// P2P process configuration
3853    #[serde(default)]
3854    pub p2p_process: OcpmProcessConfig,
3855
3856    /// O2C process configuration
3857    #[serde(default)]
3858    pub o2c_process: OcpmProcessConfig,
3859
3860    /// Output format configuration
3861    #[serde(default)]
3862    pub output: OcpmOutputConfig,
3863}
3864
3865impl Default for OcpmConfig {
3866    fn default() -> Self {
3867        Self {
3868            enabled: false,
3869            generate_lifecycle_events: true,
3870            include_object_relationships: true,
3871            compute_variants: true,
3872            max_variants: 0,
3873            p2p_process: OcpmProcessConfig::default(),
3874            o2c_process: OcpmProcessConfig::default(),
3875            output: OcpmOutputConfig::default(),
3876        }
3877    }
3878}
3879
3880/// Process-specific OCPM configuration.
3881#[derive(Debug, Clone, Serialize, Deserialize)]
3882pub struct OcpmProcessConfig {
3883    /// Rework probability (0.0-1.0)
3884    #[serde(default = "default_rework_probability")]
3885    pub rework_probability: f64,
3886
3887    /// Skip step probability (0.0-1.0)
3888    #[serde(default = "default_skip_probability")]
3889    pub skip_step_probability: f64,
3890
3891    /// Out-of-order step probability (0.0-1.0)
3892    #[serde(default = "default_out_of_order_probability")]
3893    pub out_of_order_probability: f64,
3894}
3895
3896// Defaults deliberately produce variant counts and Inductive-Miner fitness
3897// in the range seen in real ERP data (dozens of variants, ~0.7–0.9 fitness).
3898// Lowering them all to 0 yields a single-variant happy-path log.
3899fn default_rework_probability() -> f64 {
3900    0.15
3901}
3902
3903fn default_skip_probability() -> f64 {
3904    0.10
3905}
3906
3907fn default_out_of_order_probability() -> f64 {
3908    0.08
3909}
3910
3911impl Default for OcpmProcessConfig {
3912    fn default() -> Self {
3913        Self {
3914            rework_probability: default_rework_probability(),
3915            skip_step_probability: default_skip_probability(),
3916            out_of_order_probability: default_out_of_order_probability(),
3917        }
3918    }
3919}
3920
3921/// OCPM output format configuration.
3922#[derive(Debug, Clone, Serialize, Deserialize)]
3923pub struct OcpmOutputConfig {
3924    /// Export OCEL 2.0 JSON format
3925    #[serde(default = "default_true")]
3926    pub ocel_json: bool,
3927
3928    /// Export OCEL 2.0 XML format
3929    #[serde(default)]
3930    pub ocel_xml: bool,
3931
3932    /// Export XES 2.0 XML format (IEEE standard for process mining tools)
3933    #[serde(default)]
3934    pub xes: bool,
3935
3936    /// Include lifecycle transitions in XES output (start/complete pairs)
3937    #[serde(default = "default_true")]
3938    pub xes_include_lifecycle: bool,
3939
3940    /// Include resource attributes in XES output
3941    #[serde(default = "default_true")]
3942    pub xes_include_resources: bool,
3943
3944    /// Export flattened CSV for each object type
3945    #[serde(default = "default_true")]
3946    pub flattened_csv: bool,
3947
3948    /// Export event-object relationship table
3949    #[serde(default = "default_true")]
3950    pub event_object_csv: bool,
3951
3952    /// Export object-object relationship table
3953    #[serde(default = "default_true")]
3954    pub object_relationship_csv: bool,
3955
3956    /// Export process variants summary
3957    #[serde(default = "default_true")]
3958    pub variants_csv: bool,
3959
3960    /// Export reference process models (canonical P2P, O2C, R2R)
3961    #[serde(default)]
3962    pub export_reference_models: bool,
3963}
3964
3965impl Default for OcpmOutputConfig {
3966    fn default() -> Self {
3967        Self {
3968            ocel_json: true,
3969            ocel_xml: false,
3970            xes: false,
3971            xes_include_lifecycle: true,
3972            xes_include_resources: true,
3973            flattened_csv: true,
3974            event_object_csv: true,
3975            object_relationship_csv: true,
3976            variants_csv: true,
3977            export_reference_models: false,
3978        }
3979    }
3980}
3981
3982/// Audit engagement and workpaper generation configuration.
3983#[derive(Debug, Clone, Serialize, Deserialize)]
3984pub struct AuditGenerationConfig {
3985    /// Enable audit engagement generation
3986    #[serde(default)]
3987    pub enabled: bool,
3988
3989    /// [Not yet wired] Generate workpaper data — reserved for future fine-grained control.
3990    /// Currently, workpapers are always generated when `enabled = true`.
3991    #[serde(default = "default_true")]
3992    pub generate_workpapers: bool,
3993
3994    /// [Not yet wired] Default engagement type distribution — reserved for future fine-grained control.
3995    /// Currently, engagement types are determined by the audit generator's internal defaults.
3996    #[serde(default)]
3997    pub engagement_types: AuditEngagementTypesConfig,
3998
3999    /// [Not yet wired] Workpaper configuration — reserved for future fine-grained control.
4000    /// Currently, workpaper settings are determined by the audit generator's internal defaults.
4001    #[serde(default)]
4002    pub workpapers: WorkpaperConfig,
4003
4004    /// [Not yet wired] Team configuration — reserved for future fine-grained control.
4005    /// Currently, team composition is determined by the audit generator's internal defaults.
4006    #[serde(default)]
4007    pub team: AuditTeamConfig,
4008
4009    /// [Not yet wired] Review workflow configuration — reserved for future fine-grained control.
4010    /// Currently, review workflow is determined by the audit generator's internal defaults.
4011    #[serde(default)]
4012    pub review: ReviewWorkflowConfig,
4013
4014    /// FSM-driven audit generation configuration.
4015    #[serde(default)]
4016    pub fsm: Option<AuditFsmConfig>,
4017}
4018
4019impl Default for AuditGenerationConfig {
4020    fn default() -> Self {
4021        Self {
4022            enabled: false,
4023            generate_workpapers: true,
4024            engagement_types: AuditEngagementTypesConfig::default(),
4025            workpapers: WorkpaperConfig::default(),
4026            team: AuditTeamConfig::default(),
4027            review: ReviewWorkflowConfig::default(),
4028            fsm: None,
4029        }
4030    }
4031}
4032
4033/// FSM-driven audit generation configuration.
4034#[derive(Debug, Clone, Serialize, Deserialize)]
4035pub struct AuditFsmConfig {
4036    /// Enable FSM-driven audit generation.
4037    #[serde(default)]
4038    pub enabled: bool,
4039
4040    /// Blueprint source: "builtin:fsa", "builtin:ia", or a file path.
4041    #[serde(default = "default_audit_fsm_blueprint")]
4042    pub blueprint: String,
4043
4044    /// Overlay source: "builtin:default", "builtin:thorough", "builtin:rushed", or a file path.
4045    #[serde(default = "default_audit_fsm_overlay")]
4046    pub overlay: String,
4047
4048    /// Depth level override.
4049    #[serde(default)]
4050    pub depth: Option<String>,
4051
4052    /// Discriminator filter.
4053    #[serde(default)]
4054    pub discriminators: std::collections::HashMap<String, Vec<String>>,
4055
4056    /// Event trail output config.
4057    #[serde(default)]
4058    pub event_trail: AuditEventTrailConfig,
4059
4060    /// RNG seed override.
4061    #[serde(default)]
4062    pub seed: Option<u64>,
4063}
4064
4065impl Default for AuditFsmConfig {
4066    fn default() -> Self {
4067        Self {
4068            enabled: false,
4069            blueprint: default_audit_fsm_blueprint(),
4070            overlay: default_audit_fsm_overlay(),
4071            depth: None,
4072            discriminators: std::collections::HashMap::new(),
4073            event_trail: AuditEventTrailConfig::default(),
4074            seed: None,
4075        }
4076    }
4077}
4078
4079fn default_audit_fsm_blueprint() -> String {
4080    "builtin:fsa".to_string()
4081}
4082
4083fn default_audit_fsm_overlay() -> String {
4084    "builtin:default".to_string()
4085}
4086
4087/// Event trail output configuration for FSM-driven audit generation.
4088#[derive(Debug, Clone, Serialize, Deserialize)]
4089pub struct AuditEventTrailConfig {
4090    /// Emit a flat event log.
4091    #[serde(default = "default_true")]
4092    pub flat_log: bool,
4093    /// Project events to OCEL 2.0 format.
4094    #[serde(default)]
4095    pub ocel_projection: bool,
4096}
4097
4098impl Default for AuditEventTrailConfig {
4099    fn default() -> Self {
4100        Self {
4101            flat_log: true,
4102            ocel_projection: false,
4103        }
4104    }
4105}
4106
4107/// Engagement type distribution configuration.
4108#[derive(Debug, Clone, Serialize, Deserialize)]
4109pub struct AuditEngagementTypesConfig {
4110    /// Financial statement audit probability
4111    #[serde(default = "default_financial_audit_prob")]
4112    pub financial_statement: f64,
4113    /// SOX/ICFR audit probability
4114    #[serde(default = "default_sox_audit_prob")]
4115    pub sox_icfr: f64,
4116    /// Integrated audit probability
4117    #[serde(default = "default_integrated_audit_prob")]
4118    pub integrated: f64,
4119    /// Review engagement probability
4120    #[serde(default = "default_review_prob")]
4121    pub review: f64,
4122    /// Agreed-upon procedures probability
4123    #[serde(default = "default_aup_prob")]
4124    pub agreed_upon_procedures: f64,
4125}
4126
4127fn default_financial_audit_prob() -> f64 {
4128    0.40
4129}
4130fn default_sox_audit_prob() -> f64 {
4131    0.20
4132}
4133fn default_integrated_audit_prob() -> f64 {
4134    0.25
4135}
4136fn default_review_prob() -> f64 {
4137    0.10
4138}
4139fn default_aup_prob() -> f64 {
4140    0.05
4141}
4142
4143impl Default for AuditEngagementTypesConfig {
4144    fn default() -> Self {
4145        Self {
4146            financial_statement: default_financial_audit_prob(),
4147            sox_icfr: default_sox_audit_prob(),
4148            integrated: default_integrated_audit_prob(),
4149            review: default_review_prob(),
4150            agreed_upon_procedures: default_aup_prob(),
4151        }
4152    }
4153}
4154
4155/// Workpaper generation configuration.
4156#[derive(Debug, Clone, Serialize, Deserialize)]
4157pub struct WorkpaperConfig {
4158    /// Average workpapers per engagement phase
4159    #[serde(default = "default_workpapers_per_phase")]
4160    pub average_per_phase: usize,
4161
4162    /// Include ISA compliance references
4163    #[serde(default = "default_true")]
4164    pub include_isa_references: bool,
4165
4166    /// Generate sample details
4167    #[serde(default = "default_true")]
4168    pub include_sample_details: bool,
4169
4170    /// Include cross-references between workpapers
4171    #[serde(default = "default_true")]
4172    pub include_cross_references: bool,
4173
4174    /// Sampling configuration
4175    #[serde(default)]
4176    pub sampling: SamplingConfig,
4177}
4178
4179fn default_workpapers_per_phase() -> usize {
4180    5
4181}
4182
4183impl Default for WorkpaperConfig {
4184    fn default() -> Self {
4185        Self {
4186            average_per_phase: default_workpapers_per_phase(),
4187            include_isa_references: true,
4188            include_sample_details: true,
4189            include_cross_references: true,
4190            sampling: SamplingConfig::default(),
4191        }
4192    }
4193}
4194
4195/// Sampling method configuration.
4196#[derive(Debug, Clone, Serialize, Deserialize)]
4197pub struct SamplingConfig {
4198    /// Statistical sampling rate (0.0-1.0)
4199    #[serde(default = "default_statistical_rate")]
4200    pub statistical_rate: f64,
4201    /// Judgmental sampling rate (0.0-1.0)
4202    #[serde(default = "default_judgmental_rate")]
4203    pub judgmental_rate: f64,
4204    /// Haphazard sampling rate (0.0-1.0)
4205    #[serde(default = "default_haphazard_rate")]
4206    pub haphazard_rate: f64,
4207    /// 100% examination rate (0.0-1.0)
4208    #[serde(default = "default_complete_examination_rate")]
4209    pub complete_examination_rate: f64,
4210}
4211
4212fn default_statistical_rate() -> f64 {
4213    0.40
4214}
4215fn default_judgmental_rate() -> f64 {
4216    0.30
4217}
4218fn default_haphazard_rate() -> f64 {
4219    0.20
4220}
4221fn default_complete_examination_rate() -> f64 {
4222    0.10
4223}
4224
4225impl Default for SamplingConfig {
4226    fn default() -> Self {
4227        Self {
4228            statistical_rate: default_statistical_rate(),
4229            judgmental_rate: default_judgmental_rate(),
4230            haphazard_rate: default_haphazard_rate(),
4231            complete_examination_rate: default_complete_examination_rate(),
4232        }
4233    }
4234}
4235
4236/// Audit team configuration.
4237#[derive(Debug, Clone, Serialize, Deserialize)]
4238pub struct AuditTeamConfig {
4239    /// Minimum team size
4240    #[serde(default = "default_min_team_size")]
4241    pub min_team_size: usize,
4242    /// Maximum team size
4243    #[serde(default = "default_max_team_size")]
4244    pub max_team_size: usize,
4245    /// Probability of having a specialist on the team
4246    #[serde(default = "default_specialist_probability")]
4247    pub specialist_probability: f64,
4248}
4249
4250fn default_min_team_size() -> usize {
4251    3
4252}
4253fn default_max_team_size() -> usize {
4254    8
4255}
4256fn default_specialist_probability() -> f64 {
4257    0.30
4258}
4259
4260impl Default for AuditTeamConfig {
4261    fn default() -> Self {
4262        Self {
4263            min_team_size: default_min_team_size(),
4264            max_team_size: default_max_team_size(),
4265            specialist_probability: default_specialist_probability(),
4266        }
4267    }
4268}
4269
4270/// Review workflow configuration.
4271#[derive(Debug, Clone, Serialize, Deserialize)]
4272pub struct ReviewWorkflowConfig {
4273    /// Average days between preparer completion and first review
4274    #[serde(default = "default_review_delay_days")]
4275    pub average_review_delay_days: u32,
4276    /// Probability of review notes requiring rework
4277    #[serde(default = "default_rework_probability_review")]
4278    pub rework_probability: f64,
4279    /// Require partner sign-off for all workpapers
4280    #[serde(default = "default_true")]
4281    pub require_partner_signoff: bool,
4282}
4283
4284fn default_review_delay_days() -> u32 {
4285    2
4286}
4287fn default_rework_probability_review() -> f64 {
4288    0.15
4289}
4290
4291impl Default for ReviewWorkflowConfig {
4292    fn default() -> Self {
4293        Self {
4294            average_review_delay_days: default_review_delay_days(),
4295            rework_probability: default_rework_probability_review(),
4296            require_partner_signoff: true,
4297        }
4298    }
4299}
4300
4301// =============================================================================
4302// Data Quality Configuration
4303// =============================================================================
4304
4305/// Data quality variation settings for realistic flakiness injection.
4306#[derive(Debug, Clone, Serialize, Deserialize)]
4307pub struct DataQualitySchemaConfig {
4308    /// Enable data quality variations
4309    #[serde(default)]
4310    pub enabled: bool,
4311    /// Preset to use (overrides individual settings if set)
4312    #[serde(default)]
4313    pub preset: DataQualityPreset,
4314    /// Missing value injection settings
4315    #[serde(default)]
4316    pub missing_values: MissingValuesSchemaConfig,
4317    /// Typo injection settings
4318    #[serde(default)]
4319    pub typos: TypoSchemaConfig,
4320    /// Format variation settings
4321    #[serde(default)]
4322    pub format_variations: FormatVariationSchemaConfig,
4323    /// Duplicate injection settings
4324    #[serde(default)]
4325    pub duplicates: DuplicateSchemaConfig,
4326    /// Encoding issue settings
4327    #[serde(default)]
4328    pub encoding_issues: EncodingIssueSchemaConfig,
4329    /// Generate quality issue labels for ML training
4330    #[serde(default)]
4331    pub generate_labels: bool,
4332    /// Per-sink quality profiles (different settings for CSV vs JSON etc.)
4333    #[serde(default)]
4334    pub sink_profiles: SinkQualityProfiles,
4335}
4336
4337impl Default for DataQualitySchemaConfig {
4338    fn default() -> Self {
4339        Self {
4340            enabled: false,
4341            preset: DataQualityPreset::None,
4342            missing_values: MissingValuesSchemaConfig::default(),
4343            typos: TypoSchemaConfig::default(),
4344            format_variations: FormatVariationSchemaConfig::default(),
4345            duplicates: DuplicateSchemaConfig::default(),
4346            encoding_issues: EncodingIssueSchemaConfig::default(),
4347            generate_labels: true,
4348            sink_profiles: SinkQualityProfiles::default(),
4349        }
4350    }
4351}
4352
4353impl DataQualitySchemaConfig {
4354    /// Creates a config for a specific preset profile.
4355    pub fn with_preset(preset: DataQualityPreset) -> Self {
4356        let mut config = Self {
4357            preset,
4358            ..Default::default()
4359        };
4360        config.apply_preset();
4361        config
4362    }
4363
4364    /// Applies the preset settings to the individual configuration fields.
4365    /// Call this after deserializing if preset is not Custom or None.
4366    pub fn apply_preset(&mut self) {
4367        if !self.preset.overrides_settings() {
4368            return;
4369        }
4370
4371        self.enabled = true;
4372
4373        // Missing values
4374        self.missing_values.enabled = self.preset.missing_rate() > 0.0;
4375        self.missing_values.rate = self.preset.missing_rate();
4376
4377        // Typos
4378        self.typos.enabled = self.preset.typo_rate() > 0.0;
4379        self.typos.char_error_rate = self.preset.typo_rate();
4380
4381        // Duplicates
4382        self.duplicates.enabled = self.preset.duplicate_rate() > 0.0;
4383        self.duplicates.exact_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
4384        self.duplicates.near_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
4385        self.duplicates.fuzzy_duplicate_ratio = self.preset.duplicate_rate() * 0.2;
4386
4387        // Format variations
4388        self.format_variations.enabled = self.preset.format_variations_enabled();
4389
4390        // Encoding issues
4391        self.encoding_issues.enabled = self.preset.encoding_issues_enabled();
4392        self.encoding_issues.rate = self.preset.encoding_issue_rate();
4393
4394        // OCR errors for typos in legacy preset
4395        if self.preset.ocr_errors_enabled() {
4396            self.typos.type_weights.ocr_errors = 0.3;
4397        }
4398    }
4399
4400    /// Returns the effective missing value rate (considering preset).
4401    pub fn effective_missing_rate(&self) -> f64 {
4402        if self.preset.overrides_settings() {
4403            self.preset.missing_rate()
4404        } else {
4405            self.missing_values.rate
4406        }
4407    }
4408
4409    /// Returns the effective typo rate (considering preset).
4410    pub fn effective_typo_rate(&self) -> f64 {
4411        if self.preset.overrides_settings() {
4412            self.preset.typo_rate()
4413        } else {
4414            self.typos.char_error_rate
4415        }
4416    }
4417
4418    /// Returns the effective duplicate rate (considering preset).
4419    pub fn effective_duplicate_rate(&self) -> f64 {
4420        if self.preset.overrides_settings() {
4421            self.preset.duplicate_rate()
4422        } else {
4423            self.duplicates.exact_duplicate_ratio
4424                + self.duplicates.near_duplicate_ratio
4425                + self.duplicates.fuzzy_duplicate_ratio
4426        }
4427    }
4428
4429    /// Creates a clean profile config.
4430    pub fn clean() -> Self {
4431        Self::with_preset(DataQualityPreset::Clean)
4432    }
4433
4434    /// Creates a noisy profile config.
4435    pub fn noisy() -> Self {
4436        Self::with_preset(DataQualityPreset::Noisy)
4437    }
4438
4439    /// Creates a legacy profile config.
4440    pub fn legacy() -> Self {
4441        Self::with_preset(DataQualityPreset::Legacy)
4442    }
4443}
4444
4445/// Preset configurations for common data quality scenarios.
4446#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4447#[serde(rename_all = "snake_case")]
4448pub enum DataQualityPreset {
4449    /// No data quality variations (clean data)
4450    #[default]
4451    None,
4452    /// Minimal variations (very clean data with rare issues)
4453    Minimal,
4454    /// Normal variations (realistic enterprise data quality)
4455    Normal,
4456    /// High variations (messy data for stress testing)
4457    High,
4458    /// Custom (use individual settings)
4459    Custom,
4460
4461    // ========================================
4462    // ML-Oriented Profiles (Phase 2.1)
4463    // ========================================
4464    /// Clean profile for ML training - minimal data quality issues
4465    /// Missing: 0.1%, Typos: 0.05%, Duplicates: 0%, Format: None
4466    Clean,
4467    /// Noisy profile simulating typical production data issues
4468    /// Missing: 5%, Typos: 2%, Duplicates: 1%, Format: Medium
4469    Noisy,
4470    /// Legacy profile simulating migrated/OCR'd historical data
4471    /// Missing: 10%, Typos: 5%, Duplicates: 3%, Format: Heavy + OCR
4472    Legacy,
4473}
4474
4475impl DataQualityPreset {
4476    /// Returns the missing value rate for this preset.
4477    pub fn missing_rate(&self) -> f64 {
4478        match self {
4479            DataQualityPreset::None => 0.0,
4480            DataQualityPreset::Minimal => 0.005,
4481            DataQualityPreset::Normal => 0.02,
4482            DataQualityPreset::High => 0.08,
4483            DataQualityPreset::Custom => 0.01, // Use config value
4484            DataQualityPreset::Clean => 0.001,
4485            DataQualityPreset::Noisy => 0.05,
4486            DataQualityPreset::Legacy => 0.10,
4487        }
4488    }
4489
4490    /// Returns the typo rate for this preset.
4491    pub fn typo_rate(&self) -> f64 {
4492        match self {
4493            DataQualityPreset::None => 0.0,
4494            DataQualityPreset::Minimal => 0.0005,
4495            DataQualityPreset::Normal => 0.002,
4496            DataQualityPreset::High => 0.01,
4497            DataQualityPreset::Custom => 0.001, // Use config value
4498            DataQualityPreset::Clean => 0.0005,
4499            DataQualityPreset::Noisy => 0.02,
4500            DataQualityPreset::Legacy => 0.05,
4501        }
4502    }
4503
4504    /// Returns the duplicate rate for this preset.
4505    pub fn duplicate_rate(&self) -> f64 {
4506        match self {
4507            DataQualityPreset::None => 0.0,
4508            DataQualityPreset::Minimal => 0.001,
4509            DataQualityPreset::Normal => 0.005,
4510            DataQualityPreset::High => 0.02,
4511            DataQualityPreset::Custom => 0.0, // Use config value
4512            DataQualityPreset::Clean => 0.0,
4513            DataQualityPreset::Noisy => 0.01,
4514            DataQualityPreset::Legacy => 0.03,
4515        }
4516    }
4517
4518    /// Returns whether format variations are enabled for this preset.
4519    pub fn format_variations_enabled(&self) -> bool {
4520        match self {
4521            DataQualityPreset::None | DataQualityPreset::Clean => false,
4522            DataQualityPreset::Minimal => true,
4523            DataQualityPreset::Normal => true,
4524            DataQualityPreset::High => true,
4525            DataQualityPreset::Custom => true,
4526            DataQualityPreset::Noisy => true,
4527            DataQualityPreset::Legacy => true,
4528        }
4529    }
4530
4531    /// Returns whether OCR-style errors are enabled for this preset.
4532    pub fn ocr_errors_enabled(&self) -> bool {
4533        matches!(self, DataQualityPreset::Legacy | DataQualityPreset::High)
4534    }
4535
4536    /// Returns whether encoding issues are enabled for this preset.
4537    pub fn encoding_issues_enabled(&self) -> bool {
4538        matches!(
4539            self,
4540            DataQualityPreset::Legacy | DataQualityPreset::High | DataQualityPreset::Noisy
4541        )
4542    }
4543
4544    /// Returns the encoding issue rate for this preset.
4545    pub fn encoding_issue_rate(&self) -> f64 {
4546        match self {
4547            DataQualityPreset::None | DataQualityPreset::Clean | DataQualityPreset::Minimal => 0.0,
4548            DataQualityPreset::Normal => 0.002,
4549            DataQualityPreset::High => 0.01,
4550            DataQualityPreset::Custom => 0.0,
4551            DataQualityPreset::Noisy => 0.005,
4552            DataQualityPreset::Legacy => 0.02,
4553        }
4554    }
4555
4556    /// Returns true if this preset overrides individual settings.
4557    pub fn overrides_settings(&self) -> bool {
4558        !matches!(self, DataQualityPreset::Custom | DataQualityPreset::None)
4559    }
4560
4561    /// Returns a human-readable description of this preset.
4562    pub fn description(&self) -> &'static str {
4563        match self {
4564            DataQualityPreset::None => "No data quality issues (pristine data)",
4565            DataQualityPreset::Minimal => "Very rare data quality issues",
4566            DataQualityPreset::Normal => "Realistic enterprise data quality",
4567            DataQualityPreset::High => "Messy data for stress testing",
4568            DataQualityPreset::Custom => "Custom settings from configuration",
4569            DataQualityPreset::Clean => "ML-ready clean data with minimal issues",
4570            DataQualityPreset::Noisy => "Typical production data with moderate issues",
4571            DataQualityPreset::Legacy => "Legacy/migrated data with heavy issues and OCR errors",
4572        }
4573    }
4574}
4575
4576/// Missing value injection configuration.
4577#[derive(Debug, Clone, Serialize, Deserialize)]
4578pub struct MissingValuesSchemaConfig {
4579    /// Enable missing value injection
4580    #[serde(default)]
4581    pub enabled: bool,
4582    /// Global missing rate (0.0 to 1.0)
4583    #[serde(default = "default_missing_rate")]
4584    pub rate: f64,
4585    /// Missing value strategy
4586    #[serde(default)]
4587    pub strategy: MissingValueStrategy,
4588    /// Field-specific rates (field name -> rate)
4589    #[serde(default)]
4590    pub field_rates: std::collections::HashMap<String, f64>,
4591    /// Fields that should never have missing values
4592    #[serde(default)]
4593    pub protected_fields: Vec<String>,
4594}
4595
4596fn default_missing_rate() -> f64 {
4597    0.01
4598}
4599
4600impl Default for MissingValuesSchemaConfig {
4601    fn default() -> Self {
4602        Self {
4603            enabled: false,
4604            rate: default_missing_rate(),
4605            strategy: MissingValueStrategy::Mcar,
4606            field_rates: std::collections::HashMap::new(),
4607            protected_fields: vec![
4608                "document_id".to_string(),
4609                "company_code".to_string(),
4610                "posting_date".to_string(),
4611            ],
4612        }
4613    }
4614}
4615
4616/// Missing value strategy types.
4617#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4618#[serde(rename_all = "snake_case")]
4619pub enum MissingValueStrategy {
4620    /// Missing Completely At Random - equal probability for all values
4621    #[default]
4622    Mcar,
4623    /// Missing At Random - depends on other observed values
4624    Mar,
4625    /// Missing Not At Random - depends on the value itself
4626    Mnar,
4627    /// Systematic - entire field groups missing together
4628    Systematic,
4629}
4630
4631/// Typo injection configuration.
4632#[derive(Debug, Clone, Serialize, Deserialize)]
4633pub struct TypoSchemaConfig {
4634    /// Enable typo injection
4635    #[serde(default)]
4636    pub enabled: bool,
4637    /// Character error rate (per character, not per field)
4638    #[serde(default = "default_typo_rate")]
4639    pub char_error_rate: f64,
4640    /// Typo type weights
4641    #[serde(default)]
4642    pub type_weights: TypoTypeWeights,
4643    /// Fields that should never have typos
4644    #[serde(default)]
4645    pub protected_fields: Vec<String>,
4646}
4647
4648fn default_typo_rate() -> f64 {
4649    0.001
4650}
4651
4652impl Default for TypoSchemaConfig {
4653    fn default() -> Self {
4654        Self {
4655            enabled: false,
4656            char_error_rate: default_typo_rate(),
4657            type_weights: TypoTypeWeights::default(),
4658            protected_fields: vec![
4659                "document_id".to_string(),
4660                "gl_account".to_string(),
4661                "company_code".to_string(),
4662            ],
4663        }
4664    }
4665}
4666
4667/// Weights for different typo types.
4668#[derive(Debug, Clone, Serialize, Deserialize)]
4669pub struct TypoTypeWeights {
4670    /// Keyboard-adjacent substitution (e.g., 'a' -> 's')
4671    #[serde(default = "default_substitution_weight")]
4672    pub substitution: f64,
4673    /// Adjacent character transposition (e.g., 'ab' -> 'ba')
4674    #[serde(default = "default_transposition_weight")]
4675    pub transposition: f64,
4676    /// Character insertion
4677    #[serde(default = "default_insertion_weight")]
4678    pub insertion: f64,
4679    /// Character deletion
4680    #[serde(default = "default_deletion_weight")]
4681    pub deletion: f64,
4682    /// OCR-style errors (e.g., '0' -> 'O')
4683    #[serde(default = "default_ocr_weight")]
4684    pub ocr_errors: f64,
4685    /// Homophone substitution (e.g., 'their' -> 'there')
4686    #[serde(default = "default_homophone_weight")]
4687    pub homophones: f64,
4688}
4689
4690fn default_substitution_weight() -> f64 {
4691    0.35
4692}
4693fn default_transposition_weight() -> f64 {
4694    0.25
4695}
4696fn default_insertion_weight() -> f64 {
4697    0.10
4698}
4699fn default_deletion_weight() -> f64 {
4700    0.15
4701}
4702fn default_ocr_weight() -> f64 {
4703    0.10
4704}
4705fn default_homophone_weight() -> f64 {
4706    0.05
4707}
4708
4709impl Default for TypoTypeWeights {
4710    fn default() -> Self {
4711        Self {
4712            substitution: default_substitution_weight(),
4713            transposition: default_transposition_weight(),
4714            insertion: default_insertion_weight(),
4715            deletion: default_deletion_weight(),
4716            ocr_errors: default_ocr_weight(),
4717            homophones: default_homophone_weight(),
4718        }
4719    }
4720}
4721
4722/// Format variation configuration.
4723#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4724pub struct FormatVariationSchemaConfig {
4725    /// Enable format variations
4726    #[serde(default)]
4727    pub enabled: bool,
4728    /// Date format variation settings
4729    #[serde(default)]
4730    pub dates: DateFormatVariationConfig,
4731    /// Amount format variation settings
4732    #[serde(default)]
4733    pub amounts: AmountFormatVariationConfig,
4734    /// Identifier format variation settings
4735    #[serde(default)]
4736    pub identifiers: IdentifierFormatVariationConfig,
4737}
4738
4739/// Date format variation configuration.
4740#[derive(Debug, Clone, Serialize, Deserialize)]
4741pub struct DateFormatVariationConfig {
4742    /// Enable date format variations
4743    #[serde(default)]
4744    pub enabled: bool,
4745    /// Overall variation rate
4746    #[serde(default = "default_date_variation_rate")]
4747    pub rate: f64,
4748    /// Include ISO format (2024-01-15)
4749    #[serde(default = "default_true")]
4750    pub iso_format: bool,
4751    /// Include US format (01/15/2024)
4752    #[serde(default)]
4753    pub us_format: bool,
4754    /// Include EU format (15.01.2024)
4755    #[serde(default)]
4756    pub eu_format: bool,
4757    /// Include long format (January 15, 2024)
4758    #[serde(default)]
4759    pub long_format: bool,
4760}
4761
4762fn default_date_variation_rate() -> f64 {
4763    0.05
4764}
4765
4766impl Default for DateFormatVariationConfig {
4767    fn default() -> Self {
4768        Self {
4769            enabled: false,
4770            rate: default_date_variation_rate(),
4771            iso_format: true,
4772            us_format: false,
4773            eu_format: false,
4774            long_format: false,
4775        }
4776    }
4777}
4778
4779/// Amount format variation configuration.
4780#[derive(Debug, Clone, Serialize, Deserialize)]
4781pub struct AmountFormatVariationConfig {
4782    /// Enable amount format variations
4783    #[serde(default)]
4784    pub enabled: bool,
4785    /// Overall variation rate
4786    #[serde(default = "default_amount_variation_rate")]
4787    pub rate: f64,
4788    /// Include US comma format (1,234.56)
4789    #[serde(default)]
4790    pub us_comma_format: bool,
4791    /// Include EU format (1.234,56)
4792    #[serde(default)]
4793    pub eu_format: bool,
4794    /// Include currency prefix ($1,234.56)
4795    #[serde(default)]
4796    pub currency_prefix: bool,
4797    /// Include accounting format with parentheses for negatives
4798    #[serde(default)]
4799    pub accounting_format: bool,
4800}
4801
4802fn default_amount_variation_rate() -> f64 {
4803    0.02
4804}
4805
4806impl Default for AmountFormatVariationConfig {
4807    fn default() -> Self {
4808        Self {
4809            enabled: false,
4810            rate: default_amount_variation_rate(),
4811            us_comma_format: false,
4812            eu_format: false,
4813            currency_prefix: false,
4814            accounting_format: false,
4815        }
4816    }
4817}
4818
4819/// Identifier format variation configuration.
4820#[derive(Debug, Clone, Serialize, Deserialize)]
4821pub struct IdentifierFormatVariationConfig {
4822    /// Enable identifier format variations
4823    #[serde(default)]
4824    pub enabled: bool,
4825    /// Overall variation rate
4826    #[serde(default = "default_identifier_variation_rate")]
4827    pub rate: f64,
4828    /// Case variations (uppercase, lowercase, mixed)
4829    #[serde(default)]
4830    pub case_variations: bool,
4831    /// Padding variations (leading zeros)
4832    #[serde(default)]
4833    pub padding_variations: bool,
4834    /// Separator variations (dash vs underscore)
4835    #[serde(default)]
4836    pub separator_variations: bool,
4837}
4838
4839fn default_identifier_variation_rate() -> f64 {
4840    0.02
4841}
4842
4843impl Default for IdentifierFormatVariationConfig {
4844    fn default() -> Self {
4845        Self {
4846            enabled: false,
4847            rate: default_identifier_variation_rate(),
4848            case_variations: false,
4849            padding_variations: false,
4850            separator_variations: false,
4851        }
4852    }
4853}
4854
4855/// Duplicate injection configuration.
4856#[derive(Debug, Clone, Serialize, Deserialize)]
4857pub struct DuplicateSchemaConfig {
4858    /// Enable duplicate injection
4859    #[serde(default)]
4860    pub enabled: bool,
4861    /// Overall duplicate rate
4862    #[serde(default = "default_duplicate_rate")]
4863    pub rate: f64,
4864    /// Exact duplicate proportion (out of duplicates)
4865    #[serde(default = "default_exact_duplicate_ratio")]
4866    pub exact_duplicate_ratio: f64,
4867    /// Near duplicate proportion (slight variations)
4868    #[serde(default = "default_near_duplicate_ratio")]
4869    pub near_duplicate_ratio: f64,
4870    /// Fuzzy duplicate proportion (typos in key fields)
4871    #[serde(default = "default_fuzzy_duplicate_ratio")]
4872    pub fuzzy_duplicate_ratio: f64,
4873    /// Maximum date offset for near/fuzzy duplicates (days)
4874    #[serde(default = "default_max_date_offset")]
4875    pub max_date_offset_days: u32,
4876    /// Maximum amount variance for near duplicates (fraction)
4877    #[serde(default = "default_max_amount_variance")]
4878    pub max_amount_variance: f64,
4879}
4880
4881fn default_duplicate_rate() -> f64 {
4882    0.005
4883}
4884fn default_exact_duplicate_ratio() -> f64 {
4885    0.4
4886}
4887fn default_near_duplicate_ratio() -> f64 {
4888    0.35
4889}
4890fn default_fuzzy_duplicate_ratio() -> f64 {
4891    0.25
4892}
4893fn default_max_date_offset() -> u32 {
4894    3
4895}
4896fn default_max_amount_variance() -> f64 {
4897    0.01
4898}
4899
4900impl Default for DuplicateSchemaConfig {
4901    fn default() -> Self {
4902        Self {
4903            enabled: false,
4904            rate: default_duplicate_rate(),
4905            exact_duplicate_ratio: default_exact_duplicate_ratio(),
4906            near_duplicate_ratio: default_near_duplicate_ratio(),
4907            fuzzy_duplicate_ratio: default_fuzzy_duplicate_ratio(),
4908            max_date_offset_days: default_max_date_offset(),
4909            max_amount_variance: default_max_amount_variance(),
4910        }
4911    }
4912}
4913
4914/// Encoding issue configuration.
4915#[derive(Debug, Clone, Serialize, Deserialize)]
4916pub struct EncodingIssueSchemaConfig {
4917    /// Enable encoding issue injection
4918    #[serde(default)]
4919    pub enabled: bool,
4920    /// Overall encoding issue rate
4921    #[serde(default = "default_encoding_rate")]
4922    pub rate: f64,
4923    /// Include mojibake (UTF-8/Latin-1 confusion)
4924    #[serde(default)]
4925    pub mojibake: bool,
4926    /// Include HTML entity corruption
4927    #[serde(default)]
4928    pub html_entities: bool,
4929    /// Include BOM issues
4930    #[serde(default)]
4931    pub bom_issues: bool,
4932}
4933
4934fn default_encoding_rate() -> f64 {
4935    0.001
4936}
4937
4938impl Default for EncodingIssueSchemaConfig {
4939    fn default() -> Self {
4940        Self {
4941            enabled: false,
4942            rate: default_encoding_rate(),
4943            mojibake: false,
4944            html_entities: false,
4945            bom_issues: false,
4946        }
4947    }
4948}
4949
4950/// Per-sink quality profiles for different output formats.
4951#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4952pub struct SinkQualityProfiles {
4953    /// CSV-specific quality settings
4954    #[serde(default)]
4955    pub csv: Option<SinkQualityOverride>,
4956    /// JSON-specific quality settings
4957    #[serde(default)]
4958    pub json: Option<SinkQualityOverride>,
4959    /// Parquet-specific quality settings
4960    #[serde(default)]
4961    pub parquet: Option<SinkQualityOverride>,
4962}
4963
4964/// Quality setting overrides for a specific sink type.
4965#[derive(Debug, Clone, Serialize, Deserialize)]
4966pub struct SinkQualityOverride {
4967    /// Override enabled state
4968    pub enabled: Option<bool>,
4969    /// Override missing value rate
4970    pub missing_rate: Option<f64>,
4971    /// Override typo rate
4972    pub typo_rate: Option<f64>,
4973    /// Override format variation rate
4974    pub format_variation_rate: Option<f64>,
4975    /// Override duplicate rate
4976    pub duplicate_rate: Option<f64>,
4977}
4978
4979// =============================================================================
4980// Accounting Standards Configuration
4981// =============================================================================
4982
4983/// Accounting standards framework configuration for generating standards-compliant data.
4984///
4985/// Supports US GAAP, IFRS, and French GAAP (PCG) frameworks with specific standards:
4986/// - ASC 606/IFRS 15/PCG: Revenue Recognition
4987/// - ASC 842/IFRS 16/PCG: Leases
4988/// - ASC 820/IFRS 13/PCG: Fair Value Measurement
4989/// - ASC 360/IAS 36/PCG: Impairment
4990#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4991pub struct AccountingStandardsConfig {
4992    /// Enable accounting standards generation
4993    #[serde(default)]
4994    pub enabled: bool,
4995
4996    /// Accounting framework to use.
4997    /// When `None`, the country pack's `accounting.framework` is used as fallback;
4998    /// if that is also absent the orchestrator defaults to US GAAP.
4999    #[serde(default, skip_serializing_if = "Option::is_none")]
5000    pub framework: Option<AccountingFrameworkConfig>,
5001
5002    /// Revenue recognition configuration (ASC 606/IFRS 15)
5003    #[serde(default)]
5004    pub revenue_recognition: RevenueRecognitionConfig,
5005
5006    /// Lease accounting configuration (ASC 842/IFRS 16)
5007    #[serde(default)]
5008    pub leases: LeaseAccountingConfig,
5009
5010    /// Fair value measurement configuration (ASC 820/IFRS 13)
5011    #[serde(default)]
5012    pub fair_value: FairValueConfig,
5013
5014    /// Impairment testing configuration (ASC 360/IAS 36)
5015    #[serde(default)]
5016    pub impairment: ImpairmentConfig,
5017
5018    /// Business combination configuration (IFRS 3 / ASC 805)
5019    #[serde(default)]
5020    pub business_combinations: BusinessCombinationsConfig,
5021
5022    /// Expected Credit Loss configuration (IFRS 9 / ASC 326)
5023    #[serde(default)]
5024    pub expected_credit_loss: EclConfig,
5025
5026    /// Generate framework differences for dual reporting
5027    #[serde(default)]
5028    pub generate_differences: bool,
5029}
5030
5031/// Accounting framework selection.
5032#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5033#[serde(rename_all = "snake_case")]
5034pub enum AccountingFrameworkConfig {
5035    /// US Generally Accepted Accounting Principles
5036    #[default]
5037    UsGaap,
5038    /// International Financial Reporting Standards
5039    Ifrs,
5040    /// Generate data for both frameworks with reconciliation
5041    DualReporting,
5042    /// French GAAP (Plan Comptable Général – PCG)
5043    FrenchGaap,
5044    /// German GAAP (Handelsgesetzbuch – HGB, §238-263)
5045    GermanGaap,
5046}
5047
5048/// Revenue recognition configuration (ASC 606/IFRS 15).
5049#[derive(Debug, Clone, Serialize, Deserialize)]
5050pub struct RevenueRecognitionConfig {
5051    /// Enable revenue recognition generation
5052    #[serde(default)]
5053    pub enabled: bool,
5054
5055    /// Generate customer contracts
5056    #[serde(default = "default_true")]
5057    pub generate_contracts: bool,
5058
5059    /// Average number of performance obligations per contract
5060    #[serde(default = "default_avg_obligations")]
5061    pub avg_obligations_per_contract: f64,
5062
5063    /// Rate of contracts with variable consideration
5064    #[serde(default = "default_variable_consideration_rate")]
5065    pub variable_consideration_rate: f64,
5066
5067    /// Rate of over-time revenue recognition (vs point-in-time)
5068    #[serde(default = "default_over_time_rate")]
5069    pub over_time_recognition_rate: f64,
5070
5071    /// Number of contracts to generate
5072    #[serde(default = "default_contract_count")]
5073    pub contract_count: usize,
5074}
5075
5076fn default_avg_obligations() -> f64 {
5077    2.0
5078}
5079
5080fn default_variable_consideration_rate() -> f64 {
5081    0.15
5082}
5083
5084fn default_over_time_rate() -> f64 {
5085    0.30
5086}
5087
5088fn default_contract_count() -> usize {
5089    100
5090}
5091
5092impl Default for RevenueRecognitionConfig {
5093    fn default() -> Self {
5094        Self {
5095            enabled: false,
5096            generate_contracts: true,
5097            avg_obligations_per_contract: default_avg_obligations(),
5098            variable_consideration_rate: default_variable_consideration_rate(),
5099            over_time_recognition_rate: default_over_time_rate(),
5100            contract_count: default_contract_count(),
5101        }
5102    }
5103}
5104
5105/// Lease accounting configuration (ASC 842/IFRS 16).
5106#[derive(Debug, Clone, Serialize, Deserialize)]
5107pub struct LeaseAccountingConfig {
5108    /// Enable lease accounting generation
5109    #[serde(default)]
5110    pub enabled: bool,
5111
5112    /// Number of leases to generate
5113    #[serde(default = "default_lease_count")]
5114    pub lease_count: usize,
5115
5116    /// Percentage of finance leases (vs operating)
5117    #[serde(default = "default_finance_lease_pct")]
5118    pub finance_lease_percent: f64,
5119
5120    /// Average lease term in months
5121    #[serde(default = "default_avg_lease_term")]
5122    pub avg_lease_term_months: u32,
5123
5124    /// Generate amortization schedules
5125    #[serde(default = "default_true")]
5126    pub generate_amortization: bool,
5127
5128    /// Real estate lease percentage
5129    #[serde(default = "default_real_estate_pct")]
5130    pub real_estate_percent: f64,
5131}
5132
5133fn default_lease_count() -> usize {
5134    50
5135}
5136
5137fn default_finance_lease_pct() -> f64 {
5138    0.30
5139}
5140
5141fn default_avg_lease_term() -> u32 {
5142    60
5143}
5144
5145fn default_real_estate_pct() -> f64 {
5146    0.40
5147}
5148
5149impl Default for LeaseAccountingConfig {
5150    fn default() -> Self {
5151        Self {
5152            enabled: false,
5153            lease_count: default_lease_count(),
5154            finance_lease_percent: default_finance_lease_pct(),
5155            avg_lease_term_months: default_avg_lease_term(),
5156            generate_amortization: true,
5157            real_estate_percent: default_real_estate_pct(),
5158        }
5159    }
5160}
5161
5162/// Fair value measurement configuration (ASC 820/IFRS 13).
5163#[derive(Debug, Clone, Serialize, Deserialize)]
5164pub struct FairValueConfig {
5165    /// Enable fair value measurement generation
5166    #[serde(default)]
5167    pub enabled: bool,
5168
5169    /// Number of fair value measurements to generate
5170    #[serde(default = "default_fv_count")]
5171    pub measurement_count: usize,
5172
5173    /// Level 1 (quoted prices) percentage
5174    #[serde(default = "default_level1_pct")]
5175    pub level1_percent: f64,
5176
5177    /// Level 2 (observable inputs) percentage
5178    #[serde(default = "default_level2_pct")]
5179    pub level2_percent: f64,
5180
5181    /// Level 3 (unobservable inputs) percentage
5182    #[serde(default = "default_level3_pct")]
5183    pub level3_percent: f64,
5184
5185    /// Include sensitivity analysis for Level 3
5186    #[serde(default)]
5187    pub include_sensitivity_analysis: bool,
5188}
5189
5190fn default_fv_count() -> usize {
5191    25
5192}
5193
5194fn default_level1_pct() -> f64 {
5195    0.40
5196}
5197
5198fn default_level2_pct() -> f64 {
5199    0.35
5200}
5201
5202fn default_level3_pct() -> f64 {
5203    0.25
5204}
5205
5206impl Default for FairValueConfig {
5207    fn default() -> Self {
5208        Self {
5209            enabled: false,
5210            measurement_count: default_fv_count(),
5211            level1_percent: default_level1_pct(),
5212            level2_percent: default_level2_pct(),
5213            level3_percent: default_level3_pct(),
5214            include_sensitivity_analysis: false,
5215        }
5216    }
5217}
5218
5219/// Impairment testing configuration (ASC 360/IAS 36).
5220#[derive(Debug, Clone, Serialize, Deserialize)]
5221pub struct ImpairmentConfig {
5222    /// Enable impairment testing generation
5223    #[serde(default)]
5224    pub enabled: bool,
5225
5226    /// Number of impairment tests to generate
5227    #[serde(default = "default_impairment_count")]
5228    pub test_count: usize,
5229
5230    /// Rate of tests resulting in impairment
5231    #[serde(default = "default_impairment_rate")]
5232    pub impairment_rate: f64,
5233
5234    /// Generate cash flow projections
5235    #[serde(default = "default_true")]
5236    pub generate_projections: bool,
5237
5238    /// Include goodwill impairment tests
5239    #[serde(default)]
5240    pub include_goodwill: bool,
5241}
5242
5243fn default_impairment_count() -> usize {
5244    15
5245}
5246
5247fn default_impairment_rate() -> f64 {
5248    0.10
5249}
5250
5251impl Default for ImpairmentConfig {
5252    fn default() -> Self {
5253        Self {
5254            enabled: false,
5255            test_count: default_impairment_count(),
5256            impairment_rate: default_impairment_rate(),
5257            generate_projections: true,
5258            include_goodwill: false,
5259        }
5260    }
5261}
5262
5263// =============================================================================
5264// Business Combinations Configuration (IFRS 3 / ASC 805)
5265// =============================================================================
5266
5267/// Configuration for generating business combination (acquisition) data.
5268#[derive(Debug, Clone, Serialize, Deserialize)]
5269pub struct BusinessCombinationsConfig {
5270    /// Enable business combination generation
5271    #[serde(default)]
5272    pub enabled: bool,
5273
5274    /// Number of acquisitions to generate per company (1-5)
5275    #[serde(default = "default_bc_acquisition_count")]
5276    pub acquisition_count: usize,
5277}
5278
5279fn default_bc_acquisition_count() -> usize {
5280    2
5281}
5282
5283impl Default for BusinessCombinationsConfig {
5284    fn default() -> Self {
5285        Self {
5286            enabled: false,
5287            acquisition_count: default_bc_acquisition_count(),
5288        }
5289    }
5290}
5291
5292// =============================================================================
5293// ECL Configuration (IFRS 9 / ASC 326)
5294// =============================================================================
5295
5296/// Configuration for Expected Credit Loss generation.
5297#[derive(Debug, Clone, Serialize, Deserialize)]
5298pub struct EclConfig {
5299    /// Enable ECL generation.
5300    #[serde(default)]
5301    pub enabled: bool,
5302
5303    /// Weight for base economic scenario (0–1).
5304    #[serde(default = "default_ecl_base_weight")]
5305    pub base_scenario_weight: f64,
5306
5307    /// Multiplier for base scenario (typically 1.0).
5308    #[serde(default = "default_ecl_base_multiplier")]
5309    pub base_scenario_multiplier: f64,
5310
5311    /// Weight for optimistic economic scenario (0–1).
5312    #[serde(default = "default_ecl_optimistic_weight")]
5313    pub optimistic_scenario_weight: f64,
5314
5315    /// Multiplier for optimistic scenario (< 1.0 means lower losses).
5316    #[serde(default = "default_ecl_optimistic_multiplier")]
5317    pub optimistic_scenario_multiplier: f64,
5318
5319    /// Weight for pessimistic economic scenario (0–1).
5320    #[serde(default = "default_ecl_pessimistic_weight")]
5321    pub pessimistic_scenario_weight: f64,
5322
5323    /// Multiplier for pessimistic scenario (> 1.0 means higher losses).
5324    #[serde(default = "default_ecl_pessimistic_multiplier")]
5325    pub pessimistic_scenario_multiplier: f64,
5326}
5327
5328fn default_ecl_base_weight() -> f64 {
5329    0.50
5330}
5331fn default_ecl_base_multiplier() -> f64 {
5332    1.0
5333}
5334fn default_ecl_optimistic_weight() -> f64 {
5335    0.30
5336}
5337fn default_ecl_optimistic_multiplier() -> f64 {
5338    0.8
5339}
5340fn default_ecl_pessimistic_weight() -> f64 {
5341    0.20
5342}
5343fn default_ecl_pessimistic_multiplier() -> f64 {
5344    1.4
5345}
5346
5347impl Default for EclConfig {
5348    fn default() -> Self {
5349        Self {
5350            enabled: false,
5351            base_scenario_weight: default_ecl_base_weight(),
5352            base_scenario_multiplier: default_ecl_base_multiplier(),
5353            optimistic_scenario_weight: default_ecl_optimistic_weight(),
5354            optimistic_scenario_multiplier: default_ecl_optimistic_multiplier(),
5355            pessimistic_scenario_weight: default_ecl_pessimistic_weight(),
5356            pessimistic_scenario_multiplier: default_ecl_pessimistic_multiplier(),
5357        }
5358    }
5359}
5360
5361// =============================================================================
5362// Audit Standards Configuration
5363// =============================================================================
5364
5365/// Audit standards framework configuration for generating standards-compliant audit data.
5366///
5367/// Supports ISA (International Standards on Auditing) and PCAOB standards:
5368/// - ISA 200-720: Complete coverage of audit standards
5369/// - ISA 520: Analytical Procedures
5370/// - ISA 505: External Confirmations
5371/// - ISA 700/705/706/701: Audit Reports
5372/// - PCAOB AS 2201: ICFR Auditing
5373#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5374pub struct AuditStandardsConfig {
5375    /// Enable audit standards generation
5376    #[serde(default)]
5377    pub enabled: bool,
5378
5379    /// ISA compliance configuration
5380    #[serde(default)]
5381    pub isa_compliance: IsaComplianceConfig,
5382
5383    /// Analytical procedures configuration (ISA 520)
5384    #[serde(default)]
5385    pub analytical_procedures: AnalyticalProceduresConfig,
5386
5387    /// External confirmations configuration (ISA 505)
5388    #[serde(default)]
5389    pub confirmations: ConfirmationsConfig,
5390
5391    /// Audit opinion configuration (ISA 700/705/706/701)
5392    #[serde(default)]
5393    pub opinion: AuditOpinionConfig,
5394
5395    /// Generate complete audit trail with traceability
5396    #[serde(default)]
5397    pub generate_audit_trail: bool,
5398
5399    /// SOX 302/404 compliance configuration
5400    #[serde(default)]
5401    pub sox: SoxComplianceConfig,
5402
5403    /// PCAOB-specific configuration
5404    #[serde(default)]
5405    pub pcaob: PcaobConfig,
5406}
5407
5408/// ISA compliance level configuration.
5409#[derive(Debug, Clone, Serialize, Deserialize)]
5410pub struct IsaComplianceConfig {
5411    /// Enable ISA compliance tracking
5412    #[serde(default)]
5413    pub enabled: bool,
5414
5415    /// Compliance level: "basic", "standard", "comprehensive"
5416    #[serde(default = "default_compliance_level")]
5417    pub compliance_level: String,
5418
5419    /// Generate ISA requirement mappings
5420    #[serde(default = "default_true")]
5421    pub generate_isa_mappings: bool,
5422
5423    /// Generate ISA coverage summary
5424    #[serde(default = "default_true")]
5425    pub generate_coverage_summary: bool,
5426
5427    /// Include PCAOB standard mappings (for dual framework)
5428    #[serde(default)]
5429    pub include_pcaob: bool,
5430
5431    /// Framework to use: "isa", "pcaob", "dual"
5432    #[serde(default = "default_audit_framework")]
5433    pub framework: String,
5434}
5435
5436fn default_compliance_level() -> String {
5437    "standard".to_string()
5438}
5439
5440fn default_audit_framework() -> String {
5441    "isa".to_string()
5442}
5443
5444impl Default for IsaComplianceConfig {
5445    fn default() -> Self {
5446        Self {
5447            enabled: false,
5448            compliance_level: default_compliance_level(),
5449            generate_isa_mappings: true,
5450            generate_coverage_summary: true,
5451            include_pcaob: false,
5452            framework: default_audit_framework(),
5453        }
5454    }
5455}
5456
5457/// Analytical procedures configuration (ISA 520).
5458#[derive(Debug, Clone, Serialize, Deserialize)]
5459pub struct AnalyticalProceduresConfig {
5460    /// Enable analytical procedures generation
5461    #[serde(default)]
5462    pub enabled: bool,
5463
5464    /// Number of procedures per account/area
5465    #[serde(default = "default_procedures_per_account")]
5466    pub procedures_per_account: usize,
5467
5468    /// Probability of variance exceeding threshold
5469    #[serde(default = "default_variance_probability")]
5470    pub variance_probability: f64,
5471
5472    /// Include variance investigations
5473    #[serde(default = "default_true")]
5474    pub generate_investigations: bool,
5475
5476    /// Include financial ratio analysis
5477    #[serde(default = "default_true")]
5478    pub include_ratio_analysis: bool,
5479}
5480
5481fn default_procedures_per_account() -> usize {
5482    3
5483}
5484
5485fn default_variance_probability() -> f64 {
5486    0.20
5487}
5488
5489impl Default for AnalyticalProceduresConfig {
5490    fn default() -> Self {
5491        Self {
5492            enabled: false,
5493            procedures_per_account: default_procedures_per_account(),
5494            variance_probability: default_variance_probability(),
5495            generate_investigations: true,
5496            include_ratio_analysis: true,
5497        }
5498    }
5499}
5500
5501/// External confirmations configuration (ISA 505).
5502#[derive(Debug, Clone, Serialize, Deserialize)]
5503pub struct ConfirmationsConfig {
5504    /// Enable confirmation generation
5505    #[serde(default)]
5506    pub enabled: bool,
5507
5508    /// Number of confirmations to generate
5509    #[serde(default = "default_confirmation_count")]
5510    pub confirmation_count: usize,
5511
5512    /// Positive response rate
5513    #[serde(default = "default_positive_response_rate")]
5514    pub positive_response_rate: f64,
5515
5516    /// Exception rate (responses with differences)
5517    #[serde(default = "default_exception_rate_confirm")]
5518    pub exception_rate: f64,
5519
5520    /// Non-response rate
5521    #[serde(default = "default_non_response_rate")]
5522    pub non_response_rate: f64,
5523
5524    /// Generate alternative procedures for non-responses
5525    #[serde(default = "default_true")]
5526    pub generate_alternative_procedures: bool,
5527}
5528
5529fn default_confirmation_count() -> usize {
5530    50
5531}
5532
5533fn default_positive_response_rate() -> f64 {
5534    0.85
5535}
5536
5537fn default_exception_rate_confirm() -> f64 {
5538    0.10
5539}
5540
5541fn default_non_response_rate() -> f64 {
5542    0.05
5543}
5544
5545impl Default for ConfirmationsConfig {
5546    fn default() -> Self {
5547        Self {
5548            enabled: false,
5549            confirmation_count: default_confirmation_count(),
5550            positive_response_rate: default_positive_response_rate(),
5551            exception_rate: default_exception_rate_confirm(),
5552            non_response_rate: default_non_response_rate(),
5553            generate_alternative_procedures: true,
5554        }
5555    }
5556}
5557
5558/// Audit opinion configuration (ISA 700/705/706/701).
5559#[derive(Debug, Clone, Serialize, Deserialize)]
5560pub struct AuditOpinionConfig {
5561    /// Enable audit opinion generation
5562    #[serde(default)]
5563    pub enabled: bool,
5564
5565    /// Generate Key Audit Matters (KAM) / Critical Audit Matters (CAM)
5566    #[serde(default = "default_true")]
5567    pub generate_kam: bool,
5568
5569    /// Average number of KAMs/CAMs per opinion
5570    #[serde(default = "default_kam_count")]
5571    pub average_kam_count: usize,
5572
5573    /// Rate of modified opinions
5574    #[serde(default = "default_modified_opinion_rate")]
5575    pub modified_opinion_rate: f64,
5576
5577    /// Include emphasis of matter paragraphs
5578    #[serde(default)]
5579    pub include_emphasis_of_matter: bool,
5580
5581    /// Include going concern conclusions
5582    #[serde(default = "default_true")]
5583    pub include_going_concern: bool,
5584}
5585
5586fn default_kam_count() -> usize {
5587    3
5588}
5589
5590fn default_modified_opinion_rate() -> f64 {
5591    0.05
5592}
5593
5594impl Default for AuditOpinionConfig {
5595    fn default() -> Self {
5596        Self {
5597            enabled: false,
5598            generate_kam: true,
5599            average_kam_count: default_kam_count(),
5600            modified_opinion_rate: default_modified_opinion_rate(),
5601            include_emphasis_of_matter: false,
5602            include_going_concern: true,
5603        }
5604    }
5605}
5606
5607/// SOX compliance configuration (Sections 302/404).
5608#[derive(Debug, Clone, Serialize, Deserialize)]
5609pub struct SoxComplianceConfig {
5610    /// Enable SOX compliance generation
5611    #[serde(default)]
5612    pub enabled: bool,
5613
5614    /// Generate Section 302 CEO/CFO certifications
5615    #[serde(default = "default_true")]
5616    pub generate_302_certifications: bool,
5617
5618    /// Generate Section 404 ICFR assessments
5619    #[serde(default = "default_true")]
5620    pub generate_404_assessments: bool,
5621
5622    /// Materiality threshold for SOX testing
5623    #[serde(default = "default_sox_materiality_threshold")]
5624    pub materiality_threshold: f64,
5625
5626    /// Rate of material weaknesses
5627    #[serde(default = "default_material_weakness_rate")]
5628    pub material_weakness_rate: f64,
5629
5630    /// Rate of significant deficiencies
5631    #[serde(default = "default_significant_deficiency_rate")]
5632    pub significant_deficiency_rate: f64,
5633}
5634
5635fn default_material_weakness_rate() -> f64 {
5636    0.02
5637}
5638
5639fn default_significant_deficiency_rate() -> f64 {
5640    0.08
5641}
5642
5643impl Default for SoxComplianceConfig {
5644    fn default() -> Self {
5645        Self {
5646            enabled: false,
5647            generate_302_certifications: true,
5648            generate_404_assessments: true,
5649            materiality_threshold: default_sox_materiality_threshold(),
5650            material_weakness_rate: default_material_weakness_rate(),
5651            significant_deficiency_rate: default_significant_deficiency_rate(),
5652        }
5653    }
5654}
5655
5656/// PCAOB-specific configuration.
5657#[derive(Debug, Clone, Serialize, Deserialize)]
5658pub struct PcaobConfig {
5659    /// Enable PCAOB-specific elements
5660    #[serde(default)]
5661    pub enabled: bool,
5662
5663    /// Treat as PCAOB audit (vs ISA-only)
5664    #[serde(default)]
5665    pub is_pcaob_audit: bool,
5666
5667    /// Generate Critical Audit Matters (CAM)
5668    #[serde(default = "default_true")]
5669    pub generate_cam: bool,
5670
5671    /// Include ICFR opinion (for integrated audits)
5672    #[serde(default)]
5673    pub include_icfr_opinion: bool,
5674
5675    /// Generate PCAOB-ISA standard mappings
5676    #[serde(default)]
5677    pub generate_standard_mappings: bool,
5678}
5679
5680impl Default for PcaobConfig {
5681    fn default() -> Self {
5682        Self {
5683            enabled: false,
5684            is_pcaob_audit: false,
5685            generate_cam: true,
5686            include_icfr_opinion: false,
5687            generate_standard_mappings: false,
5688        }
5689    }
5690}
5691
5692// =============================================================================
5693// Advanced Distribution Configuration
5694// =============================================================================
5695
5696/// Advanced distribution configuration for realistic data generation.
5697///
5698/// This section enables sophisticated distribution models including:
5699/// - Mixture models (multi-modal distributions)
5700/// - Cross-field correlations
5701/// - Conditional distributions
5702/// - Regime changes and economic cycles
5703/// - Statistical validation
5704#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5705pub struct AdvancedDistributionConfig {
5706    /// Enable advanced distribution features.
5707    #[serde(default)]
5708    pub enabled: bool,
5709
5710    /// Mixture model configuration for amounts.
5711    #[serde(default)]
5712    pub amounts: MixtureDistributionSchemaConfig,
5713
5714    /// Cross-field correlation configuration.
5715    #[serde(default)]
5716    pub correlations: CorrelationSchemaConfig,
5717
5718    /// Conditional distribution configurations.
5719    #[serde(default)]
5720    pub conditional: Vec<ConditionalDistributionSchemaConfig>,
5721
5722    /// Regime change configuration.
5723    #[serde(default)]
5724    pub regime_changes: RegimeChangeSchemaConfig,
5725
5726    /// Industry-specific distribution profile.
5727    #[serde(default)]
5728    pub industry_profile: Option<IndustryProfileType>,
5729
5730    /// Statistical validation configuration.
5731    #[serde(default)]
5732    pub validation: StatisticalValidationSchemaConfig,
5733}
5734
5735/// Industry profile types for pre-configured distribution settings.
5736#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5737#[serde(rename_all = "snake_case")]
5738pub enum IndustryProfileType {
5739    /// Retail industry profile (POS sales, inventory, seasonal)
5740    Retail,
5741    /// Manufacturing industry profile (raw materials, maintenance, capital)
5742    Manufacturing,
5743    /// Financial services profile (wire transfers, ACH, fee income)
5744    FinancialServices,
5745    /// Healthcare profile (claims, procedures, supplies)
5746    Healthcare,
5747    /// Technology profile (subscriptions, services, R&D)
5748    Technology,
5749}
5750
5751/// Mixture model distribution configuration.
5752#[derive(Debug, Clone, Serialize, Deserialize)]
5753pub struct MixtureDistributionSchemaConfig {
5754    /// Enable mixture model for amount generation.
5755    #[serde(default)]
5756    pub enabled: bool,
5757
5758    /// Distribution type: "gaussian" or "lognormal".
5759    #[serde(default = "default_mixture_type")]
5760    pub distribution_type: MixtureDistributionType,
5761
5762    /// Mixture components with weights.
5763    #[serde(default)]
5764    pub components: Vec<MixtureComponentConfig>,
5765
5766    /// Minimum value constraint.
5767    #[serde(default = "default_min_amount")]
5768    pub min_value: f64,
5769
5770    /// Maximum value constraint (optional).
5771    #[serde(default)]
5772    pub max_value: Option<f64>,
5773
5774    /// Decimal places for rounding.
5775    #[serde(default = "default_decimal_places")]
5776    pub decimal_places: u8,
5777}
5778
5779fn default_mixture_type() -> MixtureDistributionType {
5780    MixtureDistributionType::LogNormal
5781}
5782
5783fn default_min_amount() -> f64 {
5784    0.01
5785}
5786
5787fn default_decimal_places() -> u8 {
5788    2
5789}
5790
5791impl Default for MixtureDistributionSchemaConfig {
5792    fn default() -> Self {
5793        Self {
5794            enabled: false,
5795            distribution_type: MixtureDistributionType::LogNormal,
5796            components: Vec::new(),
5797            min_value: 0.01,
5798            max_value: None,
5799            decimal_places: 2,
5800        }
5801    }
5802}
5803
5804/// Mixture distribution type.
5805#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5806#[serde(rename_all = "snake_case")]
5807pub enum MixtureDistributionType {
5808    /// Gaussian (normal) mixture
5809    Gaussian,
5810    /// Log-normal mixture (for positive amounts)
5811    #[default]
5812    LogNormal,
5813}
5814
5815/// Configuration for a single mixture component.
5816#[derive(Debug, Clone, Serialize, Deserialize)]
5817pub struct MixtureComponentConfig {
5818    /// Weight of this component (must sum to 1.0 across all components).
5819    pub weight: f64,
5820
5821    /// Location parameter (mean for Gaussian, mu for log-normal).
5822    pub mu: f64,
5823
5824    /// Scale parameter (std dev for Gaussian, sigma for log-normal).
5825    pub sigma: f64,
5826
5827    /// Optional label for this component (e.g., "routine", "significant", "major").
5828    #[serde(default)]
5829    pub label: Option<String>,
5830}
5831
5832/// Cross-field correlation configuration.
5833#[derive(Debug, Clone, Serialize, Deserialize)]
5834pub struct CorrelationSchemaConfig {
5835    /// Enable correlation modeling.
5836    #[serde(default)]
5837    pub enabled: bool,
5838
5839    /// Copula type for dependency modeling.
5840    #[serde(default)]
5841    pub copula_type: CopulaSchemaType,
5842
5843    /// Field definitions for correlation.
5844    #[serde(default)]
5845    pub fields: Vec<CorrelatedFieldConfig>,
5846
5847    /// Correlation matrix (upper triangular, row-major).
5848    /// For n fields, this should have n*(n-1)/2 values.
5849    #[serde(default)]
5850    pub matrix: Vec<f64>,
5851
5852    /// Expected correlations for validation.
5853    #[serde(default)]
5854    pub expected_correlations: Vec<ExpectedCorrelationConfig>,
5855}
5856
5857impl Default for CorrelationSchemaConfig {
5858    fn default() -> Self {
5859        Self {
5860            enabled: false,
5861            copula_type: CopulaSchemaType::Gaussian,
5862            fields: Vec::new(),
5863            matrix: Vec::new(),
5864            expected_correlations: Vec::new(),
5865        }
5866    }
5867}
5868
5869/// Copula type for dependency modeling.
5870#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5871#[serde(rename_all = "snake_case")]
5872pub enum CopulaSchemaType {
5873    /// Gaussian copula (symmetric, no tail dependence)
5874    #[default]
5875    Gaussian,
5876    /// Clayton copula (lower tail dependence)
5877    Clayton,
5878    /// Gumbel copula (upper tail dependence)
5879    Gumbel,
5880    /// Frank copula (symmetric, no tail dependence)
5881    Frank,
5882    /// Student-t copula (both tail dependencies)
5883    StudentT,
5884}
5885
5886/// Configuration for a correlated field.
5887#[derive(Debug, Clone, Serialize, Deserialize)]
5888pub struct CorrelatedFieldConfig {
5889    /// Field name.
5890    pub name: String,
5891
5892    /// Marginal distribution type.
5893    #[serde(default)]
5894    pub distribution: MarginalDistributionConfig,
5895}
5896
5897/// Marginal distribution configuration.
5898#[derive(Debug, Clone, Serialize, Deserialize)]
5899#[serde(tag = "type", rename_all = "snake_case")]
5900pub enum MarginalDistributionConfig {
5901    /// Normal distribution.
5902    Normal {
5903        /// Mean
5904        mu: f64,
5905        /// Standard deviation
5906        sigma: f64,
5907    },
5908    /// Log-normal distribution.
5909    LogNormal {
5910        /// Location parameter
5911        mu: f64,
5912        /// Scale parameter
5913        sigma: f64,
5914    },
5915    /// Uniform distribution.
5916    Uniform {
5917        /// Minimum value
5918        min: f64,
5919        /// Maximum value
5920        max: f64,
5921    },
5922    /// Discrete uniform distribution.
5923    DiscreteUniform {
5924        /// Minimum integer value
5925        min: i32,
5926        /// Maximum integer value
5927        max: i32,
5928    },
5929}
5930
5931impl Default for MarginalDistributionConfig {
5932    fn default() -> Self {
5933        Self::Normal {
5934            mu: 0.0,
5935            sigma: 1.0,
5936        }
5937    }
5938}
5939
5940/// Expected correlation for validation.
5941#[derive(Debug, Clone, Serialize, Deserialize)]
5942pub struct ExpectedCorrelationConfig {
5943    /// First field name.
5944    pub field1: String,
5945    /// Second field name.
5946    pub field2: String,
5947    /// Expected correlation coefficient.
5948    pub expected_r: f64,
5949    /// Acceptable tolerance.
5950    #[serde(default = "default_correlation_tolerance")]
5951    pub tolerance: f64,
5952}
5953
5954fn default_correlation_tolerance() -> f64 {
5955    0.10
5956}
5957
5958/// Conditional distribution configuration.
5959#[derive(Debug, Clone, Serialize, Deserialize)]
5960pub struct ConditionalDistributionSchemaConfig {
5961    /// Output field name to generate.
5962    pub output_field: String,
5963
5964    /// Input field name that conditions the distribution.
5965    pub input_field: String,
5966
5967    /// Breakpoints defining distribution changes.
5968    #[serde(default)]
5969    pub breakpoints: Vec<ConditionalBreakpointConfig>,
5970
5971    /// Default distribution when below all breakpoints.
5972    #[serde(default)]
5973    pub default_distribution: ConditionalDistributionParamsConfig,
5974
5975    /// Minimum output value constraint.
5976    #[serde(default)]
5977    pub min_value: Option<f64>,
5978
5979    /// Maximum output value constraint.
5980    #[serde(default)]
5981    pub max_value: Option<f64>,
5982
5983    /// Decimal places for output rounding.
5984    #[serde(default = "default_decimal_places")]
5985    pub decimal_places: u8,
5986}
5987
5988/// Breakpoint for conditional distribution.
5989#[derive(Debug, Clone, Serialize, Deserialize)]
5990pub struct ConditionalBreakpointConfig {
5991    /// Input value threshold.
5992    pub threshold: f64,
5993
5994    /// Distribution to use when input >= threshold.
5995    pub distribution: ConditionalDistributionParamsConfig,
5996}
5997
5998/// Distribution parameters for conditional distributions.
5999#[derive(Debug, Clone, Serialize, Deserialize)]
6000#[serde(tag = "type", rename_all = "snake_case")]
6001pub enum ConditionalDistributionParamsConfig {
6002    /// Fixed value.
6003    Fixed {
6004        /// The fixed value
6005        value: f64,
6006    },
6007    /// Normal distribution.
6008    Normal {
6009        /// Mean
6010        mu: f64,
6011        /// Standard deviation
6012        sigma: f64,
6013    },
6014    /// Log-normal distribution.
6015    LogNormal {
6016        /// Location parameter
6017        mu: f64,
6018        /// Scale parameter
6019        sigma: f64,
6020    },
6021    /// Uniform distribution.
6022    Uniform {
6023        /// Minimum
6024        min: f64,
6025        /// Maximum
6026        max: f64,
6027    },
6028    /// Beta distribution (scaled).
6029    Beta {
6030        /// Alpha parameter
6031        alpha: f64,
6032        /// Beta parameter
6033        beta: f64,
6034        /// Minimum output value
6035        min: f64,
6036        /// Maximum output value
6037        max: f64,
6038    },
6039    /// Discrete values with weights.
6040    Discrete {
6041        /// Possible values
6042        values: Vec<f64>,
6043        /// Weights (should sum to 1.0)
6044        weights: Vec<f64>,
6045    },
6046}
6047
6048impl Default for ConditionalDistributionParamsConfig {
6049    fn default() -> Self {
6050        Self::Normal {
6051            mu: 0.0,
6052            sigma: 1.0,
6053        }
6054    }
6055}
6056
6057/// Regime change configuration.
6058#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6059pub struct RegimeChangeSchemaConfig {
6060    /// Enable regime change modeling.
6061    #[serde(default)]
6062    pub enabled: bool,
6063
6064    /// List of regime changes.
6065    #[serde(default)]
6066    pub changes: Vec<RegimeChangeEventConfig>,
6067
6068    /// Economic cycle configuration.
6069    #[serde(default)]
6070    pub economic_cycle: Option<EconomicCycleSchemaConfig>,
6071
6072    /// Parameter drift configurations.
6073    #[serde(default)]
6074    pub parameter_drifts: Vec<ParameterDriftSchemaConfig>,
6075}
6076
6077/// A single regime change event.
6078#[derive(Debug, Clone, Serialize, Deserialize)]
6079pub struct RegimeChangeEventConfig {
6080    /// Date when the change occurs (ISO 8601 format).
6081    pub date: String,
6082
6083    /// Type of regime change.
6084    pub change_type: RegimeChangeTypeConfig,
6085
6086    /// Description of the change.
6087    #[serde(default)]
6088    pub description: Option<String>,
6089
6090    /// Effects of this regime change.
6091    #[serde(default)]
6092    pub effects: Vec<RegimeEffectConfig>,
6093}
6094
6095/// Type of regime change.
6096#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6097#[serde(rename_all = "snake_case")]
6098pub enum RegimeChangeTypeConfig {
6099    /// Acquisition - sudden volume and amount increase
6100    Acquisition,
6101    /// Divestiture - sudden volume and amount decrease
6102    Divestiture,
6103    /// Price increase - amounts increase
6104    PriceIncrease,
6105    /// Price decrease - amounts decrease
6106    PriceDecrease,
6107    /// New product launch - volume ramp-up
6108    ProductLaunch,
6109    /// Product discontinuation - volume ramp-down
6110    ProductDiscontinuation,
6111    /// Policy change - affects patterns
6112    PolicyChange,
6113    /// Competitor entry - market disruption
6114    CompetitorEntry,
6115    /// Custom effect
6116    Custom,
6117}
6118
6119/// Effect of a regime change on a specific field.
6120#[derive(Debug, Clone, Serialize, Deserialize)]
6121pub struct RegimeEffectConfig {
6122    /// Field being affected.
6123    pub field: String,
6124
6125    /// Multiplier to apply (1.0 = no change, 1.5 = 50% increase).
6126    pub multiplier: f64,
6127}
6128
6129/// Economic cycle configuration.
6130#[derive(Debug, Clone, Serialize, Deserialize)]
6131pub struct EconomicCycleSchemaConfig {
6132    /// Enable economic cycle modeling.
6133    #[serde(default)]
6134    pub enabled: bool,
6135
6136    /// Cycle period in months (e.g., 48 for 4-year business cycle).
6137    #[serde(default = "default_cycle_period")]
6138    pub period_months: u32,
6139
6140    /// Amplitude of cycle effect (0.0-1.0).
6141    #[serde(default = "default_cycle_amplitude")]
6142    pub amplitude: f64,
6143
6144    /// Phase offset in months.
6145    #[serde(default)]
6146    pub phase_offset: u32,
6147
6148    /// Recession periods (start_month, duration_months).
6149    #[serde(default)]
6150    pub recessions: Vec<RecessionPeriodConfig>,
6151}
6152
6153fn default_cycle_period() -> u32 {
6154    48
6155}
6156
6157fn default_cycle_amplitude() -> f64 {
6158    0.15
6159}
6160
6161impl Default for EconomicCycleSchemaConfig {
6162    fn default() -> Self {
6163        Self {
6164            enabled: false,
6165            period_months: 48,
6166            amplitude: 0.15,
6167            phase_offset: 0,
6168            recessions: Vec::new(),
6169        }
6170    }
6171}
6172
6173/// Recession period configuration.
6174#[derive(Debug, Clone, Serialize, Deserialize)]
6175pub struct RecessionPeriodConfig {
6176    /// Start month (0-indexed from generation start).
6177    pub start_month: u32,
6178
6179    /// Duration in months.
6180    pub duration_months: u32,
6181
6182    /// Severity (0.0-1.0, affects volume reduction).
6183    #[serde(default = "default_recession_severity")]
6184    pub severity: f64,
6185}
6186
6187fn default_recession_severity() -> f64 {
6188    0.20
6189}
6190
6191/// Parameter drift configuration.
6192#[derive(Debug, Clone, Serialize, Deserialize)]
6193pub struct ParameterDriftSchemaConfig {
6194    /// Parameter being drifted.
6195    pub parameter: String,
6196
6197    /// Drift type.
6198    pub drift_type: ParameterDriftTypeConfig,
6199
6200    /// Start value.
6201    pub start_value: f64,
6202
6203    /// End value.
6204    pub end_value: f64,
6205
6206    /// Start period (month, 0-indexed).
6207    #[serde(default)]
6208    pub start_period: u32,
6209
6210    /// End period (month, optional - defaults to end of generation).
6211    #[serde(default)]
6212    pub end_period: Option<u32>,
6213}
6214
6215/// Parameter drift type.
6216#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6217#[serde(rename_all = "snake_case")]
6218pub enum ParameterDriftTypeConfig {
6219    /// Linear interpolation
6220    #[default]
6221    Linear,
6222    /// Exponential growth/decay
6223    Exponential,
6224    /// S-curve (logistic)
6225    Logistic,
6226    /// Step function
6227    Step,
6228}
6229
6230/// Statistical validation configuration.
6231#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6232pub struct StatisticalValidationSchemaConfig {
6233    /// Enable statistical validation.
6234    #[serde(default)]
6235    pub enabled: bool,
6236
6237    /// Statistical tests to run.
6238    #[serde(default)]
6239    pub tests: Vec<StatisticalTestConfig>,
6240
6241    /// Validation reporting configuration.
6242    #[serde(default)]
6243    pub reporting: ValidationReportingConfig,
6244}
6245
6246/// Statistical test configuration.
6247#[derive(Debug, Clone, Serialize, Deserialize)]
6248#[serde(tag = "type", rename_all = "snake_case")]
6249pub enum StatisticalTestConfig {
6250    /// Benford's Law first digit test.
6251    BenfordFirstDigit {
6252        /// Threshold MAD for failure.
6253        #[serde(default = "default_benford_threshold")]
6254        threshold_mad: f64,
6255        /// Warning MAD threshold.
6256        #[serde(default = "default_benford_warning")]
6257        warning_mad: f64,
6258    },
6259    /// Distribution fit test.
6260    DistributionFit {
6261        /// Target distribution to test.
6262        target: TargetDistributionConfig,
6263        /// K-S test significance level.
6264        #[serde(default = "default_ks_significance")]
6265        ks_significance: f64,
6266        /// Test method (ks, anderson_darling, chi_squared).
6267        #[serde(default)]
6268        method: DistributionFitMethod,
6269    },
6270    /// Correlation check.
6271    CorrelationCheck {
6272        /// Expected correlations to validate.
6273        expected_correlations: Vec<ExpectedCorrelationConfig>,
6274    },
6275    /// Chi-squared test.
6276    ChiSquared {
6277        /// Number of bins.
6278        #[serde(default = "default_chi_squared_bins")]
6279        bins: usize,
6280        /// Significance level.
6281        #[serde(default = "default_chi_squared_significance")]
6282        significance: f64,
6283    },
6284    /// Anderson-Darling test.
6285    AndersonDarling {
6286        /// Target distribution.
6287        target: TargetDistributionConfig,
6288        /// Significance level.
6289        #[serde(default = "default_ad_significance")]
6290        significance: f64,
6291    },
6292}
6293
6294fn default_benford_threshold() -> f64 {
6295    0.015
6296}
6297
6298fn default_benford_warning() -> f64 {
6299    0.010
6300}
6301
6302fn default_ks_significance() -> f64 {
6303    0.05
6304}
6305
6306fn default_chi_squared_bins() -> usize {
6307    10
6308}
6309
6310fn default_chi_squared_significance() -> f64 {
6311    0.05
6312}
6313
6314fn default_ad_significance() -> f64 {
6315    0.05
6316}
6317
6318/// Target distribution for fit tests.
6319#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6320#[serde(rename_all = "snake_case")]
6321pub enum TargetDistributionConfig {
6322    /// Normal distribution
6323    Normal,
6324    /// Log-normal distribution
6325    #[default]
6326    LogNormal,
6327    /// Exponential distribution
6328    Exponential,
6329    /// Uniform distribution
6330    Uniform,
6331}
6332
6333/// Distribution fit test method.
6334#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6335#[serde(rename_all = "snake_case")]
6336pub enum DistributionFitMethod {
6337    /// Kolmogorov-Smirnov test
6338    #[default]
6339    KolmogorovSmirnov,
6340    /// Anderson-Darling test
6341    AndersonDarling,
6342    /// Chi-squared test
6343    ChiSquared,
6344}
6345
6346/// Validation reporting configuration.
6347#[derive(Debug, Clone, Serialize, Deserialize)]
6348pub struct ValidationReportingConfig {
6349    /// Output validation report to file.
6350    #[serde(default)]
6351    pub output_report: bool,
6352
6353    /// Report format.
6354    #[serde(default)]
6355    pub format: ValidationReportFormat,
6356
6357    /// Fail generation if validation fails.
6358    #[serde(default)]
6359    pub fail_on_error: bool,
6360
6361    /// Include detailed statistics in report.
6362    #[serde(default = "default_true")]
6363    pub include_details: bool,
6364}
6365
6366impl Default for ValidationReportingConfig {
6367    fn default() -> Self {
6368        Self {
6369            output_report: false,
6370            format: ValidationReportFormat::Json,
6371            fail_on_error: false,
6372            include_details: true,
6373        }
6374    }
6375}
6376
6377/// Validation report format.
6378#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6379#[serde(rename_all = "snake_case")]
6380pub enum ValidationReportFormat {
6381    /// JSON format
6382    #[default]
6383    Json,
6384    /// YAML format
6385    Yaml,
6386    /// HTML report
6387    Html,
6388}
6389
6390// =============================================================================
6391// Temporal Patterns Configuration
6392// =============================================================================
6393
6394/// Temporal patterns configuration for business days, period-end dynamics, and processing lags.
6395///
6396/// This section enables sophisticated temporal modeling including:
6397/// - Business day calculations and settlement dates
6398/// - Regional holiday calendars
6399/// - Period-end decay curves (non-flat volume spikes)
6400/// - Processing lag modeling (event-to-posting delays)
6401#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6402pub struct TemporalPatternsConfig {
6403    /// Enable temporal patterns features.
6404    #[serde(default)]
6405    pub enabled: bool,
6406
6407    /// Business day calculation configuration.
6408    #[serde(default)]
6409    pub business_days: BusinessDaySchemaConfig,
6410
6411    /// Regional calendar configuration.
6412    #[serde(default)]
6413    pub calendars: CalendarSchemaConfig,
6414
6415    /// Period-end dynamics configuration.
6416    #[serde(default)]
6417    pub period_end: PeriodEndSchemaConfig,
6418
6419    /// Processing lag configuration.
6420    #[serde(default)]
6421    pub processing_lags: ProcessingLagSchemaConfig,
6422
6423    /// Fiscal calendar configuration (custom year start, 4-4-5, 13-period).
6424    #[serde(default)]
6425    pub fiscal_calendar: FiscalCalendarSchemaConfig,
6426
6427    /// Intra-day patterns configuration (morning spike, lunch dip, EOD rush).
6428    #[serde(default)]
6429    pub intraday: IntraDaySchemaConfig,
6430
6431    /// Timezone handling configuration.
6432    #[serde(default)]
6433    pub timezones: TimezoneSchemaConfig,
6434}
6435
6436/// Business day calculation configuration.
6437#[derive(Debug, Clone, Serialize, Deserialize)]
6438pub struct BusinessDaySchemaConfig {
6439    /// Enable business day calculations.
6440    #[serde(default = "default_true")]
6441    pub enabled: bool,
6442
6443    /// Half-day policy: "full_day", "half_day", "non_business_day".
6444    #[serde(default = "default_half_day_policy")]
6445    pub half_day_policy: String,
6446
6447    /// Settlement rules configuration.
6448    #[serde(default)]
6449    pub settlement_rules: SettlementRulesSchemaConfig,
6450
6451    /// Month-end convention: "modified_following", "preceding", "following", "end_of_month".
6452    #[serde(default = "default_month_end_convention")]
6453    pub month_end_convention: String,
6454
6455    /// Weekend days (e.g., ["saturday", "sunday"] or ["friday", "saturday"] for Middle East).
6456    #[serde(default)]
6457    pub weekend_days: Option<Vec<String>>,
6458}
6459
6460fn default_half_day_policy() -> String {
6461    "half_day".to_string()
6462}
6463
6464fn default_month_end_convention() -> String {
6465    "modified_following".to_string()
6466}
6467
6468impl Default for BusinessDaySchemaConfig {
6469    fn default() -> Self {
6470        Self {
6471            enabled: true,
6472            half_day_policy: "half_day".to_string(),
6473            settlement_rules: SettlementRulesSchemaConfig::default(),
6474            month_end_convention: "modified_following".to_string(),
6475            weekend_days: None,
6476        }
6477    }
6478}
6479
6480/// Settlement rules configuration.
6481#[derive(Debug, Clone, Serialize, Deserialize)]
6482pub struct SettlementRulesSchemaConfig {
6483    /// Equity settlement days (T+N).
6484    #[serde(default = "default_settlement_2")]
6485    pub equity_days: i32,
6486
6487    /// Government bonds settlement days.
6488    #[serde(default = "default_settlement_1")]
6489    pub government_bonds_days: i32,
6490
6491    /// FX spot settlement days.
6492    #[serde(default = "default_settlement_2")]
6493    pub fx_spot_days: i32,
6494
6495    /// Corporate bonds settlement days.
6496    #[serde(default = "default_settlement_2")]
6497    pub corporate_bonds_days: i32,
6498
6499    /// Wire transfer cutoff time (HH:MM format).
6500    #[serde(default = "default_wire_cutoff")]
6501    pub wire_cutoff_time: String,
6502
6503    /// International wire settlement days.
6504    #[serde(default = "default_settlement_1")]
6505    pub wire_international_days: i32,
6506
6507    /// ACH settlement days.
6508    #[serde(default = "default_settlement_1")]
6509    pub ach_days: i32,
6510}
6511
6512fn default_settlement_1() -> i32 {
6513    1
6514}
6515
6516fn default_settlement_2() -> i32 {
6517    2
6518}
6519
6520fn default_wire_cutoff() -> String {
6521    "14:00".to_string()
6522}
6523
6524impl Default for SettlementRulesSchemaConfig {
6525    fn default() -> Self {
6526        Self {
6527            equity_days: 2,
6528            government_bonds_days: 1,
6529            fx_spot_days: 2,
6530            corporate_bonds_days: 2,
6531            wire_cutoff_time: "14:00".to_string(),
6532            wire_international_days: 1,
6533            ach_days: 1,
6534        }
6535    }
6536}
6537
6538/// Regional calendar configuration.
6539#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6540pub struct CalendarSchemaConfig {
6541    /// List of regions to include (e.g., ["US", "DE", "BR", "SG", "KR"]).
6542    #[serde(default)]
6543    pub regions: Vec<String>,
6544
6545    /// Custom holidays (in addition to regional calendars).
6546    #[serde(default)]
6547    pub custom_holidays: Vec<CustomHolidaySchemaConfig>,
6548}
6549
6550/// Custom holiday configuration.
6551#[derive(Debug, Clone, Serialize, Deserialize)]
6552pub struct CustomHolidaySchemaConfig {
6553    /// Holiday name.
6554    pub name: String,
6555    /// Month (1-12).
6556    pub month: u8,
6557    /// Day of month.
6558    pub day: u8,
6559    /// Activity multiplier (0.0-1.0, default 0.05).
6560    #[serde(default = "default_holiday_multiplier")]
6561    pub activity_multiplier: f64,
6562}
6563
6564fn default_holiday_multiplier() -> f64 {
6565    0.05
6566}
6567
6568/// Period-end dynamics configuration.
6569#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6570pub struct PeriodEndSchemaConfig {
6571    /// Model type: "flat", "exponential", "extended_crunch", "daily_profile".
6572    #[serde(default)]
6573    pub model: Option<String>,
6574
6575    /// Month-end configuration.
6576    #[serde(default)]
6577    pub month_end: Option<PeriodEndModelSchemaConfig>,
6578
6579    /// Quarter-end configuration.
6580    #[serde(default)]
6581    pub quarter_end: Option<PeriodEndModelSchemaConfig>,
6582
6583    /// Year-end configuration.
6584    #[serde(default)]
6585    pub year_end: Option<PeriodEndModelSchemaConfig>,
6586}
6587
6588/// Period-end model configuration.
6589#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6590pub struct PeriodEndModelSchemaConfig {
6591    /// Inherit configuration from another period (e.g., "month_end").
6592    #[serde(default)]
6593    pub inherit_from: Option<String>,
6594
6595    /// Additional multiplier on top of inherited/base model.
6596    #[serde(default)]
6597    pub additional_multiplier: Option<f64>,
6598
6599    /// Days before period end to start acceleration (negative, e.g., -10).
6600    #[serde(default)]
6601    pub start_day: Option<i32>,
6602
6603    /// Base multiplier at start of acceleration.
6604    #[serde(default)]
6605    pub base_multiplier: Option<f64>,
6606
6607    /// Peak multiplier on last day.
6608    #[serde(default)]
6609    pub peak_multiplier: Option<f64>,
6610
6611    /// Decay rate for exponential model (0.1-0.5 typical).
6612    #[serde(default)]
6613    pub decay_rate: Option<f64>,
6614
6615    /// Sustained high days for crunch model.
6616    #[serde(default)]
6617    pub sustained_high_days: Option<i32>,
6618}
6619
6620/// Processing lag configuration.
6621#[derive(Debug, Clone, Serialize, Deserialize)]
6622pub struct ProcessingLagSchemaConfig {
6623    /// Enable processing lag calculations.
6624    #[serde(default = "default_true")]
6625    pub enabled: bool,
6626
6627    /// Sales order lag configuration (log-normal mu, sigma).
6628    #[serde(default)]
6629    pub sales_order_lag: Option<LagDistributionSchemaConfig>,
6630
6631    /// Purchase order lag configuration.
6632    #[serde(default)]
6633    pub purchase_order_lag: Option<LagDistributionSchemaConfig>,
6634
6635    /// Goods receipt lag configuration.
6636    #[serde(default)]
6637    pub goods_receipt_lag: Option<LagDistributionSchemaConfig>,
6638
6639    /// Invoice receipt lag configuration.
6640    #[serde(default)]
6641    pub invoice_receipt_lag: Option<LagDistributionSchemaConfig>,
6642
6643    /// Invoice issue lag configuration.
6644    #[serde(default)]
6645    pub invoice_issue_lag: Option<LagDistributionSchemaConfig>,
6646
6647    /// Payment lag configuration.
6648    #[serde(default)]
6649    pub payment_lag: Option<LagDistributionSchemaConfig>,
6650
6651    /// Journal entry lag configuration.
6652    #[serde(default)]
6653    pub journal_entry_lag: Option<LagDistributionSchemaConfig>,
6654
6655    /// Cross-day posting configuration.
6656    #[serde(default)]
6657    pub cross_day_posting: Option<CrossDayPostingSchemaConfig>,
6658}
6659
6660impl Default for ProcessingLagSchemaConfig {
6661    fn default() -> Self {
6662        Self {
6663            enabled: true,
6664            sales_order_lag: None,
6665            purchase_order_lag: None,
6666            goods_receipt_lag: None,
6667            invoice_receipt_lag: None,
6668            invoice_issue_lag: None,
6669            payment_lag: None,
6670            journal_entry_lag: None,
6671            cross_day_posting: None,
6672        }
6673    }
6674}
6675
6676/// Lag distribution configuration (log-normal parameters).
6677#[derive(Debug, Clone, Serialize, Deserialize)]
6678pub struct LagDistributionSchemaConfig {
6679    /// Log-scale mean (mu for log-normal).
6680    pub mu: f64,
6681    /// Log-scale standard deviation (sigma for log-normal).
6682    pub sigma: f64,
6683    /// Minimum lag in hours.
6684    #[serde(default)]
6685    pub min_hours: Option<f64>,
6686    /// Maximum lag in hours.
6687    #[serde(default)]
6688    pub max_hours: Option<f64>,
6689}
6690
6691/// Cross-day posting configuration.
6692#[derive(Debug, Clone, Serialize, Deserialize)]
6693pub struct CrossDayPostingSchemaConfig {
6694    /// Enable cross-day posting logic.
6695    #[serde(default = "default_true")]
6696    pub enabled: bool,
6697
6698    /// Probability of next-day posting by hour (map of hour -> probability).
6699    /// E.g., { 17: 0.7, 19: 0.9, 21: 0.99 }
6700    #[serde(default)]
6701    pub probability_by_hour: std::collections::HashMap<u8, f64>,
6702}
6703
6704impl Default for CrossDayPostingSchemaConfig {
6705    fn default() -> Self {
6706        let mut probability_by_hour = std::collections::HashMap::new();
6707        probability_by_hour.insert(17, 0.3);
6708        probability_by_hour.insert(18, 0.6);
6709        probability_by_hour.insert(19, 0.8);
6710        probability_by_hour.insert(20, 0.9);
6711        probability_by_hour.insert(21, 0.95);
6712        probability_by_hour.insert(22, 0.99);
6713
6714        Self {
6715            enabled: true,
6716            probability_by_hour,
6717        }
6718    }
6719}
6720
6721// =============================================================================
6722// Fiscal Calendar Configuration (P2)
6723// =============================================================================
6724
6725/// Fiscal calendar configuration.
6726///
6727/// Supports calendar year, custom year start, 4-4-5 retail calendar,
6728/// and 13-period calendars.
6729#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6730pub struct FiscalCalendarSchemaConfig {
6731    /// Enable non-standard fiscal calendar.
6732    #[serde(default)]
6733    pub enabled: bool,
6734
6735    /// Fiscal calendar type: "calendar_year", "custom", "four_four_five", "thirteen_period".
6736    #[serde(default = "default_fiscal_calendar_type")]
6737    pub calendar_type: String,
6738
6739    /// Month the fiscal year starts (1-12). Used for custom year start.
6740    #[serde(default)]
6741    pub year_start_month: Option<u8>,
6742
6743    /// Day the fiscal year starts (1-31). Used for custom year start.
6744    #[serde(default)]
6745    pub year_start_day: Option<u8>,
6746
6747    /// 4-4-5 calendar configuration (if calendar_type is "four_four_five").
6748    #[serde(default)]
6749    pub four_four_five: Option<FourFourFiveSchemaConfig>,
6750}
6751
6752fn default_fiscal_calendar_type() -> String {
6753    "calendar_year".to_string()
6754}
6755
6756/// 4-4-5 retail calendar configuration.
6757#[derive(Debug, Clone, Serialize, Deserialize)]
6758pub struct FourFourFiveSchemaConfig {
6759    /// Week pattern: "four_four_five", "four_five_four", "five_four_four".
6760    #[serde(default = "default_week_pattern")]
6761    pub pattern: String,
6762
6763    /// Anchor type: "first_sunday", "last_saturday", "nearest_saturday".
6764    #[serde(default = "default_anchor_type")]
6765    pub anchor_type: String,
6766
6767    /// Anchor month (1-12).
6768    #[serde(default = "default_anchor_month")]
6769    pub anchor_month: u8,
6770
6771    /// Where to place leap week: "q4_period3" or "q1_period1".
6772    #[serde(default = "default_leap_week_placement")]
6773    pub leap_week_placement: String,
6774}
6775
6776fn default_week_pattern() -> String {
6777    "four_four_five".to_string()
6778}
6779
6780fn default_anchor_type() -> String {
6781    "last_saturday".to_string()
6782}
6783
6784fn default_anchor_month() -> u8 {
6785    1 // January
6786}
6787
6788fn default_leap_week_placement() -> String {
6789    "q4_period3".to_string()
6790}
6791
6792impl Default for FourFourFiveSchemaConfig {
6793    fn default() -> Self {
6794        Self {
6795            pattern: "four_four_five".to_string(),
6796            anchor_type: "last_saturday".to_string(),
6797            anchor_month: 1,
6798            leap_week_placement: "q4_period3".to_string(),
6799        }
6800    }
6801}
6802
6803// =============================================================================
6804// Intra-Day Patterns Configuration (P2)
6805// =============================================================================
6806
6807/// Intra-day patterns configuration.
6808///
6809/// Defines time-of-day segments with different activity multipliers
6810/// for realistic modeling of morning spikes, lunch dips, and end-of-day rushes.
6811#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6812pub struct IntraDaySchemaConfig {
6813    /// Enable intra-day patterns.
6814    #[serde(default)]
6815    pub enabled: bool,
6816
6817    /// Custom intra-day segments.
6818    #[serde(default)]
6819    pub segments: Vec<IntraDaySegmentSchemaConfig>,
6820}
6821
6822/// Intra-day segment configuration.
6823#[derive(Debug, Clone, Serialize, Deserialize)]
6824pub struct IntraDaySegmentSchemaConfig {
6825    /// Name of the segment (e.g., "morning_spike", "lunch_dip").
6826    pub name: String,
6827
6828    /// Start time (HH:MM format).
6829    pub start: String,
6830
6831    /// End time (HH:MM format).
6832    pub end: String,
6833
6834    /// Activity multiplier (1.0 = normal).
6835    #[serde(default = "default_multiplier")]
6836    pub multiplier: f64,
6837
6838    /// Posting type: "human", "system", "both".
6839    #[serde(default = "default_posting_type")]
6840    pub posting_type: String,
6841}
6842
6843fn default_multiplier() -> f64 {
6844    1.0
6845}
6846
6847fn default_posting_type() -> String {
6848    "both".to_string()
6849}
6850
6851// =============================================================================
6852// Timezone Configuration
6853// =============================================================================
6854
6855/// Timezone handling configuration for multi-region entities.
6856#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6857pub struct TimezoneSchemaConfig {
6858    /// Enable timezone handling.
6859    #[serde(default)]
6860    pub enabled: bool,
6861
6862    /// Default timezone (IANA format, e.g., "America/New_York").
6863    #[serde(default = "default_timezone")]
6864    pub default_timezone: String,
6865
6866    /// Consolidation timezone for group reporting (IANA format).
6867    #[serde(default = "default_consolidation_timezone")]
6868    pub consolidation_timezone: String,
6869
6870    /// Entity-to-timezone mappings.
6871    /// Supports patterns like "EU_*" -> "Europe/London".
6872    #[serde(default)]
6873    pub entity_mappings: Vec<EntityTimezoneMapping>,
6874}
6875
6876fn default_timezone() -> String {
6877    "America/New_York".to_string()
6878}
6879
6880fn default_consolidation_timezone() -> String {
6881    "UTC".to_string()
6882}
6883
6884/// Mapping from entity pattern to timezone.
6885#[derive(Debug, Clone, Serialize, Deserialize)]
6886pub struct EntityTimezoneMapping {
6887    /// Entity code pattern (e.g., "EU_*", "*_APAC", "1000").
6888    pub pattern: String,
6889
6890    /// Timezone (IANA format, e.g., "Europe/London").
6891    pub timezone: String,
6892}
6893
6894// =============================================================================
6895// Vendor Network Configuration
6896// =============================================================================
6897
6898/// Configuration for multi-tier vendor network generation.
6899#[derive(Debug, Clone, Serialize, Deserialize)]
6900pub struct VendorNetworkSchemaConfig {
6901    /// Enable vendor network generation.
6902    #[serde(default)]
6903    pub enabled: bool,
6904
6905    /// Maximum depth of supply chain tiers (1-3).
6906    #[serde(default = "default_vendor_tier_depth")]
6907    pub depth: u8,
6908
6909    /// Tier 1 vendor count configuration.
6910    #[serde(default)]
6911    pub tier1: TierCountSchemaConfig,
6912
6913    /// Tier 2 vendors per Tier 1 parent.
6914    #[serde(default)]
6915    pub tier2_per_parent: TierCountSchemaConfig,
6916
6917    /// Tier 3 vendors per Tier 2 parent.
6918    #[serde(default)]
6919    pub tier3_per_parent: TierCountSchemaConfig,
6920
6921    /// Vendor cluster distribution.
6922    #[serde(default)]
6923    pub clusters: VendorClusterSchemaConfig,
6924
6925    /// Concentration limits.
6926    #[serde(default)]
6927    pub dependencies: DependencySchemaConfig,
6928}
6929
6930fn default_vendor_tier_depth() -> u8 {
6931    3
6932}
6933
6934impl Default for VendorNetworkSchemaConfig {
6935    fn default() -> Self {
6936        Self {
6937            enabled: false,
6938            depth: 3,
6939            tier1: TierCountSchemaConfig { min: 50, max: 100 },
6940            tier2_per_parent: TierCountSchemaConfig { min: 4, max: 10 },
6941            tier3_per_parent: TierCountSchemaConfig { min: 2, max: 5 },
6942            clusters: VendorClusterSchemaConfig::default(),
6943            dependencies: DependencySchemaConfig::default(),
6944        }
6945    }
6946}
6947
6948/// Tier count configuration.
6949#[derive(Debug, Clone, Serialize, Deserialize)]
6950pub struct TierCountSchemaConfig {
6951    /// Minimum count.
6952    #[serde(default = "default_tier_min")]
6953    pub min: usize,
6954
6955    /// Maximum count.
6956    #[serde(default = "default_tier_max")]
6957    pub max: usize,
6958}
6959
6960fn default_tier_min() -> usize {
6961    5
6962}
6963
6964fn default_tier_max() -> usize {
6965    20
6966}
6967
6968impl Default for TierCountSchemaConfig {
6969    fn default() -> Self {
6970        Self {
6971            min: default_tier_min(),
6972            max: default_tier_max(),
6973        }
6974    }
6975}
6976
6977/// Vendor cluster distribution configuration.
6978#[derive(Debug, Clone, Serialize, Deserialize)]
6979pub struct VendorClusterSchemaConfig {
6980    /// Reliable strategic vendors percentage (default: 0.20).
6981    #[serde(default = "default_reliable_strategic")]
6982    pub reliable_strategic: f64,
6983
6984    /// Standard operational vendors percentage (default: 0.50).
6985    #[serde(default = "default_standard_operational")]
6986    pub standard_operational: f64,
6987
6988    /// Transactional vendors percentage (default: 0.25).
6989    #[serde(default = "default_transactional")]
6990    pub transactional: f64,
6991
6992    /// Problematic vendors percentage (default: 0.05).
6993    #[serde(default = "default_problematic")]
6994    pub problematic: f64,
6995}
6996
6997fn default_reliable_strategic() -> f64 {
6998    0.20
6999}
7000
7001fn default_standard_operational() -> f64 {
7002    0.50
7003}
7004
7005fn default_transactional() -> f64 {
7006    0.25
7007}
7008
7009fn default_problematic() -> f64 {
7010    0.05
7011}
7012
7013impl Default for VendorClusterSchemaConfig {
7014    fn default() -> Self {
7015        Self {
7016            reliable_strategic: 0.20,
7017            standard_operational: 0.50,
7018            transactional: 0.25,
7019            problematic: 0.05,
7020        }
7021    }
7022}
7023
7024/// Dependency and concentration limits configuration.
7025#[derive(Debug, Clone, Serialize, Deserialize)]
7026pub struct DependencySchemaConfig {
7027    /// Maximum concentration for a single vendor (default: 0.15).
7028    #[serde(default = "default_max_single_vendor")]
7029    pub max_single_vendor_concentration: f64,
7030
7031    /// Maximum concentration for top 5 vendors (default: 0.45).
7032    #[serde(default = "default_max_top5")]
7033    pub top_5_concentration: f64,
7034
7035    /// Percentage of single-source vendors (default: 0.05).
7036    #[serde(default = "default_single_source_percent")]
7037    pub single_source_percent: f64,
7038}
7039
7040fn default_max_single_vendor() -> f64 {
7041    0.15
7042}
7043
7044fn default_max_top5() -> f64 {
7045    0.45
7046}
7047
7048fn default_single_source_percent() -> f64 {
7049    0.05
7050}
7051
7052impl Default for DependencySchemaConfig {
7053    fn default() -> Self {
7054        Self {
7055            max_single_vendor_concentration: 0.15,
7056            top_5_concentration: 0.45,
7057            single_source_percent: 0.05,
7058        }
7059    }
7060}
7061
7062// =============================================================================
7063// Customer Segmentation Configuration
7064// =============================================================================
7065
7066/// Configuration for customer segmentation generation.
7067#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7068pub struct CustomerSegmentationSchemaConfig {
7069    /// Enable customer segmentation generation.
7070    #[serde(default)]
7071    pub enabled: bool,
7072
7073    /// Value segment distribution.
7074    #[serde(default)]
7075    pub value_segments: ValueSegmentsSchemaConfig,
7076
7077    /// Lifecycle stage configuration.
7078    #[serde(default)]
7079    pub lifecycle: LifecycleSchemaConfig,
7080
7081    /// Network (referrals, hierarchies) configuration.
7082    #[serde(default)]
7083    pub networks: CustomerNetworksSchemaConfig,
7084}
7085
7086/// Customer value segments distribution configuration.
7087#[derive(Debug, Clone, Serialize, Deserialize)]
7088pub struct ValueSegmentsSchemaConfig {
7089    /// Enterprise segment configuration.
7090    #[serde(default)]
7091    pub enterprise: SegmentDetailSchemaConfig,
7092
7093    /// Mid-market segment configuration.
7094    #[serde(default)]
7095    pub mid_market: SegmentDetailSchemaConfig,
7096
7097    /// SMB segment configuration.
7098    #[serde(default)]
7099    pub smb: SegmentDetailSchemaConfig,
7100
7101    /// Consumer segment configuration.
7102    #[serde(default)]
7103    pub consumer: SegmentDetailSchemaConfig,
7104}
7105
7106impl Default for ValueSegmentsSchemaConfig {
7107    fn default() -> Self {
7108        Self {
7109            enterprise: SegmentDetailSchemaConfig {
7110                revenue_share: 0.40,
7111                customer_share: 0.05,
7112                avg_order_value_range: "50000+".to_string(),
7113            },
7114            mid_market: SegmentDetailSchemaConfig {
7115                revenue_share: 0.35,
7116                customer_share: 0.20,
7117                avg_order_value_range: "5000-50000".to_string(),
7118            },
7119            smb: SegmentDetailSchemaConfig {
7120                revenue_share: 0.20,
7121                customer_share: 0.50,
7122                avg_order_value_range: "500-5000".to_string(),
7123            },
7124            consumer: SegmentDetailSchemaConfig {
7125                revenue_share: 0.05,
7126                customer_share: 0.25,
7127                avg_order_value_range: "50-500".to_string(),
7128            },
7129        }
7130    }
7131}
7132
7133/// Individual segment detail configuration.
7134#[derive(Debug, Clone, Serialize, Deserialize)]
7135pub struct SegmentDetailSchemaConfig {
7136    /// Revenue share for this segment.
7137    #[serde(default)]
7138    pub revenue_share: f64,
7139
7140    /// Customer share for this segment.
7141    #[serde(default)]
7142    pub customer_share: f64,
7143
7144    /// Average order value range (e.g., "5000-50000" or "50000+").
7145    #[serde(default)]
7146    pub avg_order_value_range: String,
7147}
7148
7149impl Default for SegmentDetailSchemaConfig {
7150    fn default() -> Self {
7151        Self {
7152            revenue_share: 0.25,
7153            customer_share: 0.25,
7154            avg_order_value_range: "1000-10000".to_string(),
7155        }
7156    }
7157}
7158
7159/// Customer lifecycle stage configuration.
7160#[derive(Debug, Clone, Serialize, Deserialize)]
7161pub struct LifecycleSchemaConfig {
7162    /// Prospect stage rate.
7163    #[serde(default)]
7164    pub prospect_rate: f64,
7165
7166    /// New customer stage rate.
7167    #[serde(default = "default_new_rate")]
7168    pub new_rate: f64,
7169
7170    /// Growth stage rate.
7171    #[serde(default = "default_growth_rate")]
7172    pub growth_rate: f64,
7173
7174    /// Mature stage rate.
7175    #[serde(default = "default_mature_rate")]
7176    pub mature_rate: f64,
7177
7178    /// At-risk stage rate.
7179    #[serde(default = "default_at_risk_rate")]
7180    pub at_risk_rate: f64,
7181
7182    /// Churned stage rate.
7183    #[serde(default = "default_churned_rate")]
7184    pub churned_rate: f64,
7185
7186    /// Won-back stage rate (churned customers reacquired).
7187    #[serde(default)]
7188    pub won_back_rate: f64,
7189}
7190
7191fn default_new_rate() -> f64 {
7192    0.10
7193}
7194
7195fn default_growth_rate() -> f64 {
7196    0.15
7197}
7198
7199fn default_mature_rate() -> f64 {
7200    0.60
7201}
7202
7203fn default_at_risk_rate() -> f64 {
7204    0.10
7205}
7206
7207fn default_churned_rate() -> f64 {
7208    0.05
7209}
7210
7211impl Default for LifecycleSchemaConfig {
7212    fn default() -> Self {
7213        Self {
7214            prospect_rate: 0.0,
7215            new_rate: 0.10,
7216            growth_rate: 0.15,
7217            mature_rate: 0.60,
7218            at_risk_rate: 0.10,
7219            churned_rate: 0.05,
7220            won_back_rate: 0.0,
7221        }
7222    }
7223}
7224
7225/// Customer networks configuration (referrals, hierarchies).
7226#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7227pub struct CustomerNetworksSchemaConfig {
7228    /// Referral network configuration.
7229    #[serde(default)]
7230    pub referrals: ReferralSchemaConfig,
7231
7232    /// Corporate hierarchy configuration.
7233    #[serde(default)]
7234    pub corporate_hierarchies: HierarchySchemaConfig,
7235}
7236
7237/// Referral network configuration.
7238#[derive(Debug, Clone, Serialize, Deserialize)]
7239pub struct ReferralSchemaConfig {
7240    /// Enable referral generation.
7241    #[serde(default = "default_true")]
7242    pub enabled: bool,
7243
7244    /// Rate of customers acquired via referral.
7245    #[serde(default = "default_referral_rate")]
7246    pub referral_rate: f64,
7247}
7248
7249fn default_referral_rate() -> f64 {
7250    0.15
7251}
7252
7253impl Default for ReferralSchemaConfig {
7254    fn default() -> Self {
7255        Self {
7256            enabled: true,
7257            referral_rate: 0.15,
7258        }
7259    }
7260}
7261
7262/// Corporate hierarchy configuration.
7263#[derive(Debug, Clone, Serialize, Deserialize)]
7264pub struct HierarchySchemaConfig {
7265    /// Enable corporate hierarchy generation.
7266    #[serde(default = "default_true")]
7267    pub enabled: bool,
7268
7269    /// Rate of customers in hierarchies.
7270    #[serde(default = "default_hierarchy_rate")]
7271    pub probability: f64,
7272}
7273
7274fn default_hierarchy_rate() -> f64 {
7275    0.30
7276}
7277
7278impl Default for HierarchySchemaConfig {
7279    fn default() -> Self {
7280        Self {
7281            enabled: true,
7282            probability: 0.30,
7283        }
7284    }
7285}
7286
7287// =============================================================================
7288// Relationship Strength Configuration
7289// =============================================================================
7290
7291/// Configuration for relationship strength calculation.
7292#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7293pub struct RelationshipStrengthSchemaConfig {
7294    /// Enable relationship strength calculation.
7295    #[serde(default)]
7296    pub enabled: bool,
7297
7298    /// Calculation weights.
7299    #[serde(default)]
7300    pub calculation: StrengthCalculationSchemaConfig,
7301
7302    /// Strength thresholds for classification.
7303    #[serde(default)]
7304    pub thresholds: StrengthThresholdsSchemaConfig,
7305}
7306
7307/// Strength calculation weights configuration.
7308#[derive(Debug, Clone, Serialize, Deserialize)]
7309pub struct StrengthCalculationSchemaConfig {
7310    /// Weight for transaction volume (default: 0.30).
7311    #[serde(default = "default_volume_weight")]
7312    pub transaction_volume_weight: f64,
7313
7314    /// Weight for transaction count (default: 0.25).
7315    #[serde(default = "default_count_weight")]
7316    pub transaction_count_weight: f64,
7317
7318    /// Weight for relationship duration (default: 0.20).
7319    #[serde(default = "default_duration_weight")]
7320    pub relationship_duration_weight: f64,
7321
7322    /// Weight for recency (default: 0.15).
7323    #[serde(default = "default_recency_weight")]
7324    pub recency_weight: f64,
7325
7326    /// Weight for mutual connections (default: 0.10).
7327    #[serde(default = "default_mutual_weight")]
7328    pub mutual_connections_weight: f64,
7329
7330    /// Recency half-life in days (default: 90).
7331    #[serde(default = "default_recency_half_life")]
7332    pub recency_half_life_days: u32,
7333}
7334
7335fn default_volume_weight() -> f64 {
7336    0.30
7337}
7338
7339fn default_count_weight() -> f64 {
7340    0.25
7341}
7342
7343fn default_duration_weight() -> f64 {
7344    0.20
7345}
7346
7347fn default_recency_weight() -> f64 {
7348    0.15
7349}
7350
7351fn default_mutual_weight() -> f64 {
7352    0.10
7353}
7354
7355fn default_recency_half_life() -> u32 {
7356    90
7357}
7358
7359impl Default for StrengthCalculationSchemaConfig {
7360    fn default() -> Self {
7361        Self {
7362            transaction_volume_weight: 0.30,
7363            transaction_count_weight: 0.25,
7364            relationship_duration_weight: 0.20,
7365            recency_weight: 0.15,
7366            mutual_connections_weight: 0.10,
7367            recency_half_life_days: 90,
7368        }
7369    }
7370}
7371
7372/// Strength thresholds for relationship classification.
7373#[derive(Debug, Clone, Serialize, Deserialize)]
7374pub struct StrengthThresholdsSchemaConfig {
7375    /// Threshold for strong relationships (default: 0.7).
7376    #[serde(default = "default_strong_threshold")]
7377    pub strong: f64,
7378
7379    /// Threshold for moderate relationships (default: 0.4).
7380    #[serde(default = "default_moderate_threshold")]
7381    pub moderate: f64,
7382
7383    /// Threshold for weak relationships (default: 0.1).
7384    #[serde(default = "default_weak_threshold")]
7385    pub weak: f64,
7386}
7387
7388fn default_strong_threshold() -> f64 {
7389    0.7
7390}
7391
7392fn default_moderate_threshold() -> f64 {
7393    0.4
7394}
7395
7396fn default_weak_threshold() -> f64 {
7397    0.1
7398}
7399
7400impl Default for StrengthThresholdsSchemaConfig {
7401    fn default() -> Self {
7402        Self {
7403            strong: 0.7,
7404            moderate: 0.4,
7405            weak: 0.1,
7406        }
7407    }
7408}
7409
7410// =============================================================================
7411// Cross-Process Links Configuration
7412// =============================================================================
7413
7414/// Configuration for cross-process linkages.
7415#[derive(Debug, Clone, Serialize, Deserialize)]
7416pub struct CrossProcessLinksSchemaConfig {
7417    /// Enable cross-process link generation.
7418    #[serde(default)]
7419    pub enabled: bool,
7420
7421    /// Enable inventory links between P2P and O2C.
7422    #[serde(default = "default_true")]
7423    pub inventory_p2p_o2c: bool,
7424
7425    /// Enable payment to bank reconciliation links.
7426    #[serde(default = "default_true")]
7427    pub payment_bank_reconciliation: bool,
7428
7429    /// Enable intercompany bilateral matching.
7430    #[serde(default = "default_true")]
7431    pub intercompany_bilateral: bool,
7432
7433    /// Percentage of GR/Deliveries to link via inventory (0.0 - 1.0).
7434    #[serde(default = "default_inventory_link_rate")]
7435    pub inventory_link_rate: f64,
7436}
7437
7438fn default_inventory_link_rate() -> f64 {
7439    0.30
7440}
7441
7442impl Default for CrossProcessLinksSchemaConfig {
7443    fn default() -> Self {
7444        Self {
7445            enabled: false,
7446            inventory_p2p_o2c: true,
7447            payment_bank_reconciliation: true,
7448            intercompany_bilateral: true,
7449            inventory_link_rate: 0.30,
7450        }
7451    }
7452}
7453
7454// =============================================================================
7455// Organizational Events Configuration
7456// =============================================================================
7457
7458/// Configuration for organizational events (acquisitions, divestitures, etc.).
7459#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7460pub struct OrganizationalEventsSchemaConfig {
7461    /// Enable organizational events.
7462    #[serde(default)]
7463    pub enabled: bool,
7464
7465    /// Effect blending mode (multiplicative, additive, maximum, minimum).
7466    #[serde(default)]
7467    pub effect_blending: EffectBlendingModeConfig,
7468
7469    /// Organizational events (acquisitions, divestitures, reorganizations, etc.).
7470    #[serde(default)]
7471    pub events: Vec<OrganizationalEventSchemaConfig>,
7472
7473    /// Process evolution events.
7474    #[serde(default)]
7475    pub process_evolution: Vec<ProcessEvolutionSchemaConfig>,
7476
7477    /// Technology transition events.
7478    #[serde(default)]
7479    pub technology_transitions: Vec<TechnologyTransitionSchemaConfig>,
7480}
7481
7482/// Effect blending mode for combining multiple event effects.
7483#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7484#[serde(rename_all = "snake_case")]
7485pub enum EffectBlendingModeConfig {
7486    /// Multiply effects together.
7487    #[default]
7488    Multiplicative,
7489    /// Add effects together.
7490    Additive,
7491    /// Take the maximum effect.
7492    Maximum,
7493    /// Take the minimum effect.
7494    Minimum,
7495}
7496
7497/// Configuration for a single organizational event.
7498#[derive(Debug, Clone, Serialize, Deserialize)]
7499pub struct OrganizationalEventSchemaConfig {
7500    /// Event ID.
7501    pub id: String,
7502
7503    /// Event type and configuration.
7504    pub event_type: OrganizationalEventTypeSchemaConfig,
7505
7506    /// Effective date.
7507    pub effective_date: String,
7508
7509    /// Transition duration in months.
7510    #[serde(default = "default_org_transition_months")]
7511    pub transition_months: u32,
7512
7513    /// Description.
7514    #[serde(default)]
7515    pub description: Option<String>,
7516}
7517
7518fn default_org_transition_months() -> u32 {
7519    6
7520}
7521
7522/// Organizational event type configuration.
7523#[derive(Debug, Clone, Serialize, Deserialize)]
7524#[serde(tag = "type", rename_all = "snake_case")]
7525pub enum OrganizationalEventTypeSchemaConfig {
7526    /// Acquisition event.
7527    Acquisition {
7528        /// Acquired entity code.
7529        acquired_entity: String,
7530        /// Volume increase multiplier.
7531        #[serde(default = "default_acquisition_volume")]
7532        volume_increase: f64,
7533        /// Integration error rate.
7534        #[serde(default = "default_acquisition_error")]
7535        integration_error_rate: f64,
7536        /// Parallel posting days.
7537        #[serde(default = "default_parallel_days")]
7538        parallel_posting_days: u32,
7539    },
7540    /// Divestiture event.
7541    Divestiture {
7542        /// Divested entity code.
7543        divested_entity: String,
7544        /// Volume reduction factor.
7545        #[serde(default = "default_divestiture_volume")]
7546        volume_reduction: f64,
7547        /// Remove entity from generation.
7548        #[serde(default = "default_true_val")]
7549        remove_entity: bool,
7550    },
7551    /// Reorganization event.
7552    Reorganization {
7553        /// Cost center remapping.
7554        #[serde(default)]
7555        cost_center_remapping: std::collections::HashMap<String, String>,
7556        /// Transition error rate.
7557        #[serde(default = "default_reorg_error")]
7558        transition_error_rate: f64,
7559    },
7560    /// Leadership change event.
7561    LeadershipChange {
7562        /// Role that changed.
7563        role: String,
7564        /// Policy changes.
7565        #[serde(default)]
7566        policy_changes: Vec<String>,
7567    },
7568    /// Workforce reduction event.
7569    WorkforceReduction {
7570        /// Reduction percentage.
7571        #[serde(default = "default_workforce_reduction")]
7572        reduction_percent: f64,
7573        /// Error rate increase.
7574        #[serde(default = "default_workforce_error")]
7575        error_rate_increase: f64,
7576    },
7577    /// Merger event.
7578    Merger {
7579        /// Merged entity code.
7580        merged_entity: String,
7581        /// Volume increase multiplier.
7582        #[serde(default = "default_merger_volume")]
7583        volume_increase: f64,
7584    },
7585}
7586
7587fn default_acquisition_volume() -> f64 {
7588    1.35
7589}
7590
7591fn default_acquisition_error() -> f64 {
7592    0.05
7593}
7594
7595fn default_parallel_days() -> u32 {
7596    30
7597}
7598
7599fn default_divestiture_volume() -> f64 {
7600    0.70
7601}
7602
7603fn default_true_val() -> bool {
7604    true
7605}
7606
7607fn default_reorg_error() -> f64 {
7608    0.04
7609}
7610
7611fn default_workforce_reduction() -> f64 {
7612    0.10
7613}
7614
7615fn default_workforce_error() -> f64 {
7616    0.05
7617}
7618
7619fn default_merger_volume() -> f64 {
7620    1.80
7621}
7622
7623/// Configuration for a process evolution event.
7624#[derive(Debug, Clone, Serialize, Deserialize)]
7625pub struct ProcessEvolutionSchemaConfig {
7626    /// Event ID.
7627    pub id: String,
7628
7629    /// Event type.
7630    pub event_type: ProcessEvolutionTypeSchemaConfig,
7631
7632    /// Effective date.
7633    pub effective_date: String,
7634
7635    /// Description.
7636    #[serde(default)]
7637    pub description: Option<String>,
7638}
7639
7640/// Process evolution type configuration.
7641#[derive(Debug, Clone, Serialize, Deserialize)]
7642#[serde(tag = "type", rename_all = "snake_case")]
7643pub enum ProcessEvolutionTypeSchemaConfig {
7644    /// Process automation.
7645    ProcessAutomation {
7646        /// Process name.
7647        process_name: String,
7648        /// Manual rate before.
7649        #[serde(default = "default_manual_before")]
7650        manual_rate_before: f64,
7651        /// Manual rate after.
7652        #[serde(default = "default_manual_after")]
7653        manual_rate_after: f64,
7654    },
7655    /// Approval workflow change.
7656    ApprovalWorkflowChange {
7657        /// Description.
7658        description: String,
7659    },
7660    /// Control enhancement.
7661    ControlEnhancement {
7662        /// Control ID.
7663        control_id: String,
7664        /// Error reduction.
7665        #[serde(default = "default_error_reduction")]
7666        error_reduction: f64,
7667    },
7668}
7669
7670fn default_manual_before() -> f64 {
7671    0.80
7672}
7673
7674fn default_manual_after() -> f64 {
7675    0.15
7676}
7677
7678fn default_error_reduction() -> f64 {
7679    0.02
7680}
7681
7682/// Configuration for a technology transition event.
7683#[derive(Debug, Clone, Serialize, Deserialize)]
7684pub struct TechnologyTransitionSchemaConfig {
7685    /// Event ID.
7686    pub id: String,
7687
7688    /// Event type.
7689    pub event_type: TechnologyTransitionTypeSchemaConfig,
7690
7691    /// Description.
7692    #[serde(default)]
7693    pub description: Option<String>,
7694}
7695
7696/// Technology transition type configuration.
7697#[derive(Debug, Clone, Serialize, Deserialize)]
7698#[serde(tag = "type", rename_all = "snake_case")]
7699pub enum TechnologyTransitionTypeSchemaConfig {
7700    /// ERP migration.
7701    ErpMigration {
7702        /// Source system.
7703        source_system: String,
7704        /// Target system.
7705        target_system: String,
7706        /// Cutover date.
7707        cutover_date: String,
7708        /// Stabilization end date.
7709        stabilization_end: String,
7710        /// Duplicate rate during migration.
7711        #[serde(default = "default_erp_duplicate_rate")]
7712        duplicate_rate: f64,
7713        /// Format mismatch rate.
7714        #[serde(default = "default_format_mismatch")]
7715        format_mismatch_rate: f64,
7716    },
7717    /// Module implementation.
7718    ModuleImplementation {
7719        /// Module name.
7720        module_name: String,
7721        /// Go-live date.
7722        go_live_date: String,
7723    },
7724}
7725
7726fn default_erp_duplicate_rate() -> f64 {
7727    0.02
7728}
7729
7730fn default_format_mismatch() -> f64 {
7731    0.03
7732}
7733
7734// =============================================================================
7735// Behavioral Drift Configuration
7736// =============================================================================
7737
7738/// Configuration for behavioral drift (vendor, customer, employee behavior).
7739#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7740pub struct BehavioralDriftSchemaConfig {
7741    /// Enable behavioral drift.
7742    #[serde(default)]
7743    pub enabled: bool,
7744
7745    /// Vendor behavior drift.
7746    #[serde(default)]
7747    pub vendor_behavior: VendorBehaviorSchemaConfig,
7748
7749    /// Customer behavior drift.
7750    #[serde(default)]
7751    pub customer_behavior: CustomerBehaviorSchemaConfig,
7752
7753    /// Employee behavior drift.
7754    #[serde(default)]
7755    pub employee_behavior: EmployeeBehaviorSchemaConfig,
7756
7757    /// Collective behavior drift.
7758    #[serde(default)]
7759    pub collective: CollectiveBehaviorSchemaConfig,
7760}
7761
7762/// Vendor behavior drift configuration.
7763#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7764pub struct VendorBehaviorSchemaConfig {
7765    /// Payment terms drift.
7766    #[serde(default)]
7767    pub payment_terms_drift: PaymentTermsDriftSchemaConfig,
7768
7769    /// Quality drift.
7770    #[serde(default)]
7771    pub quality_drift: QualityDriftSchemaConfig,
7772}
7773
7774/// Payment terms drift configuration.
7775#[derive(Debug, Clone, Serialize, Deserialize)]
7776pub struct PaymentTermsDriftSchemaConfig {
7777    /// Extension rate per year (days).
7778    #[serde(default = "default_extension_rate")]
7779    pub extension_rate_per_year: f64,
7780
7781    /// Economic sensitivity.
7782    #[serde(default = "default_economic_sensitivity")]
7783    pub economic_sensitivity: f64,
7784}
7785
7786fn default_extension_rate() -> f64 {
7787    2.5
7788}
7789
7790fn default_economic_sensitivity() -> f64 {
7791    1.0
7792}
7793
7794impl Default for PaymentTermsDriftSchemaConfig {
7795    fn default() -> Self {
7796        Self {
7797            extension_rate_per_year: 2.5,
7798            economic_sensitivity: 1.0,
7799        }
7800    }
7801}
7802
7803/// Quality drift configuration.
7804#[derive(Debug, Clone, Serialize, Deserialize)]
7805pub struct QualityDriftSchemaConfig {
7806    /// New vendor improvement rate (per year).
7807    #[serde(default = "default_improvement_rate")]
7808    pub new_vendor_improvement_rate: f64,
7809
7810    /// Complacency decline rate (per year after first year).
7811    #[serde(default = "default_decline_rate")]
7812    pub complacency_decline_rate: f64,
7813}
7814
7815fn default_improvement_rate() -> f64 {
7816    0.02
7817}
7818
7819fn default_decline_rate() -> f64 {
7820    0.01
7821}
7822
7823impl Default for QualityDriftSchemaConfig {
7824    fn default() -> Self {
7825        Self {
7826            new_vendor_improvement_rate: 0.02,
7827            complacency_decline_rate: 0.01,
7828        }
7829    }
7830}
7831
7832/// Customer behavior drift configuration.
7833#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7834pub struct CustomerBehaviorSchemaConfig {
7835    /// Payment drift.
7836    #[serde(default)]
7837    pub payment_drift: CustomerPaymentDriftSchemaConfig,
7838
7839    /// Order drift.
7840    #[serde(default)]
7841    pub order_drift: OrderDriftSchemaConfig,
7842}
7843
7844/// Customer payment drift configuration.
7845#[derive(Debug, Clone, Serialize, Deserialize)]
7846pub struct CustomerPaymentDriftSchemaConfig {
7847    /// Days extension during downturn (min, max).
7848    #[serde(default = "default_downturn_extension")]
7849    pub downturn_days_extension: (u32, u32),
7850
7851    /// Bad debt increase during downturn.
7852    #[serde(default = "default_bad_debt_increase")]
7853    pub downturn_bad_debt_increase: f64,
7854}
7855
7856fn default_downturn_extension() -> (u32, u32) {
7857    (5, 15)
7858}
7859
7860fn default_bad_debt_increase() -> f64 {
7861    0.02
7862}
7863
7864impl Default for CustomerPaymentDriftSchemaConfig {
7865    fn default() -> Self {
7866        Self {
7867            downturn_days_extension: (5, 15),
7868            downturn_bad_debt_increase: 0.02,
7869        }
7870    }
7871}
7872
7873/// Order drift configuration.
7874#[derive(Debug, Clone, Serialize, Deserialize)]
7875pub struct OrderDriftSchemaConfig {
7876    /// Digital shift rate (per year).
7877    #[serde(default = "default_digital_shift")]
7878    pub digital_shift_rate: f64,
7879}
7880
7881fn default_digital_shift() -> f64 {
7882    0.05
7883}
7884
7885impl Default for OrderDriftSchemaConfig {
7886    fn default() -> Self {
7887        Self {
7888            digital_shift_rate: 0.05,
7889        }
7890    }
7891}
7892
7893/// Employee behavior drift configuration.
7894#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7895pub struct EmployeeBehaviorSchemaConfig {
7896    /// Approval drift.
7897    #[serde(default)]
7898    pub approval_drift: ApprovalDriftSchemaConfig,
7899
7900    /// Error drift.
7901    #[serde(default)]
7902    pub error_drift: ErrorDriftSchemaConfig,
7903}
7904
7905/// Approval drift configuration.
7906#[derive(Debug, Clone, Serialize, Deserialize)]
7907pub struct ApprovalDriftSchemaConfig {
7908    /// EOM intensity increase per year.
7909    #[serde(default = "default_eom_intensity")]
7910    pub eom_intensity_increase_per_year: f64,
7911
7912    /// Rubber stamp volume threshold.
7913    #[serde(default = "default_rubber_stamp")]
7914    pub rubber_stamp_volume_threshold: u32,
7915}
7916
7917fn default_eom_intensity() -> f64 {
7918    0.05
7919}
7920
7921fn default_rubber_stamp() -> u32 {
7922    50
7923}
7924
7925impl Default for ApprovalDriftSchemaConfig {
7926    fn default() -> Self {
7927        Self {
7928            eom_intensity_increase_per_year: 0.05,
7929            rubber_stamp_volume_threshold: 50,
7930        }
7931    }
7932}
7933
7934/// Error drift configuration.
7935#[derive(Debug, Clone, Serialize, Deserialize)]
7936pub struct ErrorDriftSchemaConfig {
7937    /// New employee error rate.
7938    #[serde(default = "default_new_error")]
7939    pub new_employee_error_rate: f64,
7940
7941    /// Learning curve months.
7942    #[serde(default = "default_learning_months")]
7943    pub learning_curve_months: u32,
7944}
7945
7946fn default_new_error() -> f64 {
7947    0.08
7948}
7949
7950fn default_learning_months() -> u32 {
7951    6
7952}
7953
7954impl Default for ErrorDriftSchemaConfig {
7955    fn default() -> Self {
7956        Self {
7957            new_employee_error_rate: 0.08,
7958            learning_curve_months: 6,
7959        }
7960    }
7961}
7962
7963/// Collective behavior drift configuration.
7964#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7965pub struct CollectiveBehaviorSchemaConfig {
7966    /// Automation adoption configuration.
7967    #[serde(default)]
7968    pub automation_adoption: AutomationAdoptionSchemaConfig,
7969}
7970
7971/// Automation adoption configuration.
7972#[derive(Debug, Clone, Serialize, Deserialize)]
7973pub struct AutomationAdoptionSchemaConfig {
7974    /// Enable S-curve adoption model.
7975    #[serde(default)]
7976    pub s_curve_enabled: bool,
7977
7978    /// Adoption midpoint in months.
7979    #[serde(default = "default_midpoint")]
7980    pub adoption_midpoint_months: u32,
7981
7982    /// Steepness of adoption curve.
7983    #[serde(default = "default_steepness")]
7984    pub steepness: f64,
7985}
7986
7987fn default_midpoint() -> u32 {
7988    24
7989}
7990
7991fn default_steepness() -> f64 {
7992    0.15
7993}
7994
7995impl Default for AutomationAdoptionSchemaConfig {
7996    fn default() -> Self {
7997        Self {
7998            s_curve_enabled: false,
7999            adoption_midpoint_months: 24,
8000            steepness: 0.15,
8001        }
8002    }
8003}
8004
8005// =============================================================================
8006// Market Drift Configuration
8007// =============================================================================
8008
8009/// Configuration for market drift (economic cycles, commodities, price shocks).
8010#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8011pub struct MarketDriftSchemaConfig {
8012    /// Enable market drift.
8013    #[serde(default)]
8014    pub enabled: bool,
8015
8016    /// Economic cycle configuration.
8017    #[serde(default)]
8018    pub economic_cycle: MarketEconomicCycleSchemaConfig,
8019
8020    /// Industry-specific cycles.
8021    #[serde(default)]
8022    pub industry_cycles: std::collections::HashMap<String, IndustryCycleSchemaConfig>,
8023
8024    /// Commodity drift configuration.
8025    #[serde(default)]
8026    pub commodities: CommoditiesSchemaConfig,
8027}
8028
8029/// Market economic cycle configuration.
8030#[derive(Debug, Clone, Serialize, Deserialize)]
8031pub struct MarketEconomicCycleSchemaConfig {
8032    /// Enable economic cycle.
8033    #[serde(default)]
8034    pub enabled: bool,
8035
8036    /// Cycle type.
8037    #[serde(default)]
8038    pub cycle_type: CycleTypeSchemaConfig,
8039
8040    /// Cycle period in months.
8041    #[serde(default = "default_market_cycle_period")]
8042    pub period_months: u32,
8043
8044    /// Amplitude.
8045    #[serde(default = "default_market_amplitude")]
8046    pub amplitude: f64,
8047
8048    /// Recession configuration.
8049    #[serde(default)]
8050    pub recession: RecessionSchemaConfig,
8051}
8052
8053fn default_market_cycle_period() -> u32 {
8054    48
8055}
8056
8057fn default_market_amplitude() -> f64 {
8058    0.15
8059}
8060
8061impl Default for MarketEconomicCycleSchemaConfig {
8062    fn default() -> Self {
8063        Self {
8064            enabled: false,
8065            cycle_type: CycleTypeSchemaConfig::Sinusoidal,
8066            period_months: 48,
8067            amplitude: 0.15,
8068            recession: RecessionSchemaConfig::default(),
8069        }
8070    }
8071}
8072
8073/// Cycle type configuration.
8074#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
8075#[serde(rename_all = "snake_case")]
8076pub enum CycleTypeSchemaConfig {
8077    /// Sinusoidal cycle.
8078    #[default]
8079    Sinusoidal,
8080    /// Asymmetric cycle.
8081    Asymmetric,
8082    /// Mean-reverting cycle.
8083    MeanReverting,
8084}
8085
8086/// Recession configuration.
8087#[derive(Debug, Clone, Serialize, Deserialize)]
8088pub struct RecessionSchemaConfig {
8089    /// Enable recession simulation.
8090    #[serde(default)]
8091    pub enabled: bool,
8092
8093    /// Probability per year.
8094    #[serde(default = "default_recession_prob")]
8095    pub probability_per_year: f64,
8096
8097    /// Severity.
8098    #[serde(default)]
8099    pub severity: RecessionSeveritySchemaConfig,
8100
8101    /// Specific recession periods.
8102    #[serde(default)]
8103    pub recession_periods: Vec<RecessionPeriodSchemaConfig>,
8104}
8105
8106fn default_recession_prob() -> f64 {
8107    0.10
8108}
8109
8110impl Default for RecessionSchemaConfig {
8111    fn default() -> Self {
8112        Self {
8113            enabled: false,
8114            probability_per_year: 0.10,
8115            severity: RecessionSeveritySchemaConfig::Moderate,
8116            recession_periods: Vec::new(),
8117        }
8118    }
8119}
8120
8121/// Recession severity configuration.
8122#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
8123#[serde(rename_all = "snake_case")]
8124pub enum RecessionSeveritySchemaConfig {
8125    /// Mild recession.
8126    Mild,
8127    /// Moderate recession.
8128    #[default]
8129    Moderate,
8130    /// Severe recession.
8131    Severe,
8132}
8133
8134/// Recession period configuration.
8135#[derive(Debug, Clone, Serialize, Deserialize)]
8136pub struct RecessionPeriodSchemaConfig {
8137    /// Start month.
8138    pub start_month: u32,
8139    /// Duration in months.
8140    pub duration_months: u32,
8141}
8142
8143/// Industry cycle configuration.
8144#[derive(Debug, Clone, Serialize, Deserialize)]
8145pub struct IndustryCycleSchemaConfig {
8146    /// Period in months.
8147    #[serde(default = "default_industry_period")]
8148    pub period_months: u32,
8149
8150    /// Amplitude.
8151    #[serde(default = "default_industry_amp")]
8152    pub amplitude: f64,
8153}
8154
8155fn default_industry_period() -> u32 {
8156    36
8157}
8158
8159fn default_industry_amp() -> f64 {
8160    0.20
8161}
8162
8163/// Commodities drift configuration.
8164#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8165pub struct CommoditiesSchemaConfig {
8166    /// Enable commodity drift.
8167    #[serde(default)]
8168    pub enabled: bool,
8169
8170    /// Commodity items.
8171    #[serde(default)]
8172    pub items: Vec<CommodityItemSchemaConfig>,
8173}
8174
8175/// Commodity item configuration.
8176#[derive(Debug, Clone, Serialize, Deserialize)]
8177pub struct CommodityItemSchemaConfig {
8178    /// Commodity name.
8179    pub name: String,
8180
8181    /// Volatility.
8182    #[serde(default = "default_volatility")]
8183    pub volatility: f64,
8184
8185    /// COGS pass-through.
8186    #[serde(default)]
8187    pub cogs_pass_through: f64,
8188
8189    /// Overhead pass-through.
8190    #[serde(default)]
8191    pub overhead_pass_through: f64,
8192}
8193
8194fn default_volatility() -> f64 {
8195    0.20
8196}
8197
8198// =============================================================================
8199// Drift Labeling Configuration
8200// =============================================================================
8201
8202/// Configuration for drift ground truth labeling.
8203#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8204pub struct DriftLabelingSchemaConfig {
8205    /// Enable drift labeling.
8206    #[serde(default)]
8207    pub enabled: bool,
8208
8209    /// Statistical drift labeling.
8210    #[serde(default)]
8211    pub statistical: StatisticalDriftLabelingSchemaConfig,
8212
8213    /// Categorical drift labeling.
8214    #[serde(default)]
8215    pub categorical: CategoricalDriftLabelingSchemaConfig,
8216
8217    /// Temporal drift labeling.
8218    #[serde(default)]
8219    pub temporal: TemporalDriftLabelingSchemaConfig,
8220
8221    /// Regulatory calendar preset.
8222    #[serde(default)]
8223    pub regulatory_calendar_preset: Option<String>,
8224}
8225
8226/// Statistical drift labeling configuration.
8227#[derive(Debug, Clone, Serialize, Deserialize)]
8228pub struct StatisticalDriftLabelingSchemaConfig {
8229    /// Enable statistical drift labeling.
8230    #[serde(default = "default_true_val")]
8231    pub enabled: bool,
8232
8233    /// Minimum magnitude threshold.
8234    #[serde(default = "default_min_magnitude")]
8235    pub min_magnitude_threshold: f64,
8236}
8237
8238fn default_min_magnitude() -> f64 {
8239    0.05
8240}
8241
8242impl Default for StatisticalDriftLabelingSchemaConfig {
8243    fn default() -> Self {
8244        Self {
8245            enabled: true,
8246            min_magnitude_threshold: 0.05,
8247        }
8248    }
8249}
8250
8251/// Categorical drift labeling configuration.
8252#[derive(Debug, Clone, Serialize, Deserialize)]
8253pub struct CategoricalDriftLabelingSchemaConfig {
8254    /// Enable categorical drift labeling.
8255    #[serde(default = "default_true_val")]
8256    pub enabled: bool,
8257}
8258
8259impl Default for CategoricalDriftLabelingSchemaConfig {
8260    fn default() -> Self {
8261        Self { enabled: true }
8262    }
8263}
8264
8265/// Temporal drift labeling configuration.
8266#[derive(Debug, Clone, Serialize, Deserialize)]
8267pub struct TemporalDriftLabelingSchemaConfig {
8268    /// Enable temporal drift labeling.
8269    #[serde(default = "default_true_val")]
8270    pub enabled: bool,
8271}
8272
8273impl Default for TemporalDriftLabelingSchemaConfig {
8274    fn default() -> Self {
8275        Self { enabled: true }
8276    }
8277}
8278
8279// =============================================================================
8280// Enhanced Anomaly Injection Configuration
8281// =============================================================================
8282
8283/// Enhanced anomaly injection configuration.
8284///
8285/// Provides comprehensive anomaly injection capabilities including:
8286/// - Multi-stage fraud schemes (embezzlement, revenue manipulation, kickbacks)
8287/// - Correlated anomaly injection (co-occurrence patterns, error cascades)
8288/// - Near-miss generation for false positive reduction
8289/// - Detection difficulty classification
8290/// - Context-aware injection based on entity behavior
8291#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8292pub struct EnhancedAnomalyConfig {
8293    /// Enable enhanced anomaly injection.
8294    #[serde(default)]
8295    pub enabled: bool,
8296
8297    /// Base anomaly rates.
8298    #[serde(default)]
8299    pub rates: AnomalyRateConfig,
8300
8301    /// Multi-stage fraud scheme configuration.
8302    #[serde(default)]
8303    pub multi_stage_schemes: MultiStageSchemeConfig,
8304
8305    /// Correlated anomaly injection configuration.
8306    #[serde(default)]
8307    pub correlated_injection: CorrelatedInjectionConfig,
8308
8309    /// Near-miss generation configuration.
8310    #[serde(default)]
8311    pub near_miss: NearMissConfig,
8312
8313    /// Detection difficulty classification configuration.
8314    #[serde(default)]
8315    pub difficulty_classification: DifficultyClassificationConfig,
8316
8317    /// Context-aware injection configuration.
8318    #[serde(default)]
8319    pub context_aware: ContextAwareConfig,
8320
8321    /// Enhanced labeling configuration.
8322    #[serde(default)]
8323    pub labeling: EnhancedLabelingConfig,
8324}
8325
8326/// Base anomaly rate configuration.
8327#[derive(Debug, Clone, Serialize, Deserialize)]
8328pub struct AnomalyRateConfig {
8329    /// Total anomaly rate (0.0 to 1.0).
8330    #[serde(default = "default_total_anomaly_rate")]
8331    pub total_rate: f64,
8332
8333    /// Fraud anomaly rate.
8334    #[serde(default = "default_fraud_anomaly_rate")]
8335    pub fraud_rate: f64,
8336
8337    /// Error anomaly rate.
8338    #[serde(default = "default_error_anomaly_rate")]
8339    pub error_rate: f64,
8340
8341    /// Process issue rate.
8342    #[serde(default = "default_process_anomaly_rate")]
8343    pub process_rate: f64,
8344}
8345
8346fn default_total_anomaly_rate() -> f64 {
8347    0.03
8348}
8349fn default_fraud_anomaly_rate() -> f64 {
8350    0.01
8351}
8352fn default_error_anomaly_rate() -> f64 {
8353    0.015
8354}
8355fn default_process_anomaly_rate() -> f64 {
8356    0.005
8357}
8358
8359impl Default for AnomalyRateConfig {
8360    fn default() -> Self {
8361        Self {
8362            total_rate: default_total_anomaly_rate(),
8363            fraud_rate: default_fraud_anomaly_rate(),
8364            error_rate: default_error_anomaly_rate(),
8365            process_rate: default_process_anomaly_rate(),
8366        }
8367    }
8368}
8369
8370/// Multi-stage fraud scheme configuration.
8371#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8372pub struct MultiStageSchemeConfig {
8373    /// Enable multi-stage fraud schemes.
8374    #[serde(default)]
8375    pub enabled: bool,
8376
8377    /// Embezzlement scheme configuration.
8378    #[serde(default)]
8379    pub embezzlement: EmbezzlementSchemeConfig,
8380
8381    /// Revenue manipulation scheme configuration.
8382    #[serde(default)]
8383    pub revenue_manipulation: RevenueManipulationSchemeConfig,
8384
8385    /// Vendor kickback scheme configuration.
8386    #[serde(default)]
8387    pub kickback: KickbackSchemeConfig,
8388}
8389
8390/// Embezzlement scheme configuration.
8391#[derive(Debug, Clone, Serialize, Deserialize)]
8392pub struct EmbezzlementSchemeConfig {
8393    /// Probability of starting an embezzlement scheme per perpetrator per year.
8394    #[serde(default = "default_embezzlement_probability")]
8395    pub probability: f64,
8396
8397    /// Testing stage configuration.
8398    #[serde(default)]
8399    pub testing_stage: SchemeStageConfig,
8400
8401    /// Escalation stage configuration.
8402    #[serde(default)]
8403    pub escalation_stage: SchemeStageConfig,
8404
8405    /// Acceleration stage configuration.
8406    #[serde(default)]
8407    pub acceleration_stage: SchemeStageConfig,
8408
8409    /// Desperation stage configuration.
8410    #[serde(default)]
8411    pub desperation_stage: SchemeStageConfig,
8412}
8413
8414fn default_embezzlement_probability() -> f64 {
8415    0.02
8416}
8417
8418impl Default for EmbezzlementSchemeConfig {
8419    fn default() -> Self {
8420        Self {
8421            probability: default_embezzlement_probability(),
8422            testing_stage: SchemeStageConfig {
8423                duration_months: 2,
8424                amount_min: 100.0,
8425                amount_max: 500.0,
8426                transaction_count_min: 2,
8427                transaction_count_max: 5,
8428                difficulty: "hard".to_string(),
8429            },
8430            escalation_stage: SchemeStageConfig {
8431                duration_months: 6,
8432                amount_min: 500.0,
8433                amount_max: 2000.0,
8434                transaction_count_min: 3,
8435                transaction_count_max: 8,
8436                difficulty: "moderate".to_string(),
8437            },
8438            acceleration_stage: SchemeStageConfig {
8439                duration_months: 3,
8440                amount_min: 2000.0,
8441                amount_max: 10000.0,
8442                transaction_count_min: 5,
8443                transaction_count_max: 12,
8444                difficulty: "easy".to_string(),
8445            },
8446            desperation_stage: SchemeStageConfig {
8447                duration_months: 1,
8448                amount_min: 10000.0,
8449                amount_max: 50000.0,
8450                transaction_count_min: 3,
8451                transaction_count_max: 6,
8452                difficulty: "trivial".to_string(),
8453            },
8454        }
8455    }
8456}
8457
8458/// Revenue manipulation scheme configuration.
8459#[derive(Debug, Clone, Serialize, Deserialize)]
8460pub struct RevenueManipulationSchemeConfig {
8461    /// Probability of starting a revenue manipulation scheme per period.
8462    #[serde(default = "default_revenue_manipulation_probability")]
8463    pub probability: f64,
8464
8465    /// Early revenue recognition inflation target (Q4).
8466    #[serde(default = "default_early_recognition_target")]
8467    pub early_recognition_target: f64,
8468
8469    /// Expense deferral inflation target (Q1).
8470    #[serde(default = "default_expense_deferral_target")]
8471    pub expense_deferral_target: f64,
8472
8473    /// Reserve release inflation target (Q2).
8474    #[serde(default = "default_reserve_release_target")]
8475    pub reserve_release_target: f64,
8476
8477    /// Channel stuffing inflation target (Q4).
8478    #[serde(default = "default_channel_stuffing_target")]
8479    pub channel_stuffing_target: f64,
8480}
8481
8482fn default_revenue_manipulation_probability() -> f64 {
8483    0.01
8484}
8485fn default_early_recognition_target() -> f64 {
8486    0.02
8487}
8488fn default_expense_deferral_target() -> f64 {
8489    0.03
8490}
8491fn default_reserve_release_target() -> f64 {
8492    0.02
8493}
8494fn default_channel_stuffing_target() -> f64 {
8495    0.05
8496}
8497
8498impl Default for RevenueManipulationSchemeConfig {
8499    fn default() -> Self {
8500        Self {
8501            probability: default_revenue_manipulation_probability(),
8502            early_recognition_target: default_early_recognition_target(),
8503            expense_deferral_target: default_expense_deferral_target(),
8504            reserve_release_target: default_reserve_release_target(),
8505            channel_stuffing_target: default_channel_stuffing_target(),
8506        }
8507    }
8508}
8509
8510/// Vendor kickback scheme configuration.
8511#[derive(Debug, Clone, Serialize, Deserialize)]
8512pub struct KickbackSchemeConfig {
8513    /// Probability of starting a kickback scheme.
8514    #[serde(default = "default_kickback_probability")]
8515    pub probability: f64,
8516
8517    /// Minimum price inflation percentage.
8518    #[serde(default = "default_kickback_inflation_min")]
8519    pub inflation_min: f64,
8520
8521    /// Maximum price inflation percentage.
8522    #[serde(default = "default_kickback_inflation_max")]
8523    pub inflation_max: f64,
8524
8525    /// Kickback percentage (of inflation).
8526    #[serde(default = "default_kickback_percent")]
8527    pub kickback_percent: f64,
8528
8529    /// Setup duration in months.
8530    #[serde(default = "default_kickback_setup_months")]
8531    pub setup_months: u32,
8532
8533    /// Main operation duration in months.
8534    #[serde(default = "default_kickback_operation_months")]
8535    pub operation_months: u32,
8536}
8537
8538fn default_kickback_probability() -> f64 {
8539    0.01
8540}
8541fn default_kickback_inflation_min() -> f64 {
8542    0.10
8543}
8544fn default_kickback_inflation_max() -> f64 {
8545    0.25
8546}
8547fn default_kickback_percent() -> f64 {
8548    0.50
8549}
8550fn default_kickback_setup_months() -> u32 {
8551    3
8552}
8553fn default_kickback_operation_months() -> u32 {
8554    12
8555}
8556
8557impl Default for KickbackSchemeConfig {
8558    fn default() -> Self {
8559        Self {
8560            probability: default_kickback_probability(),
8561            inflation_min: default_kickback_inflation_min(),
8562            inflation_max: default_kickback_inflation_max(),
8563            kickback_percent: default_kickback_percent(),
8564            setup_months: default_kickback_setup_months(),
8565            operation_months: default_kickback_operation_months(),
8566        }
8567    }
8568}
8569
8570/// Individual scheme stage configuration.
8571#[derive(Debug, Clone, Serialize, Deserialize)]
8572pub struct SchemeStageConfig {
8573    /// Duration in months.
8574    pub duration_months: u32,
8575
8576    /// Minimum transaction amount.
8577    pub amount_min: f64,
8578
8579    /// Maximum transaction amount.
8580    pub amount_max: f64,
8581
8582    /// Minimum number of transactions.
8583    pub transaction_count_min: u32,
8584
8585    /// Maximum number of transactions.
8586    pub transaction_count_max: u32,
8587
8588    /// Detection difficulty level (trivial, easy, moderate, hard, expert).
8589    pub difficulty: String,
8590}
8591
8592impl Default for SchemeStageConfig {
8593    fn default() -> Self {
8594        Self {
8595            duration_months: 3,
8596            amount_min: 100.0,
8597            amount_max: 1000.0,
8598            transaction_count_min: 2,
8599            transaction_count_max: 10,
8600            difficulty: "moderate".to_string(),
8601        }
8602    }
8603}
8604
8605/// Correlated anomaly injection configuration.
8606#[derive(Debug, Clone, Serialize, Deserialize)]
8607pub struct CorrelatedInjectionConfig {
8608    /// Enable correlated anomaly injection.
8609    #[serde(default)]
8610    pub enabled: bool,
8611
8612    /// Enable fraud concealment co-occurrence patterns.
8613    #[serde(default = "default_true_val")]
8614    pub fraud_concealment: bool,
8615
8616    /// Enable error cascade patterns.
8617    #[serde(default = "default_true_val")]
8618    pub error_cascade: bool,
8619
8620    /// Enable temporal clustering (period-end spikes).
8621    #[serde(default = "default_true_val")]
8622    pub temporal_clustering: bool,
8623
8624    /// Temporal clustering configuration.
8625    #[serde(default)]
8626    pub temporal_clustering_config: TemporalClusteringConfig,
8627
8628    /// Co-occurrence patterns.
8629    #[serde(default)]
8630    pub co_occurrence_patterns: Vec<CoOccurrencePatternConfig>,
8631}
8632
8633impl Default for CorrelatedInjectionConfig {
8634    fn default() -> Self {
8635        Self {
8636            enabled: false,
8637            fraud_concealment: true,
8638            error_cascade: true,
8639            temporal_clustering: true,
8640            temporal_clustering_config: TemporalClusteringConfig::default(),
8641            co_occurrence_patterns: Vec::new(),
8642        }
8643    }
8644}
8645
8646/// Temporal clustering configuration.
8647#[derive(Debug, Clone, Serialize, Deserialize)]
8648pub struct TemporalClusteringConfig {
8649    /// Period-end error multiplier.
8650    #[serde(default = "default_period_end_multiplier")]
8651    pub period_end_multiplier: f64,
8652
8653    /// Number of business days before period end to apply multiplier.
8654    #[serde(default = "default_period_end_days")]
8655    pub period_end_days: u32,
8656
8657    /// Quarter-end additional multiplier.
8658    #[serde(default = "default_quarter_end_multiplier")]
8659    pub quarter_end_multiplier: f64,
8660
8661    /// Year-end additional multiplier.
8662    #[serde(default = "default_year_end_multiplier")]
8663    pub year_end_multiplier: f64,
8664}
8665
8666fn default_period_end_multiplier() -> f64 {
8667    2.5
8668}
8669fn default_period_end_days() -> u32 {
8670    5
8671}
8672fn default_quarter_end_multiplier() -> f64 {
8673    1.5
8674}
8675fn default_year_end_multiplier() -> f64 {
8676    2.0
8677}
8678
8679impl Default for TemporalClusteringConfig {
8680    fn default() -> Self {
8681        Self {
8682            period_end_multiplier: default_period_end_multiplier(),
8683            period_end_days: default_period_end_days(),
8684            quarter_end_multiplier: default_quarter_end_multiplier(),
8685            year_end_multiplier: default_year_end_multiplier(),
8686        }
8687    }
8688}
8689
8690/// Co-occurrence pattern configuration.
8691#[derive(Debug, Clone, Serialize, Deserialize)]
8692pub struct CoOccurrencePatternConfig {
8693    /// Pattern name.
8694    pub name: String,
8695
8696    /// Primary anomaly type that triggers the pattern.
8697    pub primary_type: String,
8698
8699    /// Correlated anomalies.
8700    pub correlated: Vec<CorrelatedAnomalyConfig>,
8701}
8702
8703/// Correlated anomaly configuration.
8704#[derive(Debug, Clone, Serialize, Deserialize)]
8705pub struct CorrelatedAnomalyConfig {
8706    /// Anomaly type.
8707    pub anomaly_type: String,
8708
8709    /// Probability of occurrence (0.0 to 1.0).
8710    pub probability: f64,
8711
8712    /// Minimum lag in days.
8713    pub lag_days_min: i32,
8714
8715    /// Maximum lag in days.
8716    pub lag_days_max: i32,
8717}
8718
8719/// Near-miss generation configuration.
8720#[derive(Debug, Clone, Serialize, Deserialize)]
8721pub struct NearMissConfig {
8722    /// Enable near-miss generation.
8723    #[serde(default)]
8724    pub enabled: bool,
8725
8726    /// Proportion of "anomalies" that are actually near-misses (0.0 to 1.0).
8727    #[serde(default = "default_near_miss_proportion")]
8728    pub proportion: f64,
8729
8730    /// Enable near-duplicate pattern.
8731    #[serde(default = "default_true_val")]
8732    pub near_duplicate: bool,
8733
8734    /// Near-duplicate date difference range in days.
8735    #[serde(default)]
8736    pub near_duplicate_days: NearDuplicateDaysConfig,
8737
8738    /// Enable threshold proximity pattern.
8739    #[serde(default = "default_true_val")]
8740    pub threshold_proximity: bool,
8741
8742    /// Threshold proximity range (e.g., 0.90-0.99 of threshold).
8743    #[serde(default)]
8744    pub threshold_proximity_range: ThresholdProximityRangeConfig,
8745
8746    /// Enable unusual but legitimate patterns.
8747    #[serde(default = "default_true_val")]
8748    pub unusual_legitimate: bool,
8749
8750    /// Types of unusual legitimate patterns to generate.
8751    #[serde(default = "default_unusual_legitimate_types")]
8752    pub unusual_legitimate_types: Vec<String>,
8753
8754    /// Enable corrected error patterns.
8755    #[serde(default = "default_true_val")]
8756    pub corrected_errors: bool,
8757
8758    /// Corrected error correction lag range in days.
8759    #[serde(default)]
8760    pub corrected_error_lag: CorrectedErrorLagConfig,
8761}
8762
8763fn default_near_miss_proportion() -> f64 {
8764    0.30
8765}
8766
8767fn default_unusual_legitimate_types() -> Vec<String> {
8768    vec![
8769        "year_end_bonus".to_string(),
8770        "contract_prepayment".to_string(),
8771        "insurance_claim".to_string(),
8772        "settlement_payment".to_string(),
8773    ]
8774}
8775
8776impl Default for NearMissConfig {
8777    fn default() -> Self {
8778        Self {
8779            enabled: false,
8780            proportion: default_near_miss_proportion(),
8781            near_duplicate: true,
8782            near_duplicate_days: NearDuplicateDaysConfig::default(),
8783            threshold_proximity: true,
8784            threshold_proximity_range: ThresholdProximityRangeConfig::default(),
8785            unusual_legitimate: true,
8786            unusual_legitimate_types: default_unusual_legitimate_types(),
8787            corrected_errors: true,
8788            corrected_error_lag: CorrectedErrorLagConfig::default(),
8789        }
8790    }
8791}
8792
8793/// Near-duplicate days configuration.
8794#[derive(Debug, Clone, Serialize, Deserialize)]
8795pub struct NearDuplicateDaysConfig {
8796    /// Minimum days apart.
8797    #[serde(default = "default_near_duplicate_min")]
8798    pub min: u32,
8799
8800    /// Maximum days apart.
8801    #[serde(default = "default_near_duplicate_max")]
8802    pub max: u32,
8803}
8804
8805fn default_near_duplicate_min() -> u32 {
8806    1
8807}
8808fn default_near_duplicate_max() -> u32 {
8809    3
8810}
8811
8812impl Default for NearDuplicateDaysConfig {
8813    fn default() -> Self {
8814        Self {
8815            min: default_near_duplicate_min(),
8816            max: default_near_duplicate_max(),
8817        }
8818    }
8819}
8820
8821/// Threshold proximity range configuration.
8822#[derive(Debug, Clone, Serialize, Deserialize)]
8823pub struct ThresholdProximityRangeConfig {
8824    /// Minimum proximity (e.g., 0.90 = 90% of threshold).
8825    #[serde(default = "default_threshold_proximity_min")]
8826    pub min: f64,
8827
8828    /// Maximum proximity (e.g., 0.99 = 99% of threshold).
8829    #[serde(default = "default_threshold_proximity_max")]
8830    pub max: f64,
8831}
8832
8833fn default_threshold_proximity_min() -> f64 {
8834    0.90
8835}
8836fn default_threshold_proximity_max() -> f64 {
8837    0.99
8838}
8839
8840impl Default for ThresholdProximityRangeConfig {
8841    fn default() -> Self {
8842        Self {
8843            min: default_threshold_proximity_min(),
8844            max: default_threshold_proximity_max(),
8845        }
8846    }
8847}
8848
8849/// Corrected error lag configuration.
8850#[derive(Debug, Clone, Serialize, Deserialize)]
8851pub struct CorrectedErrorLagConfig {
8852    /// Minimum correction lag in days.
8853    #[serde(default = "default_corrected_error_lag_min")]
8854    pub min: u32,
8855
8856    /// Maximum correction lag in days.
8857    #[serde(default = "default_corrected_error_lag_max")]
8858    pub max: u32,
8859}
8860
8861fn default_corrected_error_lag_min() -> u32 {
8862    1
8863}
8864fn default_corrected_error_lag_max() -> u32 {
8865    5
8866}
8867
8868impl Default for CorrectedErrorLagConfig {
8869    fn default() -> Self {
8870        Self {
8871            min: default_corrected_error_lag_min(),
8872            max: default_corrected_error_lag_max(),
8873        }
8874    }
8875}
8876
8877/// Detection difficulty classification configuration.
8878#[derive(Debug, Clone, Serialize, Deserialize)]
8879pub struct DifficultyClassificationConfig {
8880    /// Enable detection difficulty classification.
8881    #[serde(default)]
8882    pub enabled: bool,
8883
8884    /// Target distribution of difficulty levels.
8885    #[serde(default)]
8886    pub target_distribution: DifficultyDistributionConfig,
8887}
8888
8889impl Default for DifficultyClassificationConfig {
8890    fn default() -> Self {
8891        Self {
8892            enabled: true,
8893            target_distribution: DifficultyDistributionConfig::default(),
8894        }
8895    }
8896}
8897
8898/// Target distribution of detection difficulty levels.
8899#[derive(Debug, Clone, Serialize, Deserialize)]
8900pub struct DifficultyDistributionConfig {
8901    /// Proportion of trivial anomalies (expected 99% detection).
8902    #[serde(default = "default_difficulty_trivial")]
8903    pub trivial: f64,
8904
8905    /// Proportion of easy anomalies (expected 90% detection).
8906    #[serde(default = "default_difficulty_easy")]
8907    pub easy: f64,
8908
8909    /// Proportion of moderate anomalies (expected 70% detection).
8910    #[serde(default = "default_difficulty_moderate")]
8911    pub moderate: f64,
8912
8913    /// Proportion of hard anomalies (expected 40% detection).
8914    #[serde(default = "default_difficulty_hard")]
8915    pub hard: f64,
8916
8917    /// Proportion of expert anomalies (expected 15% detection).
8918    #[serde(default = "default_difficulty_expert")]
8919    pub expert: f64,
8920}
8921
8922fn default_difficulty_trivial() -> f64 {
8923    0.15
8924}
8925fn default_difficulty_easy() -> f64 {
8926    0.25
8927}
8928fn default_difficulty_moderate() -> f64 {
8929    0.30
8930}
8931fn default_difficulty_hard() -> f64 {
8932    0.20
8933}
8934fn default_difficulty_expert() -> f64 {
8935    0.10
8936}
8937
8938impl Default for DifficultyDistributionConfig {
8939    fn default() -> Self {
8940        Self {
8941            trivial: default_difficulty_trivial(),
8942            easy: default_difficulty_easy(),
8943            moderate: default_difficulty_moderate(),
8944            hard: default_difficulty_hard(),
8945            expert: default_difficulty_expert(),
8946        }
8947    }
8948}
8949
8950/// Context-aware injection configuration.
8951#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8952pub struct ContextAwareConfig {
8953    /// Enable context-aware injection.
8954    #[serde(default)]
8955    pub enabled: bool,
8956
8957    /// Vendor-specific anomaly rules.
8958    #[serde(default)]
8959    pub vendor_rules: VendorAnomalyRulesConfig,
8960
8961    /// Employee-specific anomaly rules.
8962    #[serde(default)]
8963    pub employee_rules: EmployeeAnomalyRulesConfig,
8964
8965    /// Account-specific anomaly rules.
8966    #[serde(default)]
8967    pub account_rules: AccountAnomalyRulesConfig,
8968
8969    /// Behavioral baseline configuration.
8970    #[serde(default)]
8971    pub behavioral_baseline: BehavioralBaselineConfig,
8972}
8973
8974/// Vendor-specific anomaly rules configuration.
8975#[derive(Debug, Clone, Serialize, Deserialize)]
8976pub struct VendorAnomalyRulesConfig {
8977    /// Error rate multiplier for new vendors (< threshold days).
8978    #[serde(default = "default_new_vendor_multiplier")]
8979    pub new_vendor_error_multiplier: f64,
8980
8981    /// Days threshold for "new" vendor classification.
8982    #[serde(default = "default_new_vendor_threshold")]
8983    pub new_vendor_threshold_days: u32,
8984
8985    /// Error rate multiplier for international vendors.
8986    #[serde(default = "default_international_multiplier")]
8987    pub international_error_multiplier: f64,
8988
8989    /// Strategic vendor anomaly types (may differ from general vendors).
8990    #[serde(default = "default_strategic_vendor_types")]
8991    pub strategic_vendor_anomaly_types: Vec<String>,
8992}
8993
8994fn default_new_vendor_multiplier() -> f64 {
8995    2.5
8996}
8997fn default_new_vendor_threshold() -> u32 {
8998    90
8999}
9000fn default_international_multiplier() -> f64 {
9001    1.5
9002}
9003fn default_strategic_vendor_types() -> Vec<String> {
9004    vec![
9005        "pricing_dispute".to_string(),
9006        "contract_violation".to_string(),
9007    ]
9008}
9009
9010impl Default for VendorAnomalyRulesConfig {
9011    fn default() -> Self {
9012        Self {
9013            new_vendor_error_multiplier: default_new_vendor_multiplier(),
9014            new_vendor_threshold_days: default_new_vendor_threshold(),
9015            international_error_multiplier: default_international_multiplier(),
9016            strategic_vendor_anomaly_types: default_strategic_vendor_types(),
9017        }
9018    }
9019}
9020
9021/// Employee-specific anomaly rules configuration.
9022#[derive(Debug, Clone, Serialize, Deserialize)]
9023pub struct EmployeeAnomalyRulesConfig {
9024    /// Error rate for new employees (< threshold days).
9025    #[serde(default = "default_new_employee_rate")]
9026    pub new_employee_error_rate: f64,
9027
9028    /// Days threshold for "new" employee classification.
9029    #[serde(default = "default_new_employee_threshold")]
9030    pub new_employee_threshold_days: u32,
9031
9032    /// Transaction volume threshold for fatigue errors.
9033    #[serde(default = "default_volume_fatigue_threshold")]
9034    pub volume_fatigue_threshold: u32,
9035
9036    /// Error rate multiplier when primary approver is absent.
9037    #[serde(default = "default_coverage_multiplier")]
9038    pub coverage_error_multiplier: f64,
9039}
9040
9041fn default_new_employee_rate() -> f64 {
9042    0.05
9043}
9044fn default_new_employee_threshold() -> u32 {
9045    180
9046}
9047fn default_volume_fatigue_threshold() -> u32 {
9048    50
9049}
9050fn default_coverage_multiplier() -> f64 {
9051    1.8
9052}
9053
9054impl Default for EmployeeAnomalyRulesConfig {
9055    fn default() -> Self {
9056        Self {
9057            new_employee_error_rate: default_new_employee_rate(),
9058            new_employee_threshold_days: default_new_employee_threshold(),
9059            volume_fatigue_threshold: default_volume_fatigue_threshold(),
9060            coverage_error_multiplier: default_coverage_multiplier(),
9061        }
9062    }
9063}
9064
9065/// Account-specific anomaly rules configuration.
9066#[derive(Debug, Clone, Serialize, Deserialize)]
9067pub struct AccountAnomalyRulesConfig {
9068    /// Error rate multiplier for high-risk accounts.
9069    #[serde(default = "default_high_risk_multiplier")]
9070    pub high_risk_account_multiplier: f64,
9071
9072    /// Account codes considered high-risk.
9073    #[serde(default = "default_high_risk_accounts")]
9074    pub high_risk_accounts: Vec<String>,
9075
9076    /// Error rate multiplier for suspense accounts.
9077    #[serde(default = "default_suspense_multiplier")]
9078    pub suspense_account_multiplier: f64,
9079
9080    /// Account codes considered suspense accounts.
9081    #[serde(default = "default_suspense_accounts")]
9082    pub suspense_accounts: Vec<String>,
9083
9084    /// Error rate multiplier for intercompany accounts.
9085    #[serde(default = "default_intercompany_multiplier")]
9086    pub intercompany_account_multiplier: f64,
9087}
9088
9089fn default_high_risk_multiplier() -> f64 {
9090    2.0
9091}
9092fn default_high_risk_accounts() -> Vec<String> {
9093    vec![
9094        "1100".to_string(), // AR Control
9095        "2000".to_string(), // AP Control
9096        "3000".to_string(), // Cash
9097    ]
9098}
9099fn default_suspense_multiplier() -> f64 {
9100    3.0
9101}
9102fn default_suspense_accounts() -> Vec<String> {
9103    vec!["9999".to_string(), "9998".to_string()]
9104}
9105fn default_intercompany_multiplier() -> f64 {
9106    1.5
9107}
9108
9109impl Default for AccountAnomalyRulesConfig {
9110    fn default() -> Self {
9111        Self {
9112            high_risk_account_multiplier: default_high_risk_multiplier(),
9113            high_risk_accounts: default_high_risk_accounts(),
9114            suspense_account_multiplier: default_suspense_multiplier(),
9115            suspense_accounts: default_suspense_accounts(),
9116            intercompany_account_multiplier: default_intercompany_multiplier(),
9117        }
9118    }
9119}
9120
9121/// Behavioral baseline configuration.
9122#[derive(Debug, Clone, Serialize, Deserialize)]
9123pub struct BehavioralBaselineConfig {
9124    /// Enable behavioral baseline tracking.
9125    #[serde(default)]
9126    pub enabled: bool,
9127
9128    /// Number of days to build baseline from.
9129    #[serde(default = "default_baseline_period")]
9130    pub baseline_period_days: u32,
9131
9132    /// Standard deviation threshold for amount anomalies.
9133    #[serde(default = "default_deviation_threshold")]
9134    pub deviation_threshold_std: f64,
9135
9136    /// Standard deviation threshold for frequency anomalies.
9137    #[serde(default = "default_frequency_deviation")]
9138    pub frequency_deviation_threshold: f64,
9139}
9140
9141fn default_baseline_period() -> u32 {
9142    90
9143}
9144fn default_deviation_threshold() -> f64 {
9145    3.0
9146}
9147fn default_frequency_deviation() -> f64 {
9148    2.0
9149}
9150
9151impl Default for BehavioralBaselineConfig {
9152    fn default() -> Self {
9153        Self {
9154            enabled: false,
9155            baseline_period_days: default_baseline_period(),
9156            deviation_threshold_std: default_deviation_threshold(),
9157            frequency_deviation_threshold: default_frequency_deviation(),
9158        }
9159    }
9160}
9161
9162/// Enhanced labeling configuration.
9163#[derive(Debug, Clone, Serialize, Deserialize)]
9164pub struct EnhancedLabelingConfig {
9165    /// Enable severity scoring.
9166    #[serde(default = "default_true_val")]
9167    pub severity_scoring: bool,
9168
9169    /// Enable difficulty classification.
9170    #[serde(default = "default_true_val")]
9171    pub difficulty_classification: bool,
9172
9173    /// Materiality thresholds for severity classification.
9174    #[serde(default)]
9175    pub materiality_thresholds: MaterialityThresholdsConfig,
9176}
9177
9178impl Default for EnhancedLabelingConfig {
9179    fn default() -> Self {
9180        Self {
9181            severity_scoring: true,
9182            difficulty_classification: true,
9183            materiality_thresholds: MaterialityThresholdsConfig::default(),
9184        }
9185    }
9186}
9187
9188/// Materiality thresholds configuration.
9189#[derive(Debug, Clone, Serialize, Deserialize)]
9190pub struct MaterialityThresholdsConfig {
9191    /// Threshold for trivial impact (as percentage of total).
9192    #[serde(default = "default_materiality_trivial")]
9193    pub trivial: f64,
9194
9195    /// Threshold for immaterial impact.
9196    #[serde(default = "default_materiality_immaterial")]
9197    pub immaterial: f64,
9198
9199    /// Threshold for material impact.
9200    #[serde(default = "default_materiality_material")]
9201    pub material: f64,
9202
9203    /// Threshold for highly material impact.
9204    #[serde(default = "default_materiality_highly_material")]
9205    pub highly_material: f64,
9206}
9207
9208fn default_materiality_trivial() -> f64 {
9209    0.001
9210}
9211fn default_materiality_immaterial() -> f64 {
9212    0.01
9213}
9214fn default_materiality_material() -> f64 {
9215    0.05
9216}
9217fn default_materiality_highly_material() -> f64 {
9218    0.10
9219}
9220
9221impl Default for MaterialityThresholdsConfig {
9222    fn default() -> Self {
9223        Self {
9224            trivial: default_materiality_trivial(),
9225            immaterial: default_materiality_immaterial(),
9226            material: default_materiality_material(),
9227            highly_material: default_materiality_highly_material(),
9228        }
9229    }
9230}
9231
9232// =============================================================================
9233// Industry-Specific Configuration
9234// =============================================================================
9235
9236/// Industry-specific transaction and anomaly generation configuration.
9237///
9238/// This configuration enables generation of industry-authentic:
9239/// - Transaction types with appropriate terminology
9240/// - Master data (BOM, routings, clinical codes, etc.)
9241/// - Industry-specific anomaly patterns
9242/// - Regulatory framework compliance
9243#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9244pub struct IndustrySpecificConfig {
9245    /// Enable industry-specific generation.
9246    #[serde(default)]
9247    pub enabled: bool,
9248
9249    /// Manufacturing industry settings.
9250    #[serde(default)]
9251    pub manufacturing: ManufacturingConfig,
9252
9253    /// Retail industry settings.
9254    #[serde(default)]
9255    pub retail: RetailConfig,
9256
9257    /// Healthcare industry settings.
9258    #[serde(default)]
9259    pub healthcare: HealthcareConfig,
9260
9261    /// Technology industry settings.
9262    #[serde(default)]
9263    pub technology: TechnologyConfig,
9264
9265    /// Financial services industry settings.
9266    #[serde(default)]
9267    pub financial_services: FinancialServicesConfig,
9268
9269    /// Professional services industry settings.
9270    #[serde(default)]
9271    pub professional_services: ProfessionalServicesConfig,
9272}
9273
9274/// Manufacturing industry configuration.
9275#[derive(Debug, Clone, Serialize, Deserialize)]
9276pub struct ManufacturingConfig {
9277    /// Enable manufacturing-specific generation.
9278    #[serde(default)]
9279    pub enabled: bool,
9280
9281    /// Bill of Materials depth (typical: 3-7).
9282    #[serde(default = "default_bom_depth")]
9283    pub bom_depth: u32,
9284
9285    /// Whether to use just-in-time inventory.
9286    #[serde(default)]
9287    pub just_in_time: bool,
9288
9289    /// Production order types to generate.
9290    #[serde(default = "default_production_order_types")]
9291    pub production_order_types: Vec<String>,
9292
9293    /// Quality framework (ISO_9001, Six_Sigma, etc.).
9294    #[serde(default)]
9295    pub quality_framework: Option<String>,
9296
9297    /// Number of supplier tiers to model (1-3).
9298    #[serde(default = "default_supplier_tiers")]
9299    pub supplier_tiers: u32,
9300
9301    /// Standard cost update frequency.
9302    #[serde(default = "default_cost_frequency")]
9303    pub standard_cost_frequency: String,
9304
9305    /// Target yield rate (0.95-0.99 typical).
9306    #[serde(default = "default_yield_rate")]
9307    pub target_yield_rate: f64,
9308
9309    /// Scrap percentage threshold for alerts.
9310    #[serde(default = "default_scrap_threshold")]
9311    pub scrap_alert_threshold: f64,
9312
9313    /// Manufacturing anomaly injection rates.
9314    #[serde(default)]
9315    pub anomaly_rates: ManufacturingAnomalyRates,
9316
9317    /// Cost accounting configuration (WIP → FG → COGS pipeline).
9318    #[serde(default)]
9319    pub cost_accounting: ManufacturingCostAccountingConfig,
9320}
9321
9322/// Configuration for manufacturing cost accounting JE generation.
9323#[derive(Debug, Clone, Serialize, Deserialize)]
9324pub struct ManufacturingCostAccountingConfig {
9325    /// Enable multi-stage cost flow (WIP → FG → COGS) instead of flat JEs.
9326    #[serde(default = "default_true")]
9327    pub enabled: bool,
9328
9329    /// Generate standard cost variance JEs.
9330    #[serde(default = "default_true")]
9331    pub variance_accounts_enabled: bool,
9332
9333    /// Generate warranty provisions from quality inspection failures.
9334    #[serde(default = "default_true")]
9335    pub warranty_provisions_enabled: bool,
9336
9337    /// Minimum defect rate (0.0-1.0) to trigger warranty provision generation.
9338    #[serde(default = "default_warranty_defect_threshold")]
9339    pub warranty_defect_threshold: f64,
9340}
9341
9342fn default_warranty_defect_threshold() -> f64 {
9343    0.01
9344}
9345
9346impl Default for ManufacturingCostAccountingConfig {
9347    fn default() -> Self {
9348        Self {
9349            enabled: true,
9350            variance_accounts_enabled: true,
9351            warranty_provisions_enabled: true,
9352            warranty_defect_threshold: 0.01,
9353        }
9354    }
9355}
9356
9357fn default_bom_depth() -> u32 {
9358    4
9359}
9360
9361fn default_production_order_types() -> Vec<String> {
9362    vec![
9363        "standard".to_string(),
9364        "rework".to_string(),
9365        "prototype".to_string(),
9366    ]
9367}
9368
9369fn default_supplier_tiers() -> u32 {
9370    2
9371}
9372
9373fn default_cost_frequency() -> String {
9374    "quarterly".to_string()
9375}
9376
9377fn default_yield_rate() -> f64 {
9378    0.97
9379}
9380
9381fn default_scrap_threshold() -> f64 {
9382    0.03
9383}
9384
9385impl Default for ManufacturingConfig {
9386    fn default() -> Self {
9387        Self {
9388            enabled: false,
9389            bom_depth: default_bom_depth(),
9390            just_in_time: false,
9391            production_order_types: default_production_order_types(),
9392            quality_framework: Some("ISO_9001".to_string()),
9393            supplier_tiers: default_supplier_tiers(),
9394            standard_cost_frequency: default_cost_frequency(),
9395            target_yield_rate: default_yield_rate(),
9396            scrap_alert_threshold: default_scrap_threshold(),
9397            anomaly_rates: ManufacturingAnomalyRates::default(),
9398            cost_accounting: ManufacturingCostAccountingConfig::default(),
9399        }
9400    }
9401}
9402
9403/// Manufacturing anomaly injection rates.
9404#[derive(Debug, Clone, Serialize, Deserialize)]
9405pub struct ManufacturingAnomalyRates {
9406    /// Yield manipulation rate.
9407    #[serde(default = "default_mfg_yield_rate")]
9408    pub yield_manipulation: f64,
9409
9410    /// Labor misallocation rate.
9411    #[serde(default = "default_mfg_labor_rate")]
9412    pub labor_misallocation: f64,
9413
9414    /// Phantom production rate.
9415    #[serde(default = "default_mfg_phantom_rate")]
9416    pub phantom_production: f64,
9417
9418    /// Standard cost manipulation rate.
9419    #[serde(default = "default_mfg_cost_rate")]
9420    pub standard_cost_manipulation: f64,
9421
9422    /// Inventory fraud rate.
9423    #[serde(default = "default_mfg_inventory_rate")]
9424    pub inventory_fraud: f64,
9425}
9426
9427fn default_mfg_yield_rate() -> f64 {
9428    0.015
9429}
9430
9431fn default_mfg_labor_rate() -> f64 {
9432    0.02
9433}
9434
9435fn default_mfg_phantom_rate() -> f64 {
9436    0.005
9437}
9438
9439fn default_mfg_cost_rate() -> f64 {
9440    0.01
9441}
9442
9443fn default_mfg_inventory_rate() -> f64 {
9444    0.008
9445}
9446
9447impl Default for ManufacturingAnomalyRates {
9448    fn default() -> Self {
9449        Self {
9450            yield_manipulation: default_mfg_yield_rate(),
9451            labor_misallocation: default_mfg_labor_rate(),
9452            phantom_production: default_mfg_phantom_rate(),
9453            standard_cost_manipulation: default_mfg_cost_rate(),
9454            inventory_fraud: default_mfg_inventory_rate(),
9455        }
9456    }
9457}
9458
9459/// Retail industry configuration.
9460#[derive(Debug, Clone, Serialize, Deserialize)]
9461pub struct RetailConfig {
9462    /// Enable retail-specific generation.
9463    #[serde(default)]
9464    pub enabled: bool,
9465
9466    /// Store type distribution.
9467    #[serde(default)]
9468    pub store_types: RetailStoreTypeConfig,
9469
9470    /// Average daily transactions per store.
9471    #[serde(default = "default_retail_daily_txns")]
9472    pub avg_daily_transactions: u32,
9473
9474    /// Enable loss prevention tracking.
9475    #[serde(default = "default_true")]
9476    pub loss_prevention: bool,
9477
9478    /// Shrinkage rate (0.01-0.03 typical).
9479    #[serde(default = "default_shrinkage_rate")]
9480    pub shrinkage_rate: f64,
9481
9482    /// Retail anomaly injection rates.
9483    #[serde(default)]
9484    pub anomaly_rates: RetailAnomalyRates,
9485}
9486
9487fn default_retail_daily_txns() -> u32 {
9488    500
9489}
9490
9491fn default_shrinkage_rate() -> f64 {
9492    0.015
9493}
9494
9495impl Default for RetailConfig {
9496    fn default() -> Self {
9497        Self {
9498            enabled: false,
9499            store_types: RetailStoreTypeConfig::default(),
9500            avg_daily_transactions: default_retail_daily_txns(),
9501            loss_prevention: true,
9502            shrinkage_rate: default_shrinkage_rate(),
9503            anomaly_rates: RetailAnomalyRates::default(),
9504        }
9505    }
9506}
9507
9508/// Retail store type distribution.
9509#[derive(Debug, Clone, Serialize, Deserialize)]
9510pub struct RetailStoreTypeConfig {
9511    /// Percentage of flagship stores.
9512    #[serde(default = "default_flagship_pct")]
9513    pub flagship: f64,
9514
9515    /// Percentage of regional stores.
9516    #[serde(default = "default_regional_pct")]
9517    pub regional: f64,
9518
9519    /// Percentage of outlet stores.
9520    #[serde(default = "default_outlet_pct")]
9521    pub outlet: f64,
9522
9523    /// Percentage of e-commerce.
9524    #[serde(default = "default_ecommerce_pct")]
9525    pub ecommerce: f64,
9526}
9527
9528fn default_flagship_pct() -> f64 {
9529    0.10
9530}
9531
9532fn default_regional_pct() -> f64 {
9533    0.50
9534}
9535
9536fn default_outlet_pct() -> f64 {
9537    0.25
9538}
9539
9540fn default_ecommerce_pct() -> f64 {
9541    0.15
9542}
9543
9544impl Default for RetailStoreTypeConfig {
9545    fn default() -> Self {
9546        Self {
9547            flagship: default_flagship_pct(),
9548            regional: default_regional_pct(),
9549            outlet: default_outlet_pct(),
9550            ecommerce: default_ecommerce_pct(),
9551        }
9552    }
9553}
9554
9555/// Retail anomaly injection rates.
9556#[derive(Debug, Clone, Serialize, Deserialize)]
9557pub struct RetailAnomalyRates {
9558    /// Sweethearting rate.
9559    #[serde(default = "default_sweethearting_rate")]
9560    pub sweethearting: f64,
9561
9562    /// Skimming rate.
9563    #[serde(default = "default_skimming_rate")]
9564    pub skimming: f64,
9565
9566    /// Refund fraud rate.
9567    #[serde(default = "default_refund_fraud_rate")]
9568    pub refund_fraud: f64,
9569
9570    /// Void abuse rate.
9571    #[serde(default = "default_void_abuse_rate")]
9572    pub void_abuse: f64,
9573
9574    /// Gift card fraud rate.
9575    #[serde(default = "default_gift_card_rate")]
9576    pub gift_card_fraud: f64,
9577
9578    /// Vendor kickback rate.
9579    #[serde(default = "default_retail_kickback_rate")]
9580    pub vendor_kickback: f64,
9581}
9582
9583fn default_sweethearting_rate() -> f64 {
9584    0.02
9585}
9586
9587fn default_skimming_rate() -> f64 {
9588    0.005
9589}
9590
9591fn default_refund_fraud_rate() -> f64 {
9592    0.015
9593}
9594
9595fn default_void_abuse_rate() -> f64 {
9596    0.01
9597}
9598
9599fn default_gift_card_rate() -> f64 {
9600    0.008
9601}
9602
9603fn default_retail_kickback_rate() -> f64 {
9604    0.003
9605}
9606
9607impl Default for RetailAnomalyRates {
9608    fn default() -> Self {
9609        Self {
9610            sweethearting: default_sweethearting_rate(),
9611            skimming: default_skimming_rate(),
9612            refund_fraud: default_refund_fraud_rate(),
9613            void_abuse: default_void_abuse_rate(),
9614            gift_card_fraud: default_gift_card_rate(),
9615            vendor_kickback: default_retail_kickback_rate(),
9616        }
9617    }
9618}
9619
9620/// Healthcare industry configuration.
9621#[derive(Debug, Clone, Serialize, Deserialize)]
9622pub struct HealthcareConfig {
9623    /// Enable healthcare-specific generation.
9624    #[serde(default)]
9625    pub enabled: bool,
9626
9627    /// Healthcare facility type.
9628    #[serde(default = "default_facility_type")]
9629    pub facility_type: String,
9630
9631    /// Payer mix distribution.
9632    #[serde(default)]
9633    pub payer_mix: HealthcarePayerMix,
9634
9635    /// Coding systems enabled.
9636    #[serde(default)]
9637    pub coding_systems: HealthcareCodingSystems,
9638
9639    /// Healthcare compliance settings.
9640    #[serde(default)]
9641    pub compliance: HealthcareComplianceConfig,
9642
9643    /// Average daily encounters.
9644    #[serde(default = "default_daily_encounters")]
9645    pub avg_daily_encounters: u32,
9646
9647    /// Average charges per encounter.
9648    #[serde(default = "default_charges_per_encounter")]
9649    pub avg_charges_per_encounter: u32,
9650
9651    /// Denial rate (0.0-1.0).
9652    #[serde(default = "default_hc_denial_rate")]
9653    pub denial_rate: f64,
9654
9655    /// Bad debt rate (0.0-1.0).
9656    #[serde(default = "default_hc_bad_debt_rate")]
9657    pub bad_debt_rate: f64,
9658
9659    /// Charity care rate (0.0-1.0).
9660    #[serde(default = "default_hc_charity_care_rate")]
9661    pub charity_care_rate: f64,
9662
9663    /// Healthcare anomaly injection rates.
9664    #[serde(default)]
9665    pub anomaly_rates: HealthcareAnomalyRates,
9666}
9667
9668fn default_facility_type() -> String {
9669    "hospital".to_string()
9670}
9671
9672fn default_daily_encounters() -> u32 {
9673    150
9674}
9675
9676fn default_charges_per_encounter() -> u32 {
9677    8
9678}
9679
9680fn default_hc_denial_rate() -> f64 {
9681    0.05
9682}
9683
9684fn default_hc_bad_debt_rate() -> f64 {
9685    0.03
9686}
9687
9688fn default_hc_charity_care_rate() -> f64 {
9689    0.02
9690}
9691
9692impl Default for HealthcareConfig {
9693    fn default() -> Self {
9694        Self {
9695            enabled: false,
9696            facility_type: default_facility_type(),
9697            payer_mix: HealthcarePayerMix::default(),
9698            coding_systems: HealthcareCodingSystems::default(),
9699            compliance: HealthcareComplianceConfig::default(),
9700            avg_daily_encounters: default_daily_encounters(),
9701            avg_charges_per_encounter: default_charges_per_encounter(),
9702            denial_rate: default_hc_denial_rate(),
9703            bad_debt_rate: default_hc_bad_debt_rate(),
9704            charity_care_rate: default_hc_charity_care_rate(),
9705            anomaly_rates: HealthcareAnomalyRates::default(),
9706        }
9707    }
9708}
9709
9710/// Healthcare payer mix distribution.
9711#[derive(Debug, Clone, Serialize, Deserialize)]
9712pub struct HealthcarePayerMix {
9713    /// Medicare percentage.
9714    #[serde(default = "default_medicare_pct")]
9715    pub medicare: f64,
9716
9717    /// Medicaid percentage.
9718    #[serde(default = "default_medicaid_pct")]
9719    pub medicaid: f64,
9720
9721    /// Commercial insurance percentage.
9722    #[serde(default = "default_commercial_pct")]
9723    pub commercial: f64,
9724
9725    /// Self-pay percentage.
9726    #[serde(default = "default_self_pay_pct")]
9727    pub self_pay: f64,
9728}
9729
9730fn default_medicare_pct() -> f64 {
9731    0.40
9732}
9733
9734fn default_medicaid_pct() -> f64 {
9735    0.20
9736}
9737
9738fn default_commercial_pct() -> f64 {
9739    0.30
9740}
9741
9742fn default_self_pay_pct() -> f64 {
9743    0.10
9744}
9745
9746impl Default for HealthcarePayerMix {
9747    fn default() -> Self {
9748        Self {
9749            medicare: default_medicare_pct(),
9750            medicaid: default_medicaid_pct(),
9751            commercial: default_commercial_pct(),
9752            self_pay: default_self_pay_pct(),
9753        }
9754    }
9755}
9756
9757/// Healthcare coding systems configuration.
9758#[derive(Debug, Clone, Serialize, Deserialize)]
9759pub struct HealthcareCodingSystems {
9760    /// Enable ICD-10 diagnosis coding.
9761    #[serde(default = "default_true")]
9762    pub icd10: bool,
9763
9764    /// Enable CPT procedure coding.
9765    #[serde(default = "default_true")]
9766    pub cpt: bool,
9767
9768    /// Enable DRG grouping.
9769    #[serde(default = "default_true")]
9770    pub drg: bool,
9771
9772    /// Enable HCPCS Level II coding.
9773    #[serde(default = "default_true")]
9774    pub hcpcs: bool,
9775
9776    /// Enable revenue codes.
9777    #[serde(default = "default_true")]
9778    pub revenue_codes: bool,
9779}
9780
9781impl Default for HealthcareCodingSystems {
9782    fn default() -> Self {
9783        Self {
9784            icd10: true,
9785            cpt: true,
9786            drg: true,
9787            hcpcs: true,
9788            revenue_codes: true,
9789        }
9790    }
9791}
9792
9793/// Healthcare compliance configuration.
9794#[derive(Debug, Clone, Serialize, Deserialize)]
9795pub struct HealthcareComplianceConfig {
9796    /// Enable HIPAA compliance.
9797    #[serde(default = "default_true")]
9798    pub hipaa: bool,
9799
9800    /// Enable Stark Law compliance.
9801    #[serde(default = "default_true")]
9802    pub stark_law: bool,
9803
9804    /// Enable Anti-Kickback Statute compliance.
9805    #[serde(default = "default_true")]
9806    pub anti_kickback: bool,
9807
9808    /// Enable False Claims Act compliance.
9809    #[serde(default = "default_true")]
9810    pub false_claims_act: bool,
9811
9812    /// Enable EMTALA compliance (for hospitals).
9813    #[serde(default = "default_true")]
9814    pub emtala: bool,
9815}
9816
9817impl Default for HealthcareComplianceConfig {
9818    fn default() -> Self {
9819        Self {
9820            hipaa: true,
9821            stark_law: true,
9822            anti_kickback: true,
9823            false_claims_act: true,
9824            emtala: true,
9825        }
9826    }
9827}
9828
9829/// Healthcare anomaly injection rates.
9830#[derive(Debug, Clone, Serialize, Deserialize)]
9831pub struct HealthcareAnomalyRates {
9832    /// Upcoding rate.
9833    #[serde(default = "default_upcoding_rate")]
9834    pub upcoding: f64,
9835
9836    /// Unbundling rate.
9837    #[serde(default = "default_unbundling_rate")]
9838    pub unbundling: f64,
9839
9840    /// Phantom billing rate.
9841    #[serde(default = "default_phantom_billing_rate")]
9842    pub phantom_billing: f64,
9843
9844    /// Kickback rate.
9845    #[serde(default = "default_healthcare_kickback_rate")]
9846    pub kickbacks: f64,
9847
9848    /// Duplicate billing rate.
9849    #[serde(default = "default_duplicate_billing_rate")]
9850    pub duplicate_billing: f64,
9851
9852    /// Medical necessity abuse rate.
9853    #[serde(default = "default_med_necessity_rate")]
9854    pub medical_necessity_abuse: f64,
9855}
9856
9857fn default_upcoding_rate() -> f64 {
9858    0.02
9859}
9860
9861fn default_unbundling_rate() -> f64 {
9862    0.015
9863}
9864
9865fn default_phantom_billing_rate() -> f64 {
9866    0.005
9867}
9868
9869fn default_healthcare_kickback_rate() -> f64 {
9870    0.003
9871}
9872
9873fn default_duplicate_billing_rate() -> f64 {
9874    0.008
9875}
9876
9877fn default_med_necessity_rate() -> f64 {
9878    0.01
9879}
9880
9881impl Default for HealthcareAnomalyRates {
9882    fn default() -> Self {
9883        Self {
9884            upcoding: default_upcoding_rate(),
9885            unbundling: default_unbundling_rate(),
9886            phantom_billing: default_phantom_billing_rate(),
9887            kickbacks: default_healthcare_kickback_rate(),
9888            duplicate_billing: default_duplicate_billing_rate(),
9889            medical_necessity_abuse: default_med_necessity_rate(),
9890        }
9891    }
9892}
9893
9894/// Technology industry configuration.
9895#[derive(Debug, Clone, Serialize, Deserialize)]
9896pub struct TechnologyConfig {
9897    /// Enable technology-specific generation.
9898    #[serde(default)]
9899    pub enabled: bool,
9900
9901    /// Revenue model type.
9902    #[serde(default = "default_revenue_model")]
9903    pub revenue_model: String,
9904
9905    /// Subscription revenue percentage (for SaaS).
9906    #[serde(default = "default_subscription_pct")]
9907    pub subscription_revenue_pct: f64,
9908
9909    /// License revenue percentage.
9910    #[serde(default = "default_license_pct")]
9911    pub license_revenue_pct: f64,
9912
9913    /// Services revenue percentage.
9914    #[serde(default = "default_services_pct")]
9915    pub services_revenue_pct: f64,
9916
9917    /// R&D capitalization settings.
9918    #[serde(default)]
9919    pub rd_capitalization: RdCapitalizationConfig,
9920
9921    /// Technology anomaly injection rates.
9922    #[serde(default)]
9923    pub anomaly_rates: TechnologyAnomalyRates,
9924}
9925
9926fn default_revenue_model() -> String {
9927    "saas".to_string()
9928}
9929
9930fn default_subscription_pct() -> f64 {
9931    0.60
9932}
9933
9934fn default_license_pct() -> f64 {
9935    0.25
9936}
9937
9938fn default_services_pct() -> f64 {
9939    0.15
9940}
9941
9942impl Default for TechnologyConfig {
9943    fn default() -> Self {
9944        Self {
9945            enabled: false,
9946            revenue_model: default_revenue_model(),
9947            subscription_revenue_pct: default_subscription_pct(),
9948            license_revenue_pct: default_license_pct(),
9949            services_revenue_pct: default_services_pct(),
9950            rd_capitalization: RdCapitalizationConfig::default(),
9951            anomaly_rates: TechnologyAnomalyRates::default(),
9952        }
9953    }
9954}
9955
9956/// R&D capitalization configuration.
9957#[derive(Debug, Clone, Serialize, Deserialize)]
9958pub struct RdCapitalizationConfig {
9959    /// Enable R&D capitalization.
9960    #[serde(default = "default_true")]
9961    pub enabled: bool,
9962
9963    /// Capitalization rate (0.0-1.0).
9964    #[serde(default = "default_cap_rate")]
9965    pub capitalization_rate: f64,
9966
9967    /// Useful life in years.
9968    #[serde(default = "default_useful_life")]
9969    pub useful_life_years: u32,
9970}
9971
9972fn default_cap_rate() -> f64 {
9973    0.30
9974}
9975
9976fn default_useful_life() -> u32 {
9977    3
9978}
9979
9980impl Default for RdCapitalizationConfig {
9981    fn default() -> Self {
9982        Self {
9983            enabled: true,
9984            capitalization_rate: default_cap_rate(),
9985            useful_life_years: default_useful_life(),
9986        }
9987    }
9988}
9989
9990/// Technology anomaly injection rates.
9991#[derive(Debug, Clone, Serialize, Deserialize)]
9992pub struct TechnologyAnomalyRates {
9993    /// Premature revenue recognition rate.
9994    #[serde(default = "default_premature_rev_rate")]
9995    pub premature_revenue: f64,
9996
9997    /// Side letter abuse rate.
9998    #[serde(default = "default_side_letter_rate")]
9999    pub side_letter_abuse: f64,
10000
10001    /// Channel stuffing rate.
10002    #[serde(default = "default_channel_stuffing_rate")]
10003    pub channel_stuffing: f64,
10004
10005    /// Improper capitalization rate.
10006    #[serde(default = "default_improper_cap_rate")]
10007    pub improper_capitalization: f64,
10008}
10009
10010fn default_premature_rev_rate() -> f64 {
10011    0.015
10012}
10013
10014fn default_side_letter_rate() -> f64 {
10015    0.008
10016}
10017
10018fn default_channel_stuffing_rate() -> f64 {
10019    0.01
10020}
10021
10022fn default_improper_cap_rate() -> f64 {
10023    0.012
10024}
10025
10026impl Default for TechnologyAnomalyRates {
10027    fn default() -> Self {
10028        Self {
10029            premature_revenue: default_premature_rev_rate(),
10030            side_letter_abuse: default_side_letter_rate(),
10031            channel_stuffing: default_channel_stuffing_rate(),
10032            improper_capitalization: default_improper_cap_rate(),
10033        }
10034    }
10035}
10036
10037/// Financial services industry configuration.
10038#[derive(Debug, Clone, Serialize, Deserialize)]
10039pub struct FinancialServicesConfig {
10040    /// Enable financial services-specific generation.
10041    #[serde(default)]
10042    pub enabled: bool,
10043
10044    /// Financial institution type.
10045    #[serde(default = "default_fi_type")]
10046    pub institution_type: String,
10047
10048    /// Regulatory framework.
10049    #[serde(default = "default_fi_regulatory")]
10050    pub regulatory_framework: String,
10051
10052    /// Financial services anomaly injection rates.
10053    #[serde(default)]
10054    pub anomaly_rates: FinancialServicesAnomalyRates,
10055}
10056
10057fn default_fi_type() -> String {
10058    "commercial_bank".to_string()
10059}
10060
10061fn default_fi_regulatory() -> String {
10062    "us_banking".to_string()
10063}
10064
10065impl Default for FinancialServicesConfig {
10066    fn default() -> Self {
10067        Self {
10068            enabled: false,
10069            institution_type: default_fi_type(),
10070            regulatory_framework: default_fi_regulatory(),
10071            anomaly_rates: FinancialServicesAnomalyRates::default(),
10072        }
10073    }
10074}
10075
10076/// Financial services anomaly injection rates.
10077#[derive(Debug, Clone, Serialize, Deserialize)]
10078pub struct FinancialServicesAnomalyRates {
10079    /// Loan fraud rate.
10080    #[serde(default = "default_loan_fraud_rate")]
10081    pub loan_fraud: f64,
10082
10083    /// Trading fraud rate.
10084    #[serde(default = "default_trading_fraud_rate")]
10085    pub trading_fraud: f64,
10086
10087    /// Insurance fraud rate.
10088    #[serde(default = "default_insurance_fraud_rate")]
10089    pub insurance_fraud: f64,
10090
10091    /// Account manipulation rate.
10092    #[serde(default = "default_account_manip_rate")]
10093    pub account_manipulation: f64,
10094}
10095
10096fn default_loan_fraud_rate() -> f64 {
10097    0.01
10098}
10099
10100fn default_trading_fraud_rate() -> f64 {
10101    0.008
10102}
10103
10104fn default_insurance_fraud_rate() -> f64 {
10105    0.012
10106}
10107
10108fn default_account_manip_rate() -> f64 {
10109    0.005
10110}
10111
10112impl Default for FinancialServicesAnomalyRates {
10113    fn default() -> Self {
10114        Self {
10115            loan_fraud: default_loan_fraud_rate(),
10116            trading_fraud: default_trading_fraud_rate(),
10117            insurance_fraud: default_insurance_fraud_rate(),
10118            account_manipulation: default_account_manip_rate(),
10119        }
10120    }
10121}
10122
10123/// Professional services industry configuration.
10124#[derive(Debug, Clone, Serialize, Deserialize)]
10125pub struct ProfessionalServicesConfig {
10126    /// Enable professional services-specific generation.
10127    #[serde(default)]
10128    pub enabled: bool,
10129
10130    /// Firm type.
10131    #[serde(default = "default_firm_type")]
10132    pub firm_type: String,
10133
10134    /// Billing model.
10135    #[serde(default = "default_billing_model")]
10136    pub billing_model: String,
10137
10138    /// Average hourly rate.
10139    #[serde(default = "default_hourly_rate")]
10140    pub avg_hourly_rate: f64,
10141
10142    /// Trust account settings (for law firms).
10143    #[serde(default)]
10144    pub trust_accounting: TrustAccountingConfig,
10145
10146    /// Professional services anomaly injection rates.
10147    #[serde(default)]
10148    pub anomaly_rates: ProfessionalServicesAnomalyRates,
10149}
10150
10151fn default_firm_type() -> String {
10152    "consulting".to_string()
10153}
10154
10155fn default_billing_model() -> String {
10156    "time_and_materials".to_string()
10157}
10158
10159fn default_hourly_rate() -> f64 {
10160    250.0
10161}
10162
10163impl Default for ProfessionalServicesConfig {
10164    fn default() -> Self {
10165        Self {
10166            enabled: false,
10167            firm_type: default_firm_type(),
10168            billing_model: default_billing_model(),
10169            avg_hourly_rate: default_hourly_rate(),
10170            trust_accounting: TrustAccountingConfig::default(),
10171            anomaly_rates: ProfessionalServicesAnomalyRates::default(),
10172        }
10173    }
10174}
10175
10176/// Trust accounting configuration for law firms.
10177#[derive(Debug, Clone, Serialize, Deserialize)]
10178pub struct TrustAccountingConfig {
10179    /// Enable trust accounting.
10180    #[serde(default)]
10181    pub enabled: bool,
10182
10183    /// Require three-way reconciliation.
10184    #[serde(default = "default_true")]
10185    pub require_three_way_reconciliation: bool,
10186}
10187
10188impl Default for TrustAccountingConfig {
10189    fn default() -> Self {
10190        Self {
10191            enabled: false,
10192            require_three_way_reconciliation: true,
10193        }
10194    }
10195}
10196
10197/// Professional services anomaly injection rates.
10198#[derive(Debug, Clone, Serialize, Deserialize)]
10199pub struct ProfessionalServicesAnomalyRates {
10200    /// Time billing fraud rate.
10201    #[serde(default = "default_time_fraud_rate")]
10202    pub time_billing_fraud: f64,
10203
10204    /// Expense report fraud rate.
10205    #[serde(default = "default_expense_fraud_rate")]
10206    pub expense_fraud: f64,
10207
10208    /// Trust misappropriation rate.
10209    #[serde(default = "default_trust_misappropriation_rate")]
10210    pub trust_misappropriation: f64,
10211}
10212
10213fn default_time_fraud_rate() -> f64 {
10214    0.02
10215}
10216
10217fn default_expense_fraud_rate() -> f64 {
10218    0.015
10219}
10220
10221fn default_trust_misappropriation_rate() -> f64 {
10222    0.003
10223}
10224
10225impl Default for ProfessionalServicesAnomalyRates {
10226    fn default() -> Self {
10227        Self {
10228            time_billing_fraud: default_time_fraud_rate(),
10229            expense_fraud: default_expense_fraud_rate(),
10230            trust_misappropriation: default_trust_misappropriation_rate(),
10231        }
10232    }
10233}
10234
10235/// Fingerprint privacy configuration for extraction and synthesis.
10236///
10237/// Controls the privacy parameters used when extracting fingerprints
10238/// from sensitive data. Supports predefined levels or custom (epsilon, delta) tuples.
10239///
10240/// ```yaml
10241/// fingerprint_privacy:
10242///   level: custom
10243///   epsilon: 0.5
10244///   delta: 1.0e-5
10245///   k_anonymity: 10
10246///   composition_method: renyi_dp
10247/// ```
10248#[derive(Debug, Clone, Serialize, Deserialize)]
10249pub struct FingerprintPrivacyConfig {
10250    /// Privacy level preset. Use "custom" for user-specified epsilon/delta.
10251    #[serde(default)]
10252    pub level: String,
10253    /// Custom epsilon value (only used when level = "custom").
10254    #[serde(default = "default_epsilon")]
10255    pub epsilon: f64,
10256    /// Custom delta value for (epsilon, delta)-DP (only used with RDP/zCDP).
10257    #[serde(default = "default_delta")]
10258    pub delta: f64,
10259    /// K-anonymity threshold.
10260    #[serde(default = "default_k_anonymity")]
10261    pub k_anonymity: u32,
10262    /// Composition method: "naive", "advanced", "renyi_dp", "zcdp".
10263    #[serde(default)]
10264    pub composition_method: String,
10265}
10266
10267fn default_epsilon() -> f64 {
10268    1.0
10269}
10270
10271fn default_delta() -> f64 {
10272    1e-5
10273}
10274
10275fn default_k_anonymity() -> u32 {
10276    5
10277}
10278
10279impl Default for FingerprintPrivacyConfig {
10280    fn default() -> Self {
10281        Self {
10282            level: "standard".to_string(),
10283            epsilon: default_epsilon(),
10284            delta: default_delta(),
10285            k_anonymity: default_k_anonymity(),
10286            composition_method: "naive".to_string(),
10287        }
10288    }
10289}
10290
10291/// Quality gates configuration for pass/fail thresholds on generation runs.
10292///
10293/// ```yaml
10294/// quality_gates:
10295///   enabled: true
10296///   profile: strict  # strict, default, lenient, custom
10297///   fail_on_violation: true
10298///   custom_gates:
10299///     - name: benford_compliance
10300///       metric: benford_mad
10301///       threshold: 0.015
10302///       comparison: lte
10303/// ```
10304#[derive(Debug, Clone, Serialize, Deserialize)]
10305pub struct QualityGatesSchemaConfig {
10306    /// Enable quality gate evaluation.
10307    #[serde(default)]
10308    pub enabled: bool,
10309    /// Gate profile: "strict", "default", "lenient", or "custom".
10310    #[serde(default = "default_gate_profile_name")]
10311    pub profile: String,
10312    /// Whether to fail the generation on gate violations.
10313    #[serde(default)]
10314    pub fail_on_violation: bool,
10315    /// Custom gate definitions (used when profile = "custom").
10316    #[serde(default)]
10317    pub custom_gates: Vec<QualityGateEntry>,
10318}
10319
10320fn default_gate_profile_name() -> String {
10321    "default".to_string()
10322}
10323
10324impl Default for QualityGatesSchemaConfig {
10325    fn default() -> Self {
10326        Self {
10327            enabled: false,
10328            profile: default_gate_profile_name(),
10329            fail_on_violation: false,
10330            custom_gates: Vec::new(),
10331        }
10332    }
10333}
10334
10335/// A single quality gate entry in configuration.
10336#[derive(Debug, Clone, Serialize, Deserialize)]
10337pub struct QualityGateEntry {
10338    /// Gate name.
10339    pub name: String,
10340    /// Metric to check: benford_mad, balance_coherence, document_chain_integrity,
10341    /// correlation_preservation, temporal_consistency, privacy_mia_auc,
10342    /// completion_rate, duplicate_rate, referential_integrity, ic_match_rate.
10343    pub metric: String,
10344    /// Threshold value.
10345    pub threshold: f64,
10346    /// Upper threshold for "between" comparison.
10347    #[serde(default)]
10348    pub upper_threshold: Option<f64>,
10349    /// Comparison operator: "gte", "lte", "eq", "between".
10350    #[serde(default = "default_gate_comparison")]
10351    pub comparison: String,
10352}
10353
10354fn default_gate_comparison() -> String {
10355    "gte".to_string()
10356}
10357
10358/// Compliance configuration for regulatory requirements.
10359///
10360/// ```yaml
10361/// compliance:
10362///   content_marking:
10363///     enabled: true
10364///     format: embedded  # embedded, sidecar, both
10365///   article10_report: true
10366/// ```
10367#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10368pub struct ComplianceSchemaConfig {
10369    /// Synthetic content marking configuration (EU AI Act Article 50).
10370    #[serde(default)]
10371    pub content_marking: ContentMarkingSchemaConfig,
10372    /// Generate Article 10 data governance report.
10373    #[serde(default)]
10374    pub article10_report: bool,
10375    /// Certificate configuration for proving DP guarantees.
10376    #[serde(default)]
10377    pub certificates: CertificateSchemaConfig,
10378}
10379
10380/// Configuration for synthetic data certificates.
10381#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10382pub struct CertificateSchemaConfig {
10383    /// Whether certificate generation is enabled.
10384    #[serde(default)]
10385    pub enabled: bool,
10386    /// Environment variable name for the signing key.
10387    #[serde(default)]
10388    pub signing_key_env: Option<String>,
10389    /// Whether to include quality metrics in the certificate.
10390    #[serde(default)]
10391    pub include_quality_metrics: bool,
10392}
10393
10394/// Content marking configuration for synthetic data output.
10395#[derive(Debug, Clone, Serialize, Deserialize)]
10396pub struct ContentMarkingSchemaConfig {
10397    /// Whether content marking is enabled.
10398    #[serde(default = "default_true")]
10399    pub enabled: bool,
10400    /// Marking format: "embedded", "sidecar", or "both".
10401    #[serde(default = "default_marking_format")]
10402    pub format: String,
10403}
10404
10405fn default_marking_format() -> String {
10406    "embedded".to_string()
10407}
10408
10409impl Default for ContentMarkingSchemaConfig {
10410    fn default() -> Self {
10411        Self {
10412            enabled: true,
10413            format: default_marking_format(),
10414        }
10415    }
10416}
10417
10418/// Webhook notification configuration.
10419#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10420pub struct WebhookSchemaConfig {
10421    /// Whether webhooks are enabled.
10422    #[serde(default)]
10423    pub enabled: bool,
10424    /// Webhook endpoint configurations.
10425    #[serde(default)]
10426    pub endpoints: Vec<WebhookEndpointConfig>,
10427}
10428
10429/// Configuration for a single webhook endpoint.
10430#[derive(Debug, Clone, Serialize, Deserialize)]
10431pub struct WebhookEndpointConfig {
10432    /// Target URL for the webhook.
10433    pub url: String,
10434    /// Event types this endpoint subscribes to.
10435    #[serde(default)]
10436    pub events: Vec<String>,
10437    /// Optional secret for HMAC-SHA256 signature.
10438    #[serde(default)]
10439    pub secret: Option<String>,
10440    /// Maximum retry attempts (default: 3).
10441    #[serde(default = "default_webhook_retries")]
10442    pub max_retries: u32,
10443    /// Timeout in seconds (default: 10).
10444    #[serde(default = "default_webhook_timeout")]
10445    pub timeout_secs: u64,
10446}
10447
10448fn default_webhook_retries() -> u32 {
10449    3
10450}
10451fn default_webhook_timeout() -> u64 {
10452    10
10453}
10454
10455// ===== Enterprise Process Chain Config Structs =====
10456
10457// ----- Source-to-Pay (S2C/S2P) -----
10458
10459/// Source-to-Pay configuration covering the entire sourcing lifecycle.
10460#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10461pub struct SourceToPayConfig {
10462    /// Enable source-to-pay generation
10463    #[serde(default)]
10464    pub enabled: bool,
10465    /// Spend analysis configuration
10466    #[serde(default)]
10467    pub spend_analysis: SpendAnalysisConfig,
10468    /// Sourcing project configuration
10469    #[serde(default)]
10470    pub sourcing: SourcingConfig,
10471    /// Supplier qualification configuration
10472    #[serde(default)]
10473    pub qualification: QualificationConfig,
10474    /// RFx event configuration
10475    #[serde(default)]
10476    pub rfx: RfxConfig,
10477    /// Contract configuration
10478    #[serde(default)]
10479    pub contracts: ContractConfig,
10480    /// Catalog configuration
10481    #[serde(default)]
10482    pub catalog: CatalogConfig,
10483    /// Scorecard configuration
10484    #[serde(default)]
10485    pub scorecards: ScorecardConfig,
10486    /// P2P integration settings
10487    #[serde(default)]
10488    pub p2p_integration: P2PIntegrationConfig,
10489}
10490
10491/// Spend analysis configuration.
10492#[derive(Debug, Clone, Serialize, Deserialize)]
10493pub struct SpendAnalysisConfig {
10494    /// HHI threshold for triggering sourcing project
10495    #[serde(default = "default_hhi_threshold")]
10496    pub hhi_threshold: f64,
10497    /// Target spend coverage under contracts
10498    #[serde(default = "default_contract_coverage_target")]
10499    pub contract_coverage_target: f64,
10500}
10501
10502impl Default for SpendAnalysisConfig {
10503    fn default() -> Self {
10504        Self {
10505            hhi_threshold: default_hhi_threshold(),
10506            contract_coverage_target: default_contract_coverage_target(),
10507        }
10508    }
10509}
10510
10511fn default_hhi_threshold() -> f64 {
10512    2500.0
10513}
10514fn default_contract_coverage_target() -> f64 {
10515    0.80
10516}
10517
10518/// Sourcing project configuration.
10519#[derive(Debug, Clone, Serialize, Deserialize)]
10520pub struct SourcingConfig {
10521    /// Number of sourcing projects per year
10522    #[serde(default = "default_sourcing_projects_per_year")]
10523    pub projects_per_year: u32,
10524    /// Months before expiry to trigger renewal project
10525    #[serde(default = "default_renewal_horizon_months")]
10526    pub renewal_horizon_months: u32,
10527    /// Average project duration in months
10528    #[serde(default = "default_project_duration_months")]
10529    pub project_duration_months: u32,
10530}
10531
10532impl Default for SourcingConfig {
10533    fn default() -> Self {
10534        Self {
10535            projects_per_year: default_sourcing_projects_per_year(),
10536            renewal_horizon_months: default_renewal_horizon_months(),
10537            project_duration_months: default_project_duration_months(),
10538        }
10539    }
10540}
10541
10542fn default_sourcing_projects_per_year() -> u32 {
10543    10
10544}
10545fn default_renewal_horizon_months() -> u32 {
10546    3
10547}
10548fn default_project_duration_months() -> u32 {
10549    4
10550}
10551
10552/// Supplier qualification configuration.
10553#[derive(Debug, Clone, Serialize, Deserialize)]
10554pub struct QualificationConfig {
10555    /// Pass rate for qualification
10556    #[serde(default = "default_qualification_pass_rate")]
10557    pub pass_rate: f64,
10558    /// Qualification validity in days
10559    #[serde(default = "default_qualification_validity_days")]
10560    pub validity_days: u32,
10561    /// Financial stability weight
10562    #[serde(default = "default_financial_weight")]
10563    pub financial_weight: f64,
10564    /// Quality management weight
10565    #[serde(default = "default_quality_weight")]
10566    pub quality_weight: f64,
10567    /// Delivery performance weight
10568    #[serde(default = "default_delivery_weight")]
10569    pub delivery_weight: f64,
10570    /// Compliance weight
10571    #[serde(default = "default_compliance_weight")]
10572    pub compliance_weight: f64,
10573}
10574
10575impl Default for QualificationConfig {
10576    fn default() -> Self {
10577        Self {
10578            pass_rate: default_qualification_pass_rate(),
10579            validity_days: default_qualification_validity_days(),
10580            financial_weight: default_financial_weight(),
10581            quality_weight: default_quality_weight(),
10582            delivery_weight: default_delivery_weight(),
10583            compliance_weight: default_compliance_weight(),
10584        }
10585    }
10586}
10587
10588fn default_qualification_pass_rate() -> f64 {
10589    0.75
10590}
10591fn default_qualification_validity_days() -> u32 {
10592    365
10593}
10594fn default_financial_weight() -> f64 {
10595    0.25
10596}
10597fn default_quality_weight() -> f64 {
10598    0.30
10599}
10600fn default_delivery_weight() -> f64 {
10601    0.25
10602}
10603fn default_compliance_weight() -> f64 {
10604    0.20
10605}
10606
10607/// RFx event configuration.
10608#[derive(Debug, Clone, Serialize, Deserialize)]
10609pub struct RfxConfig {
10610    /// Spend threshold above which RFI is required before RFP
10611    #[serde(default = "default_rfi_threshold")]
10612    pub rfi_threshold: f64,
10613    /// Minimum vendors invited per RFx
10614    #[serde(default = "default_min_invited_vendors")]
10615    pub min_invited_vendors: u32,
10616    /// Maximum vendors invited per RFx
10617    #[serde(default = "default_max_invited_vendors")]
10618    pub max_invited_vendors: u32,
10619    /// Response rate (% of invited vendors that submit bids)
10620    #[serde(default = "default_response_rate")]
10621    pub response_rate: f64,
10622    /// Default price weight in evaluation
10623    #[serde(default = "default_price_weight")]
10624    pub default_price_weight: f64,
10625    /// Default quality weight in evaluation
10626    #[serde(default = "default_rfx_quality_weight")]
10627    pub default_quality_weight: f64,
10628    /// Default delivery weight in evaluation
10629    #[serde(default = "default_rfx_delivery_weight")]
10630    pub default_delivery_weight: f64,
10631}
10632
10633impl Default for RfxConfig {
10634    fn default() -> Self {
10635        Self {
10636            rfi_threshold: default_rfi_threshold(),
10637            min_invited_vendors: default_min_invited_vendors(),
10638            max_invited_vendors: default_max_invited_vendors(),
10639            response_rate: default_response_rate(),
10640            default_price_weight: default_price_weight(),
10641            default_quality_weight: default_rfx_quality_weight(),
10642            default_delivery_weight: default_rfx_delivery_weight(),
10643        }
10644    }
10645}
10646
10647fn default_rfi_threshold() -> f64 {
10648    100_000.0
10649}
10650fn default_min_invited_vendors() -> u32 {
10651    3
10652}
10653fn default_max_invited_vendors() -> u32 {
10654    8
10655}
10656fn default_response_rate() -> f64 {
10657    0.70
10658}
10659fn default_price_weight() -> f64 {
10660    0.40
10661}
10662fn default_rfx_quality_weight() -> f64 {
10663    0.35
10664}
10665fn default_rfx_delivery_weight() -> f64 {
10666    0.25
10667}
10668
10669/// Contract configuration.
10670#[derive(Debug, Clone, Serialize, Deserialize)]
10671pub struct ContractConfig {
10672    /// Minimum contract duration in months
10673    #[serde(default = "default_min_contract_months")]
10674    pub min_duration_months: u32,
10675    /// Maximum contract duration in months
10676    #[serde(default = "default_max_contract_months")]
10677    pub max_duration_months: u32,
10678    /// Auto-renewal rate
10679    #[serde(default = "default_auto_renewal_rate")]
10680    pub auto_renewal_rate: f64,
10681    /// Amendment rate (% of contracts with at least one amendment)
10682    #[serde(default = "default_amendment_rate")]
10683    pub amendment_rate: f64,
10684    /// Distribution of contract types
10685    #[serde(default)]
10686    pub type_distribution: ContractTypeDistribution,
10687}
10688
10689impl Default for ContractConfig {
10690    fn default() -> Self {
10691        Self {
10692            min_duration_months: default_min_contract_months(),
10693            max_duration_months: default_max_contract_months(),
10694            auto_renewal_rate: default_auto_renewal_rate(),
10695            amendment_rate: default_amendment_rate(),
10696            type_distribution: ContractTypeDistribution::default(),
10697        }
10698    }
10699}
10700
10701fn default_min_contract_months() -> u32 {
10702    12
10703}
10704fn default_max_contract_months() -> u32 {
10705    36
10706}
10707fn default_auto_renewal_rate() -> f64 {
10708    0.40
10709}
10710fn default_amendment_rate() -> f64 {
10711    0.20
10712}
10713
10714/// Distribution of contract types.
10715#[derive(Debug, Clone, Serialize, Deserialize)]
10716pub struct ContractTypeDistribution {
10717    /// Fixed price percentage
10718    #[serde(default = "default_fixed_price_pct")]
10719    pub fixed_price: f64,
10720    /// Blanket/framework percentage
10721    #[serde(default = "default_blanket_pct")]
10722    pub blanket: f64,
10723    /// Time and materials percentage
10724    #[serde(default = "default_time_materials_pct")]
10725    pub time_and_materials: f64,
10726    /// Service agreement percentage
10727    #[serde(default = "default_service_agreement_pct")]
10728    pub service_agreement: f64,
10729}
10730
10731impl Default for ContractTypeDistribution {
10732    fn default() -> Self {
10733        Self {
10734            fixed_price: default_fixed_price_pct(),
10735            blanket: default_blanket_pct(),
10736            time_and_materials: default_time_materials_pct(),
10737            service_agreement: default_service_agreement_pct(),
10738        }
10739    }
10740}
10741
10742fn default_fixed_price_pct() -> f64 {
10743    0.40
10744}
10745fn default_blanket_pct() -> f64 {
10746    0.30
10747}
10748fn default_time_materials_pct() -> f64 {
10749    0.15
10750}
10751fn default_service_agreement_pct() -> f64 {
10752    0.15
10753}
10754
10755/// Catalog configuration.
10756#[derive(Debug, Clone, Serialize, Deserialize)]
10757pub struct CatalogConfig {
10758    /// Percentage of catalog items marked as preferred
10759    #[serde(default = "default_preferred_vendor_flag_rate")]
10760    pub preferred_vendor_flag_rate: f64,
10761    /// Rate of materials with multiple sources in catalog
10762    #[serde(default = "default_multi_source_rate")]
10763    pub multi_source_rate: f64,
10764}
10765
10766impl Default for CatalogConfig {
10767    fn default() -> Self {
10768        Self {
10769            preferred_vendor_flag_rate: default_preferred_vendor_flag_rate(),
10770            multi_source_rate: default_multi_source_rate(),
10771        }
10772    }
10773}
10774
10775fn default_preferred_vendor_flag_rate() -> f64 {
10776    0.70
10777}
10778fn default_multi_source_rate() -> f64 {
10779    0.25
10780}
10781
10782/// Scorecard configuration.
10783#[derive(Debug, Clone, Serialize, Deserialize)]
10784pub struct ScorecardConfig {
10785    /// Scorecard review frequency (quarterly, monthly)
10786    #[serde(default = "default_scorecard_frequency")]
10787    pub frequency: String,
10788    /// On-time delivery weight in overall score
10789    #[serde(default = "default_otd_weight")]
10790    pub on_time_delivery_weight: f64,
10791    /// Quality weight in overall score
10792    #[serde(default = "default_quality_score_weight")]
10793    pub quality_weight: f64,
10794    /// Price competitiveness weight
10795    #[serde(default = "default_price_score_weight")]
10796    pub price_weight: f64,
10797    /// Responsiveness weight
10798    #[serde(default = "default_responsiveness_weight")]
10799    pub responsiveness_weight: f64,
10800    /// Grade A threshold (score >= this)
10801    #[serde(default = "default_grade_a_threshold")]
10802    pub grade_a_threshold: f64,
10803    /// Grade B threshold
10804    #[serde(default = "default_grade_b_threshold")]
10805    pub grade_b_threshold: f64,
10806    /// Grade C threshold
10807    #[serde(default = "default_grade_c_threshold")]
10808    pub grade_c_threshold: f64,
10809}
10810
10811impl Default for ScorecardConfig {
10812    fn default() -> Self {
10813        Self {
10814            frequency: default_scorecard_frequency(),
10815            on_time_delivery_weight: default_otd_weight(),
10816            quality_weight: default_quality_score_weight(),
10817            price_weight: default_price_score_weight(),
10818            responsiveness_weight: default_responsiveness_weight(),
10819            grade_a_threshold: default_grade_a_threshold(),
10820            grade_b_threshold: default_grade_b_threshold(),
10821            grade_c_threshold: default_grade_c_threshold(),
10822        }
10823    }
10824}
10825
10826fn default_scorecard_frequency() -> String {
10827    "quarterly".to_string()
10828}
10829fn default_otd_weight() -> f64 {
10830    0.30
10831}
10832fn default_quality_score_weight() -> f64 {
10833    0.30
10834}
10835fn default_price_score_weight() -> f64 {
10836    0.25
10837}
10838fn default_responsiveness_weight() -> f64 {
10839    0.15
10840}
10841fn default_grade_a_threshold() -> f64 {
10842    90.0
10843}
10844fn default_grade_b_threshold() -> f64 {
10845    75.0
10846}
10847fn default_grade_c_threshold() -> f64 {
10848    60.0
10849}
10850
10851/// P2P integration settings for contract enforcement.
10852#[derive(Debug, Clone, Serialize, Deserialize)]
10853pub struct P2PIntegrationConfig {
10854    /// Rate of off-contract (maverick) purchases
10855    #[serde(default = "default_off_contract_rate")]
10856    pub off_contract_rate: f64,
10857    /// Price tolerance for contract price validation
10858    #[serde(default = "default_price_tolerance")]
10859    pub price_tolerance: f64,
10860    /// Whether to enforce catalog ordering
10861    #[serde(default)]
10862    pub catalog_enforcement: bool,
10863}
10864
10865impl Default for P2PIntegrationConfig {
10866    fn default() -> Self {
10867        Self {
10868            off_contract_rate: default_off_contract_rate(),
10869            price_tolerance: default_price_tolerance(),
10870            catalog_enforcement: false,
10871        }
10872    }
10873}
10874
10875fn default_off_contract_rate() -> f64 {
10876    0.15
10877}
10878fn default_price_tolerance() -> f64 {
10879    0.02
10880}
10881
10882// ----- Financial Reporting -----
10883
10884/// Financial reporting configuration.
10885#[derive(Debug, Clone, Serialize, Deserialize)]
10886pub struct FinancialReportingConfig {
10887    /// Enable financial reporting generation
10888    #[serde(default)]
10889    pub enabled: bool,
10890    /// Generate balance sheet
10891    #[serde(default = "default_true")]
10892    pub generate_balance_sheet: bool,
10893    /// Generate income statement
10894    #[serde(default = "default_true")]
10895    pub generate_income_statement: bool,
10896    /// Generate cash flow statement
10897    #[serde(default = "default_true")]
10898    pub generate_cash_flow: bool,
10899    /// Generate changes in equity statement
10900    #[serde(default = "default_true")]
10901    pub generate_changes_in_equity: bool,
10902    /// Number of comparative periods
10903    #[serde(default = "default_comparative_periods")]
10904    pub comparative_periods: u32,
10905    /// Management KPIs configuration
10906    #[serde(default)]
10907    pub management_kpis: ManagementKpisConfig,
10908    /// Budget configuration
10909    #[serde(default)]
10910    pub budgets: BudgetConfig,
10911}
10912
10913impl Default for FinancialReportingConfig {
10914    fn default() -> Self {
10915        Self {
10916            enabled: false,
10917            generate_balance_sheet: true,
10918            generate_income_statement: true,
10919            generate_cash_flow: true,
10920            generate_changes_in_equity: true,
10921            comparative_periods: default_comparative_periods(),
10922            management_kpis: ManagementKpisConfig::default(),
10923            budgets: BudgetConfig::default(),
10924        }
10925    }
10926}
10927
10928fn default_comparative_periods() -> u32 {
10929    1
10930}
10931
10932/// Management KPIs configuration.
10933#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10934pub struct ManagementKpisConfig {
10935    /// Enable KPI generation
10936    #[serde(default)]
10937    pub enabled: bool,
10938    /// KPI calculation frequency (monthly, quarterly)
10939    #[serde(default = "default_kpi_frequency")]
10940    pub frequency: String,
10941}
10942
10943fn default_kpi_frequency() -> String {
10944    "monthly".to_string()
10945}
10946
10947/// Budget configuration.
10948#[derive(Debug, Clone, Serialize, Deserialize)]
10949pub struct BudgetConfig {
10950    /// Enable budget generation
10951    #[serde(default)]
10952    pub enabled: bool,
10953    /// Expected revenue growth rate for budgeting
10954    #[serde(default = "default_revenue_growth_rate")]
10955    pub revenue_growth_rate: f64,
10956    /// Expected expense inflation rate
10957    #[serde(default = "default_expense_inflation_rate")]
10958    pub expense_inflation_rate: f64,
10959    /// Random noise to add to budget vs actual
10960    #[serde(default = "default_variance_noise")]
10961    pub variance_noise: f64,
10962}
10963
10964impl Default for BudgetConfig {
10965    fn default() -> Self {
10966        Self {
10967            enabled: false,
10968            revenue_growth_rate: default_revenue_growth_rate(),
10969            expense_inflation_rate: default_expense_inflation_rate(),
10970            variance_noise: default_variance_noise(),
10971        }
10972    }
10973}
10974
10975fn default_revenue_growth_rate() -> f64 {
10976    0.05
10977}
10978fn default_expense_inflation_rate() -> f64 {
10979    0.03
10980}
10981fn default_variance_noise() -> f64 {
10982    0.10
10983}
10984
10985// ----- HR Configuration -----
10986
10987/// HR (Hire-to-Retire) process configuration.
10988#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10989pub struct HrConfig {
10990    /// Enable HR generation
10991    #[serde(default)]
10992    pub enabled: bool,
10993    /// Payroll configuration
10994    #[serde(default)]
10995    pub payroll: PayrollConfig,
10996    /// Time and attendance configuration
10997    #[serde(default)]
10998    pub time_attendance: TimeAttendanceConfig,
10999    /// Expense management configuration
11000    #[serde(default)]
11001    pub expenses: ExpenseConfig,
11002}
11003
11004/// Payroll configuration.
11005#[derive(Debug, Clone, Serialize, Deserialize)]
11006pub struct PayrollConfig {
11007    /// Enable payroll generation
11008    #[serde(default = "default_true")]
11009    pub enabled: bool,
11010    /// Pay frequency (monthly, biweekly, weekly)
11011    #[serde(default = "default_pay_frequency")]
11012    pub pay_frequency: String,
11013    /// Salary ranges by job level
11014    #[serde(default)]
11015    pub salary_ranges: PayrollSalaryRanges,
11016    /// Effective tax rates
11017    #[serde(default)]
11018    pub tax_rates: PayrollTaxRates,
11019    /// Benefits enrollment rate
11020    #[serde(default = "default_benefits_enrollment_rate")]
11021    pub benefits_enrollment_rate: f64,
11022    /// Retirement plan participation rate
11023    #[serde(default = "default_retirement_participation_rate")]
11024    pub retirement_participation_rate: f64,
11025}
11026
11027impl Default for PayrollConfig {
11028    fn default() -> Self {
11029        Self {
11030            enabled: true,
11031            pay_frequency: default_pay_frequency(),
11032            salary_ranges: PayrollSalaryRanges::default(),
11033            tax_rates: PayrollTaxRates::default(),
11034            benefits_enrollment_rate: default_benefits_enrollment_rate(),
11035            retirement_participation_rate: default_retirement_participation_rate(),
11036        }
11037    }
11038}
11039
11040fn default_pay_frequency() -> String {
11041    "monthly".to_string()
11042}
11043fn default_benefits_enrollment_rate() -> f64 {
11044    0.60
11045}
11046fn default_retirement_participation_rate() -> f64 {
11047    0.45
11048}
11049
11050/// Salary ranges by job level.
11051#[derive(Debug, Clone, Serialize, Deserialize)]
11052pub struct PayrollSalaryRanges {
11053    /// Staff level min/max
11054    #[serde(default = "default_staff_min")]
11055    pub staff_min: f64,
11056    #[serde(default = "default_staff_max")]
11057    pub staff_max: f64,
11058    /// Manager level min/max
11059    #[serde(default = "default_manager_min")]
11060    pub manager_min: f64,
11061    #[serde(default = "default_manager_max")]
11062    pub manager_max: f64,
11063    /// Director level min/max
11064    #[serde(default = "default_director_min")]
11065    pub director_min: f64,
11066    #[serde(default = "default_director_max")]
11067    pub director_max: f64,
11068    /// Executive level min/max
11069    #[serde(default = "default_executive_min")]
11070    pub executive_min: f64,
11071    #[serde(default = "default_executive_max")]
11072    pub executive_max: f64,
11073}
11074
11075impl Default for PayrollSalaryRanges {
11076    fn default() -> Self {
11077        Self {
11078            staff_min: default_staff_min(),
11079            staff_max: default_staff_max(),
11080            manager_min: default_manager_min(),
11081            manager_max: default_manager_max(),
11082            director_min: default_director_min(),
11083            director_max: default_director_max(),
11084            executive_min: default_executive_min(),
11085            executive_max: default_executive_max(),
11086        }
11087    }
11088}
11089
11090fn default_staff_min() -> f64 {
11091    50_000.0
11092}
11093fn default_staff_max() -> f64 {
11094    70_000.0
11095}
11096fn default_manager_min() -> f64 {
11097    80_000.0
11098}
11099fn default_manager_max() -> f64 {
11100    120_000.0
11101}
11102fn default_director_min() -> f64 {
11103    120_000.0
11104}
11105fn default_director_max() -> f64 {
11106    180_000.0
11107}
11108fn default_executive_min() -> f64 {
11109    180_000.0
11110}
11111fn default_executive_max() -> f64 {
11112    350_000.0
11113}
11114
11115/// Effective tax rates for payroll.
11116#[derive(Debug, Clone, Serialize, Deserialize)]
11117pub struct PayrollTaxRates {
11118    /// Federal effective tax rate
11119    #[serde(default = "default_federal_rate")]
11120    pub federal_effective: f64,
11121    /// State effective tax rate
11122    #[serde(default = "default_state_rate")]
11123    pub state_effective: f64,
11124    /// FICA/social security rate
11125    #[serde(default = "default_fica_rate")]
11126    pub fica: f64,
11127}
11128
11129impl Default for PayrollTaxRates {
11130    fn default() -> Self {
11131        Self {
11132            federal_effective: default_federal_rate(),
11133            state_effective: default_state_rate(),
11134            fica: default_fica_rate(),
11135        }
11136    }
11137}
11138
11139fn default_federal_rate() -> f64 {
11140    0.22
11141}
11142fn default_state_rate() -> f64 {
11143    0.05
11144}
11145fn default_fica_rate() -> f64 {
11146    0.0765
11147}
11148
11149/// Time and attendance configuration.
11150#[derive(Debug, Clone, Serialize, Deserialize)]
11151pub struct TimeAttendanceConfig {
11152    /// Enable time tracking
11153    #[serde(default = "default_true")]
11154    pub enabled: bool,
11155    /// Overtime rate (% of employees with overtime in a period)
11156    #[serde(default = "default_overtime_rate")]
11157    pub overtime_rate: f64,
11158}
11159
11160impl Default for TimeAttendanceConfig {
11161    fn default() -> Self {
11162        Self {
11163            enabled: true,
11164            overtime_rate: default_overtime_rate(),
11165        }
11166    }
11167}
11168
11169fn default_overtime_rate() -> f64 {
11170    0.10
11171}
11172
11173/// Expense management configuration.
11174#[derive(Debug, Clone, Serialize, Deserialize)]
11175pub struct ExpenseConfig {
11176    /// Enable expense report generation
11177    #[serde(default = "default_true")]
11178    pub enabled: bool,
11179    /// Rate of employees submitting expenses per month
11180    #[serde(default = "default_expense_submission_rate")]
11181    pub submission_rate: f64,
11182    /// Rate of policy violations
11183    #[serde(default = "default_policy_violation_rate")]
11184    pub policy_violation_rate: f64,
11185}
11186
11187impl Default for ExpenseConfig {
11188    fn default() -> Self {
11189        Self {
11190            enabled: true,
11191            submission_rate: default_expense_submission_rate(),
11192            policy_violation_rate: default_policy_violation_rate(),
11193        }
11194    }
11195}
11196
11197fn default_expense_submission_rate() -> f64 {
11198    0.30
11199}
11200fn default_policy_violation_rate() -> f64 {
11201    0.08
11202}
11203
11204// ----- Manufacturing Configuration -----
11205
11206/// Manufacturing process configuration (production orders, WIP, routing).
11207#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11208pub struct ManufacturingProcessConfig {
11209    /// Enable manufacturing generation
11210    #[serde(default)]
11211    pub enabled: bool,
11212    /// Production order configuration
11213    #[serde(default)]
11214    pub production_orders: ProductionOrderConfig,
11215    /// Costing configuration
11216    #[serde(default)]
11217    pub costing: ManufacturingCostingConfig,
11218    /// Routing configuration
11219    #[serde(default)]
11220    pub routing: RoutingConfig,
11221}
11222
11223/// Production order configuration.
11224#[derive(Debug, Clone, Serialize, Deserialize)]
11225pub struct ProductionOrderConfig {
11226    /// Orders per month
11227    #[serde(default = "default_prod_orders_per_month")]
11228    pub orders_per_month: u32,
11229    /// Average batch size
11230    #[serde(default = "default_prod_avg_batch_size")]
11231    pub avg_batch_size: u32,
11232    /// Yield rate
11233    #[serde(default = "default_prod_yield_rate")]
11234    pub yield_rate: f64,
11235    /// Make-to-order rate (vs make-to-stock)
11236    #[serde(default = "default_prod_make_to_order_rate")]
11237    pub make_to_order_rate: f64,
11238    /// Rework rate
11239    #[serde(default = "default_prod_rework_rate")]
11240    pub rework_rate: f64,
11241}
11242
11243impl Default for ProductionOrderConfig {
11244    fn default() -> Self {
11245        Self {
11246            orders_per_month: default_prod_orders_per_month(),
11247            avg_batch_size: default_prod_avg_batch_size(),
11248            yield_rate: default_prod_yield_rate(),
11249            make_to_order_rate: default_prod_make_to_order_rate(),
11250            rework_rate: default_prod_rework_rate(),
11251        }
11252    }
11253}
11254
11255fn default_prod_orders_per_month() -> u32 {
11256    50
11257}
11258fn default_prod_avg_batch_size() -> u32 {
11259    100
11260}
11261fn default_prod_yield_rate() -> f64 {
11262    0.97
11263}
11264fn default_prod_make_to_order_rate() -> f64 {
11265    0.20
11266}
11267fn default_prod_rework_rate() -> f64 {
11268    0.03
11269}
11270
11271/// Manufacturing costing configuration.
11272#[derive(Debug, Clone, Serialize, Deserialize)]
11273pub struct ManufacturingCostingConfig {
11274    /// Labor rate per hour
11275    #[serde(default = "default_labor_rate")]
11276    pub labor_rate_per_hour: f64,
11277    /// Overhead application rate (multiplier on direct labor)
11278    #[serde(default = "default_overhead_rate")]
11279    pub overhead_rate: f64,
11280    /// Standard cost update frequency
11281    #[serde(default = "default_cost_update_frequency")]
11282    pub standard_cost_update_frequency: String,
11283}
11284
11285impl Default for ManufacturingCostingConfig {
11286    fn default() -> Self {
11287        Self {
11288            labor_rate_per_hour: default_labor_rate(),
11289            overhead_rate: default_overhead_rate(),
11290            standard_cost_update_frequency: default_cost_update_frequency(),
11291        }
11292    }
11293}
11294
11295fn default_labor_rate() -> f64 {
11296    35.0
11297}
11298fn default_overhead_rate() -> f64 {
11299    1.50
11300}
11301fn default_cost_update_frequency() -> String {
11302    "quarterly".to_string()
11303}
11304
11305/// Routing configuration for production operations.
11306#[derive(Debug, Clone, Serialize, Deserialize)]
11307pub struct RoutingConfig {
11308    /// Average number of operations per routing
11309    #[serde(default = "default_avg_operations")]
11310    pub avg_operations: u32,
11311    /// Average setup time in hours
11312    #[serde(default = "default_setup_time")]
11313    pub setup_time_hours: f64,
11314    /// Run time variation coefficient
11315    #[serde(default = "default_run_time_variation")]
11316    pub run_time_variation: f64,
11317}
11318
11319impl Default for RoutingConfig {
11320    fn default() -> Self {
11321        Self {
11322            avg_operations: default_avg_operations(),
11323            setup_time_hours: default_setup_time(),
11324            run_time_variation: default_run_time_variation(),
11325        }
11326    }
11327}
11328
11329fn default_avg_operations() -> u32 {
11330    4
11331}
11332fn default_setup_time() -> f64 {
11333    1.5
11334}
11335fn default_run_time_variation() -> f64 {
11336    0.15
11337}
11338
11339// ----- Sales Quote Configuration -----
11340
11341/// Sales quote (quote-to-order) pipeline configuration.
11342#[derive(Debug, Clone, Serialize, Deserialize)]
11343pub struct SalesQuoteConfig {
11344    /// Enable sales quote generation
11345    #[serde(default)]
11346    pub enabled: bool,
11347    /// Quotes per month
11348    #[serde(default = "default_quotes_per_month")]
11349    pub quotes_per_month: u32,
11350    /// Win rate (fraction of quotes that convert to orders)
11351    #[serde(default = "default_quote_win_rate")]
11352    pub win_rate: f64,
11353    /// Average quote validity in days
11354    #[serde(default = "default_quote_validity_days")]
11355    pub validity_days: u32,
11356}
11357
11358impl Default for SalesQuoteConfig {
11359    fn default() -> Self {
11360        Self {
11361            enabled: false,
11362            quotes_per_month: default_quotes_per_month(),
11363            win_rate: default_quote_win_rate(),
11364            validity_days: default_quote_validity_days(),
11365        }
11366    }
11367}
11368
11369fn default_quotes_per_month() -> u32 {
11370    30
11371}
11372fn default_quote_win_rate() -> f64 {
11373    0.35
11374}
11375fn default_quote_validity_days() -> u32 {
11376    30
11377}
11378
11379// =============================================================================
11380// Tax Accounting Configuration
11381// =============================================================================
11382
11383/// Tax accounting configuration.
11384///
11385/// Controls generation of tax-related data including VAT/GST, sales tax,
11386/// withholding tax, tax provisions, and payroll tax across multiple jurisdictions.
11387#[derive(Debug, Clone, Serialize, Deserialize)]
11388pub struct TaxConfig {
11389    /// Whether tax generation is enabled.
11390    #[serde(default)]
11391    pub enabled: bool,
11392    /// Tax jurisdiction configuration.
11393    #[serde(default)]
11394    pub jurisdictions: TaxJurisdictionConfig,
11395    /// VAT/GST configuration.
11396    #[serde(default)]
11397    pub vat_gst: VatGstConfig,
11398    /// Sales tax configuration.
11399    #[serde(default)]
11400    pub sales_tax: SalesTaxConfig,
11401    /// Withholding tax configuration.
11402    #[serde(default)]
11403    pub withholding: WithholdingTaxSchemaConfig,
11404    /// Tax provision configuration.
11405    #[serde(default)]
11406    pub provisions: TaxProvisionSchemaConfig,
11407    /// Payroll tax configuration.
11408    #[serde(default)]
11409    pub payroll_tax: PayrollTaxSchemaConfig,
11410    /// Anomaly injection rate for tax data (0.0 to 1.0).
11411    #[serde(default = "default_tax_anomaly_rate")]
11412    pub anomaly_rate: f64,
11413}
11414
11415fn default_tax_anomaly_rate() -> f64 {
11416    0.03
11417}
11418
11419impl Default for TaxConfig {
11420    fn default() -> Self {
11421        Self {
11422            enabled: false,
11423            jurisdictions: TaxJurisdictionConfig::default(),
11424            vat_gst: VatGstConfig::default(),
11425            sales_tax: SalesTaxConfig::default(),
11426            withholding: WithholdingTaxSchemaConfig::default(),
11427            provisions: TaxProvisionSchemaConfig::default(),
11428            payroll_tax: PayrollTaxSchemaConfig::default(),
11429            anomaly_rate: default_tax_anomaly_rate(),
11430        }
11431    }
11432}
11433
11434/// Tax jurisdiction configuration.
11435///
11436/// Specifies which countries and subnational jurisdictions to include
11437/// when generating tax data.
11438#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11439pub struct TaxJurisdictionConfig {
11440    /// List of country codes to include (e.g., ["US", "DE", "GB"]).
11441    #[serde(default)]
11442    pub countries: Vec<String>,
11443    /// Whether to include subnational jurisdictions (e.g., US states, Canadian provinces).
11444    #[serde(default)]
11445    pub include_subnational: bool,
11446}
11447
11448/// VAT/GST configuration.
11449///
11450/// Controls generation of Value Added Tax / Goods and Services Tax data,
11451/// including standard and reduced rates, exempt categories, and reverse charge.
11452#[derive(Debug, Clone, Serialize, Deserialize)]
11453pub struct VatGstConfig {
11454    /// Whether VAT/GST generation is enabled.
11455    #[serde(default)]
11456    pub enabled: bool,
11457    /// Standard VAT/GST rates by country code (e.g., {"DE": 0.19, "GB": 0.20}).
11458    #[serde(default)]
11459    pub standard_rates: std::collections::HashMap<String, f64>,
11460    /// Reduced VAT/GST rates by country code (e.g., {"DE": 0.07, "GB": 0.05}).
11461    #[serde(default)]
11462    pub reduced_rates: std::collections::HashMap<String, f64>,
11463    /// Categories exempt from VAT/GST (e.g., ["financial_services", "healthcare"]).
11464    #[serde(default)]
11465    pub exempt_categories: Vec<String>,
11466    /// Whether to apply reverse charge mechanism for cross-border B2B transactions.
11467    #[serde(default = "default_true")]
11468    pub reverse_charge: bool,
11469}
11470
11471impl Default for VatGstConfig {
11472    fn default() -> Self {
11473        Self {
11474            enabled: false,
11475            standard_rates: std::collections::HashMap::new(),
11476            reduced_rates: std::collections::HashMap::new(),
11477            exempt_categories: Vec::new(),
11478            reverse_charge: true,
11479        }
11480    }
11481}
11482
11483/// Sales tax configuration.
11484///
11485/// Controls generation of US-style sales tax data including nexus determination.
11486#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11487pub struct SalesTaxConfig {
11488    /// Whether sales tax generation is enabled.
11489    #[serde(default)]
11490    pub enabled: bool,
11491    /// US states where the company has nexus (e.g., ["CA", "NY", "TX"]).
11492    #[serde(default)]
11493    pub nexus_states: Vec<String>,
11494}
11495
11496/// Withholding tax configuration.
11497///
11498/// Controls generation of withholding tax data for cross-border payments,
11499/// including treaty network and rate overrides.
11500#[derive(Debug, Clone, Serialize, Deserialize)]
11501pub struct WithholdingTaxSchemaConfig {
11502    /// Whether withholding tax generation is enabled.
11503    #[serde(default)]
11504    pub enabled: bool,
11505    /// Whether to simulate a treaty network with reduced rates.
11506    #[serde(default = "default_true")]
11507    pub treaty_network: bool,
11508    /// Default withholding tax rate for non-treaty countries (0.0 to 1.0).
11509    #[serde(default = "default_withholding_rate")]
11510    pub default_rate: f64,
11511    /// Reduced withholding tax rate for treaty countries (0.0 to 1.0).
11512    #[serde(default = "default_treaty_reduced_rate")]
11513    pub treaty_reduced_rate: f64,
11514}
11515
11516fn default_withholding_rate() -> f64 {
11517    0.30
11518}
11519
11520fn default_treaty_reduced_rate() -> f64 {
11521    0.15
11522}
11523
11524impl Default for WithholdingTaxSchemaConfig {
11525    fn default() -> Self {
11526        Self {
11527            enabled: false,
11528            treaty_network: true,
11529            default_rate: default_withholding_rate(),
11530            treaty_reduced_rate: default_treaty_reduced_rate(),
11531        }
11532    }
11533}
11534
11535/// Tax provision configuration.
11536///
11537/// Controls generation of tax provision data including statutory rates
11538/// and uncertain tax positions (ASC 740 / IAS 12).
11539#[derive(Debug, Clone, Serialize, Deserialize)]
11540pub struct TaxProvisionSchemaConfig {
11541    /// Whether tax provision generation is enabled.
11542    /// Defaults to true when tax is enabled, as provisions are typically required.
11543    #[serde(default = "default_true")]
11544    pub enabled: bool,
11545    /// Statutory corporate tax rate (0.0 to 1.0).
11546    #[serde(default = "default_statutory_rate")]
11547    pub statutory_rate: f64,
11548    /// Whether to generate uncertain tax positions (FIN 48 / IFRIC 23).
11549    #[serde(default = "default_true")]
11550    pub uncertain_positions: bool,
11551}
11552
11553fn default_statutory_rate() -> f64 {
11554    0.21
11555}
11556
11557impl Default for TaxProvisionSchemaConfig {
11558    fn default() -> Self {
11559        Self {
11560            enabled: true,
11561            statutory_rate: default_statutory_rate(),
11562            uncertain_positions: true,
11563        }
11564    }
11565}
11566
11567/// Payroll tax configuration.
11568///
11569/// Controls generation of payroll tax data (employer/employee contributions,
11570/// social security, Medicare, etc.).
11571#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11572pub struct PayrollTaxSchemaConfig {
11573    /// Whether payroll tax generation is enabled.
11574    #[serde(default)]
11575    pub enabled: bool,
11576}
11577
11578// ---------------------------------------------------------------------------
11579// Treasury & Cash Management Configuration
11580// ---------------------------------------------------------------------------
11581
11582/// Treasury and cash management configuration.
11583///
11584/// Controls generation of cash positions, forecasts, pooling, hedging
11585/// instruments (ASC 815 / IFRS 9), debt instruments with covenants,
11586/// bank guarantees, and intercompany netting runs.
11587#[derive(Debug, Clone, Serialize, Deserialize)]
11588pub struct TreasuryConfig {
11589    /// Whether treasury generation is enabled.
11590    #[serde(default)]
11591    pub enabled: bool,
11592    /// Cash positioning configuration.
11593    #[serde(default)]
11594    pub cash_positioning: CashPositioningConfig,
11595    /// Cash forecasting configuration.
11596    #[serde(default)]
11597    pub cash_forecasting: CashForecastingConfig,
11598    /// Cash pooling configuration.
11599    #[serde(default)]
11600    pub cash_pooling: CashPoolingConfig,
11601    /// Hedging configuration (FX forwards, IR swaps, etc.).
11602    #[serde(default)]
11603    pub hedging: HedgingSchemaConfig,
11604    /// Debt instrument and covenant configuration.
11605    #[serde(default)]
11606    pub debt: DebtSchemaConfig,
11607    /// Intercompany netting configuration.
11608    #[serde(default)]
11609    pub netting: NettingSchemaConfig,
11610    /// Bank guarantee / letter of credit configuration.
11611    #[serde(default)]
11612    pub bank_guarantees: BankGuaranteeSchemaConfig,
11613    /// Anomaly injection rate for treasury data (0.0 to 1.0).
11614    #[serde(default = "default_treasury_anomaly_rate")]
11615    pub anomaly_rate: f64,
11616}
11617
11618fn default_treasury_anomaly_rate() -> f64 {
11619    0.02
11620}
11621
11622impl Default for TreasuryConfig {
11623    fn default() -> Self {
11624        Self {
11625            enabled: false,
11626            cash_positioning: CashPositioningConfig::default(),
11627            cash_forecasting: CashForecastingConfig::default(),
11628            cash_pooling: CashPoolingConfig::default(),
11629            hedging: HedgingSchemaConfig::default(),
11630            debt: DebtSchemaConfig::default(),
11631            netting: NettingSchemaConfig::default(),
11632            bank_guarantees: BankGuaranteeSchemaConfig::default(),
11633            anomaly_rate: default_treasury_anomaly_rate(),
11634        }
11635    }
11636}
11637
11638/// Cash positioning configuration.
11639///
11640/// Controls daily cash position generation per entity/bank account.
11641#[derive(Debug, Clone, Serialize, Deserialize)]
11642pub struct CashPositioningConfig {
11643    /// Whether cash positioning is enabled.
11644    #[serde(default = "default_true")]
11645    pub enabled: bool,
11646    /// Position generation frequency.
11647    #[serde(default = "default_cash_frequency")]
11648    pub frequency: String,
11649    /// Minimum cash balance policy threshold.
11650    #[serde(default = "default_minimum_balance_policy")]
11651    pub minimum_balance_policy: f64,
11652}
11653
11654fn default_cash_frequency() -> String {
11655    "daily".to_string()
11656}
11657
11658fn default_minimum_balance_policy() -> f64 {
11659    100_000.0
11660}
11661
11662impl Default for CashPositioningConfig {
11663    fn default() -> Self {
11664        Self {
11665            enabled: true,
11666            frequency: default_cash_frequency(),
11667            minimum_balance_policy: default_minimum_balance_policy(),
11668        }
11669    }
11670}
11671
11672/// Cash forecasting configuration.
11673///
11674/// Controls forward-looking cash forecast generation with probability-weighted items.
11675#[derive(Debug, Clone, Serialize, Deserialize)]
11676pub struct CashForecastingConfig {
11677    /// Whether cash forecasting is enabled.
11678    #[serde(default = "default_true")]
11679    pub enabled: bool,
11680    /// Number of days to forecast into the future.
11681    #[serde(default = "default_horizon_days")]
11682    pub horizon_days: u32,
11683    /// AR collection probability curve type ("aging" or "flat").
11684    #[serde(default = "default_ar_probability_curve")]
11685    pub ar_collection_probability_curve: String,
11686    /// Confidence interval for the forecast (0.0 to 1.0).
11687    #[serde(default = "default_confidence_interval")]
11688    pub confidence_interval: f64,
11689}
11690
11691fn default_horizon_days() -> u32 {
11692    90
11693}
11694
11695fn default_ar_probability_curve() -> String {
11696    "aging".to_string()
11697}
11698
11699fn default_confidence_interval() -> f64 {
11700    0.90
11701}
11702
11703impl Default for CashForecastingConfig {
11704    fn default() -> Self {
11705        Self {
11706            enabled: true,
11707            horizon_days: default_horizon_days(),
11708            ar_collection_probability_curve: default_ar_probability_curve(),
11709            confidence_interval: default_confidence_interval(),
11710        }
11711    }
11712}
11713
11714/// Cash pooling configuration.
11715///
11716/// Controls cash pool structure generation (physical, notional, zero-balancing).
11717#[derive(Debug, Clone, Serialize, Deserialize)]
11718pub struct CashPoolingConfig {
11719    /// Whether cash pooling is enabled.
11720    #[serde(default)]
11721    pub enabled: bool,
11722    /// Pool type: "physical_pooling", "notional_pooling", or "zero_balancing".
11723    #[serde(default = "default_pool_type")]
11724    pub pool_type: String,
11725    /// Time of day when sweeps occur (HH:MM format).
11726    #[serde(default = "default_sweep_time")]
11727    pub sweep_time: String,
11728}
11729
11730fn default_pool_type() -> String {
11731    "zero_balancing".to_string()
11732}
11733
11734fn default_sweep_time() -> String {
11735    "16:00".to_string()
11736}
11737
11738impl Default for CashPoolingConfig {
11739    fn default() -> Self {
11740        Self {
11741            enabled: false,
11742            pool_type: default_pool_type(),
11743            sweep_time: default_sweep_time(),
11744        }
11745    }
11746}
11747
11748/// Hedging configuration.
11749///
11750/// Controls generation of hedging instruments and hedge relationship designations
11751/// under ASC 815 / IFRS 9.
11752#[derive(Debug, Clone, Serialize, Deserialize)]
11753pub struct HedgingSchemaConfig {
11754    /// Whether hedging generation is enabled.
11755    #[serde(default)]
11756    pub enabled: bool,
11757    /// Target hedge ratio (0.0 to 1.0). Proportion of FX exposure to hedge.
11758    #[serde(default = "default_hedge_ratio")]
11759    pub hedge_ratio: f64,
11760    /// Types of instruments to generate (e.g., ["fx_forward", "interest_rate_swap"]).
11761    #[serde(default = "default_hedge_instruments")]
11762    pub instruments: Vec<String>,
11763    /// Whether to designate formal hedge accounting relationships.
11764    #[serde(default = "default_true")]
11765    pub hedge_accounting: bool,
11766    /// Effectiveness testing method: "dollar_offset", "regression", or "critical_terms".
11767    #[serde(default = "default_effectiveness_method")]
11768    pub effectiveness_method: String,
11769}
11770
11771fn default_hedge_ratio() -> f64 {
11772    0.75
11773}
11774
11775fn default_hedge_instruments() -> Vec<String> {
11776    vec!["fx_forward".to_string(), "interest_rate_swap".to_string()]
11777}
11778
11779fn default_effectiveness_method() -> String {
11780    "regression".to_string()
11781}
11782
11783impl Default for HedgingSchemaConfig {
11784    fn default() -> Self {
11785        Self {
11786            enabled: false,
11787            hedge_ratio: default_hedge_ratio(),
11788            instruments: default_hedge_instruments(),
11789            hedge_accounting: true,
11790            effectiveness_method: default_effectiveness_method(),
11791        }
11792    }
11793}
11794
11795/// Debt instrument configuration.
11796///
11797/// Controls generation of debt instruments (term loans, revolving credit, bonds)
11798/// with amortization schedules and financial covenants.
11799#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11800pub struct DebtSchemaConfig {
11801    /// Whether debt instrument generation is enabled.
11802    #[serde(default)]
11803    pub enabled: bool,
11804    /// Debt instrument definitions.
11805    #[serde(default)]
11806    pub instruments: Vec<DebtInstrumentDef>,
11807    /// Covenant definitions.
11808    #[serde(default)]
11809    pub covenants: Vec<CovenantDef>,
11810}
11811
11812/// Definition of a debt instrument in configuration.
11813#[derive(Debug, Clone, Serialize, Deserialize)]
11814pub struct DebtInstrumentDef {
11815    /// Instrument type: "term_loan", "revolving_credit", "bond", "commercial_paper", "bridge_loan".
11816    #[serde(rename = "type")]
11817    pub instrument_type: String,
11818    /// Principal amount (for term loans, bonds).
11819    #[serde(default)]
11820    pub principal: Option<f64>,
11821    /// Interest rate (annual, as decimal fraction).
11822    #[serde(default)]
11823    pub rate: Option<f64>,
11824    /// Maturity in months.
11825    #[serde(default)]
11826    pub maturity_months: Option<u32>,
11827    /// Facility limit (for revolving credit).
11828    #[serde(default)]
11829    pub facility: Option<f64>,
11830}
11831
11832/// Definition of a debt covenant in configuration.
11833#[derive(Debug, Clone, Serialize, Deserialize)]
11834pub struct CovenantDef {
11835    /// Covenant type: "debt_to_equity", "interest_coverage", "current_ratio",
11836    /// "net_worth", "debt_to_ebitda", "fixed_charge_coverage".
11837    #[serde(rename = "type")]
11838    pub covenant_type: String,
11839    /// Covenant threshold value.
11840    pub threshold: f64,
11841}
11842
11843/// Intercompany netting configuration.
11844///
11845/// Controls generation of multilateral netting runs.
11846#[derive(Debug, Clone, Serialize, Deserialize)]
11847pub struct NettingSchemaConfig {
11848    /// Whether netting generation is enabled.
11849    #[serde(default)]
11850    pub enabled: bool,
11851    /// Netting cycle: "daily", "weekly", or "monthly".
11852    #[serde(default = "default_netting_cycle")]
11853    pub cycle: String,
11854}
11855
11856fn default_netting_cycle() -> String {
11857    "monthly".to_string()
11858}
11859
11860impl Default for NettingSchemaConfig {
11861    fn default() -> Self {
11862        Self {
11863            enabled: false,
11864            cycle: default_netting_cycle(),
11865        }
11866    }
11867}
11868
11869/// Bank guarantee and letter of credit configuration.
11870///
11871/// Controls generation of bank guarantees, standby LCs, and performance bonds.
11872#[derive(Debug, Clone, Serialize, Deserialize)]
11873pub struct BankGuaranteeSchemaConfig {
11874    /// Whether bank guarantee generation is enabled.
11875    #[serde(default)]
11876    pub enabled: bool,
11877    /// Number of guarantees to generate.
11878    #[serde(default = "default_guarantee_count")]
11879    pub count: u32,
11880}
11881
11882fn default_guarantee_count() -> u32 {
11883    5
11884}
11885
11886impl Default for BankGuaranteeSchemaConfig {
11887    fn default() -> Self {
11888        Self {
11889            enabled: false,
11890            count: default_guarantee_count(),
11891        }
11892    }
11893}
11894
11895// ===========================================================================
11896// Project Accounting Configuration
11897// ===========================================================================
11898
11899/// Project accounting configuration.
11900///
11901/// Controls generation of project cost lines, revenue recognition,
11902/// milestones, change orders, retainage, and earned value metrics.
11903#[derive(Debug, Clone, Serialize, Deserialize)]
11904pub struct ProjectAccountingConfig {
11905    /// Whether project accounting is enabled.
11906    #[serde(default)]
11907    pub enabled: bool,
11908    /// Number of projects to generate.
11909    #[serde(default = "default_project_count")]
11910    pub project_count: u32,
11911    /// Distribution of project types (capital, internal, customer, r_and_d, maintenance, technology).
11912    #[serde(default)]
11913    pub project_types: ProjectTypeDistribution,
11914    /// WBS structure configuration.
11915    #[serde(default)]
11916    pub wbs: WbsSchemaConfig,
11917    /// Cost allocation rates (what % of source documents get project-tagged).
11918    #[serde(default)]
11919    pub cost_allocation: CostAllocationConfig,
11920    /// Revenue recognition configuration for project accounting.
11921    #[serde(default)]
11922    pub revenue_recognition: ProjectRevenueRecognitionConfig,
11923    /// Milestone configuration.
11924    #[serde(default)]
11925    pub milestones: MilestoneSchemaConfig,
11926    /// Change order configuration.
11927    #[serde(default)]
11928    pub change_orders: ChangeOrderSchemaConfig,
11929    /// Retainage configuration.
11930    #[serde(default)]
11931    pub retainage: RetainageSchemaConfig,
11932    /// Earned value management configuration.
11933    #[serde(default)]
11934    pub earned_value: EarnedValueSchemaConfig,
11935    /// Anomaly injection rate for project accounting data (0.0 to 1.0).
11936    #[serde(default = "default_project_anomaly_rate")]
11937    pub anomaly_rate: f64,
11938}
11939
11940fn default_project_count() -> u32 {
11941    10
11942}
11943
11944fn default_project_anomaly_rate() -> f64 {
11945    0.03
11946}
11947
11948impl Default for ProjectAccountingConfig {
11949    fn default() -> Self {
11950        Self {
11951            enabled: false,
11952            project_count: default_project_count(),
11953            project_types: ProjectTypeDistribution::default(),
11954            wbs: WbsSchemaConfig::default(),
11955            cost_allocation: CostAllocationConfig::default(),
11956            revenue_recognition: ProjectRevenueRecognitionConfig::default(),
11957            milestones: MilestoneSchemaConfig::default(),
11958            change_orders: ChangeOrderSchemaConfig::default(),
11959            retainage: RetainageSchemaConfig::default(),
11960            earned_value: EarnedValueSchemaConfig::default(),
11961            anomaly_rate: default_project_anomaly_rate(),
11962        }
11963    }
11964}
11965
11966/// Distribution of project types by weight.
11967#[derive(Debug, Clone, Serialize, Deserialize)]
11968pub struct ProjectTypeDistribution {
11969    /// Weight for capital projects (default 0.25).
11970    #[serde(default = "default_capital_weight")]
11971    pub capital: f64,
11972    /// Weight for internal projects (default 0.20).
11973    #[serde(default = "default_internal_weight")]
11974    pub internal: f64,
11975    /// Weight for customer projects (default 0.30).
11976    #[serde(default = "default_customer_weight")]
11977    pub customer: f64,
11978    /// Weight for R&D projects (default 0.10).
11979    #[serde(default = "default_rnd_weight")]
11980    pub r_and_d: f64,
11981    /// Weight for maintenance projects (default 0.10).
11982    #[serde(default = "default_maintenance_weight")]
11983    pub maintenance: f64,
11984    /// Weight for technology projects (default 0.05).
11985    #[serde(default = "default_technology_weight")]
11986    pub technology: f64,
11987}
11988
11989fn default_capital_weight() -> f64 {
11990    0.25
11991}
11992fn default_internal_weight() -> f64 {
11993    0.20
11994}
11995fn default_customer_weight() -> f64 {
11996    0.30
11997}
11998fn default_rnd_weight() -> f64 {
11999    0.10
12000}
12001fn default_maintenance_weight() -> f64 {
12002    0.10
12003}
12004fn default_technology_weight() -> f64 {
12005    0.05
12006}
12007
12008impl Default for ProjectTypeDistribution {
12009    fn default() -> Self {
12010        Self {
12011            capital: default_capital_weight(),
12012            internal: default_internal_weight(),
12013            customer: default_customer_weight(),
12014            r_and_d: default_rnd_weight(),
12015            maintenance: default_maintenance_weight(),
12016            technology: default_technology_weight(),
12017        }
12018    }
12019}
12020
12021/// WBS structure configuration.
12022#[derive(Debug, Clone, Serialize, Deserialize)]
12023pub struct WbsSchemaConfig {
12024    /// Maximum depth of WBS hierarchy (default 3).
12025    #[serde(default = "default_wbs_max_depth")]
12026    pub max_depth: u32,
12027    /// Minimum elements per level-1 WBS (default 2).
12028    #[serde(default = "default_wbs_min_elements")]
12029    pub min_elements_per_level: u32,
12030    /// Maximum elements per level-1 WBS (default 6).
12031    #[serde(default = "default_wbs_max_elements")]
12032    pub max_elements_per_level: u32,
12033}
12034
12035fn default_wbs_max_depth() -> u32 {
12036    3
12037}
12038fn default_wbs_min_elements() -> u32 {
12039    2
12040}
12041fn default_wbs_max_elements() -> u32 {
12042    6
12043}
12044
12045impl Default for WbsSchemaConfig {
12046    fn default() -> Self {
12047        Self {
12048            max_depth: default_wbs_max_depth(),
12049            min_elements_per_level: default_wbs_min_elements(),
12050            max_elements_per_level: default_wbs_max_elements(),
12051        }
12052    }
12053}
12054
12055/// Cost allocation rates — what fraction of each document type gets linked to a project.
12056#[derive(Debug, Clone, Serialize, Deserialize)]
12057pub struct CostAllocationConfig {
12058    /// Fraction of time entries assigned to projects (0.0 to 1.0).
12059    #[serde(default = "default_time_entry_rate")]
12060    pub time_entry_project_rate: f64,
12061    /// Fraction of expense reports assigned to projects (0.0 to 1.0).
12062    #[serde(default = "default_expense_rate")]
12063    pub expense_project_rate: f64,
12064    /// Fraction of purchase orders assigned to projects (0.0 to 1.0).
12065    #[serde(default = "default_po_rate")]
12066    pub purchase_order_project_rate: f64,
12067    /// Fraction of vendor invoices assigned to projects (0.0 to 1.0).
12068    #[serde(default = "default_vi_rate")]
12069    pub vendor_invoice_project_rate: f64,
12070}
12071
12072fn default_time_entry_rate() -> f64 {
12073    0.60
12074}
12075fn default_expense_rate() -> f64 {
12076    0.30
12077}
12078fn default_po_rate() -> f64 {
12079    0.40
12080}
12081fn default_vi_rate() -> f64 {
12082    0.35
12083}
12084
12085impl Default for CostAllocationConfig {
12086    fn default() -> Self {
12087        Self {
12088            time_entry_project_rate: default_time_entry_rate(),
12089            expense_project_rate: default_expense_rate(),
12090            purchase_order_project_rate: default_po_rate(),
12091            vendor_invoice_project_rate: default_vi_rate(),
12092        }
12093    }
12094}
12095
12096/// Revenue recognition configuration for project accounting.
12097#[derive(Debug, Clone, Serialize, Deserialize)]
12098pub struct ProjectRevenueRecognitionConfig {
12099    /// Whether revenue recognition is enabled for customer projects.
12100    #[serde(default = "default_true")]
12101    pub enabled: bool,
12102    /// Default method: "percentage_of_completion", "completed_contract", "milestone_based".
12103    #[serde(default = "default_revenue_method")]
12104    pub method: String,
12105    /// Default completion measure: "cost_to_cost", "labor_hours", "physical_completion".
12106    #[serde(default = "default_completion_measure")]
12107    pub completion_measure: String,
12108    /// Average contract value for customer projects.
12109    #[serde(default = "default_avg_contract_value")]
12110    pub avg_contract_value: f64,
12111}
12112
12113fn default_revenue_method() -> String {
12114    "percentage_of_completion".to_string()
12115}
12116fn default_completion_measure() -> String {
12117    "cost_to_cost".to_string()
12118}
12119fn default_avg_contract_value() -> f64 {
12120    500_000.0
12121}
12122
12123impl Default for ProjectRevenueRecognitionConfig {
12124    fn default() -> Self {
12125        Self {
12126            enabled: true,
12127            method: default_revenue_method(),
12128            completion_measure: default_completion_measure(),
12129            avg_contract_value: default_avg_contract_value(),
12130        }
12131    }
12132}
12133
12134/// Milestone configuration.
12135#[derive(Debug, Clone, Serialize, Deserialize)]
12136pub struct MilestoneSchemaConfig {
12137    /// Whether milestone generation is enabled.
12138    #[serde(default = "default_true")]
12139    pub enabled: bool,
12140    /// Average number of milestones per project.
12141    #[serde(default = "default_milestones_per_project")]
12142    pub avg_per_project: u32,
12143    /// Fraction of milestones that are payment milestones (0.0 to 1.0).
12144    #[serde(default = "default_payment_milestone_rate")]
12145    pub payment_milestone_rate: f64,
12146}
12147
12148fn default_milestones_per_project() -> u32 {
12149    4
12150}
12151fn default_payment_milestone_rate() -> f64 {
12152    0.50
12153}
12154
12155impl Default for MilestoneSchemaConfig {
12156    fn default() -> Self {
12157        Self {
12158            enabled: true,
12159            avg_per_project: default_milestones_per_project(),
12160            payment_milestone_rate: default_payment_milestone_rate(),
12161        }
12162    }
12163}
12164
12165/// Change order configuration.
12166#[derive(Debug, Clone, Serialize, Deserialize)]
12167pub struct ChangeOrderSchemaConfig {
12168    /// Whether change order generation is enabled.
12169    #[serde(default = "default_true")]
12170    pub enabled: bool,
12171    /// Probability that a project will have at least one change order (0.0 to 1.0).
12172    #[serde(default = "default_change_order_probability")]
12173    pub probability: f64,
12174    /// Maximum change orders per project.
12175    #[serde(default = "default_max_change_orders")]
12176    pub max_per_project: u32,
12177    /// Approval rate for change orders (0.0 to 1.0).
12178    #[serde(default = "default_change_order_approval_rate")]
12179    pub approval_rate: f64,
12180}
12181
12182fn default_change_order_probability() -> f64 {
12183    0.40
12184}
12185fn default_max_change_orders() -> u32 {
12186    3
12187}
12188fn default_change_order_approval_rate() -> f64 {
12189    0.75
12190}
12191
12192impl Default for ChangeOrderSchemaConfig {
12193    fn default() -> Self {
12194        Self {
12195            enabled: true,
12196            probability: default_change_order_probability(),
12197            max_per_project: default_max_change_orders(),
12198            approval_rate: default_change_order_approval_rate(),
12199        }
12200    }
12201}
12202
12203/// Retainage configuration.
12204#[derive(Debug, Clone, Serialize, Deserialize)]
12205pub struct RetainageSchemaConfig {
12206    /// Whether retainage is enabled.
12207    #[serde(default)]
12208    pub enabled: bool,
12209    /// Default retainage percentage (0.0 to 1.0, e.g., 0.10 for 10%).
12210    #[serde(default = "default_retainage_pct")]
12211    pub default_percentage: f64,
12212}
12213
12214fn default_retainage_pct() -> f64 {
12215    0.10
12216}
12217
12218impl Default for RetainageSchemaConfig {
12219    fn default() -> Self {
12220        Self {
12221            enabled: false,
12222            default_percentage: default_retainage_pct(),
12223        }
12224    }
12225}
12226
12227/// Earned value management (EVM) configuration.
12228#[derive(Debug, Clone, Serialize, Deserialize)]
12229pub struct EarnedValueSchemaConfig {
12230    /// Whether EVM metrics are generated.
12231    #[serde(default = "default_true")]
12232    pub enabled: bool,
12233    /// Measurement frequency: "weekly", "biweekly", "monthly".
12234    #[serde(default = "default_evm_frequency")]
12235    pub frequency: String,
12236}
12237
12238fn default_evm_frequency() -> String {
12239    "monthly".to_string()
12240}
12241
12242impl Default for EarnedValueSchemaConfig {
12243    fn default() -> Self {
12244        Self {
12245            enabled: true,
12246            frequency: default_evm_frequency(),
12247        }
12248    }
12249}
12250
12251// =============================================================================
12252// ESG / Sustainability Configuration
12253// =============================================================================
12254
12255/// Top-level ESG / sustainability reporting configuration.
12256#[derive(Debug, Clone, Serialize, Deserialize)]
12257pub struct EsgConfig {
12258    /// Whether ESG generation is enabled.
12259    #[serde(default)]
12260    pub enabled: bool,
12261    /// Environmental metrics (emissions, energy, water, waste).
12262    #[serde(default)]
12263    pub environmental: EnvironmentalConfig,
12264    /// Social metrics (diversity, pay equity, safety).
12265    #[serde(default)]
12266    pub social: SocialConfig,
12267    /// Governance metrics (board composition, ethics, compliance).
12268    #[serde(default)]
12269    pub governance: GovernanceSchemaConfig,
12270    /// Supply-chain ESG assessment settings.
12271    #[serde(default)]
12272    pub supply_chain_esg: SupplyChainEsgConfig,
12273    /// ESG reporting / disclosure framework settings.
12274    #[serde(default)]
12275    pub reporting: EsgReportingConfig,
12276    /// Climate scenario analysis settings.
12277    #[serde(default)]
12278    pub climate_scenarios: ClimateScenarioConfig,
12279    /// Anomaly injection rate for ESG data (0.0 to 1.0).
12280    #[serde(default = "default_esg_anomaly_rate")]
12281    pub anomaly_rate: f64,
12282}
12283
12284fn default_esg_anomaly_rate() -> f64 {
12285    0.02
12286}
12287
12288impl Default for EsgConfig {
12289    fn default() -> Self {
12290        Self {
12291            enabled: false,
12292            environmental: EnvironmentalConfig::default(),
12293            social: SocialConfig::default(),
12294            governance: GovernanceSchemaConfig::default(),
12295            supply_chain_esg: SupplyChainEsgConfig::default(),
12296            reporting: EsgReportingConfig::default(),
12297            climate_scenarios: ClimateScenarioConfig::default(),
12298            anomaly_rate: default_esg_anomaly_rate(),
12299        }
12300    }
12301}
12302
12303/// Country pack configuration.
12304///
12305/// Controls where to load additional country packs and per-country overrides.
12306/// When omitted, only the built-in packs (_default, US, DE, GB) are used.
12307#[derive(Debug, Clone, Serialize, Deserialize, Default)]
12308pub struct CountryPacksSchemaConfig {
12309    /// Optional directory containing additional `*.json` country packs.
12310    #[serde(default)]
12311    pub external_dir: Option<PathBuf>,
12312    /// Per-country overrides applied after loading.
12313    /// Keys are ISO 3166-1 alpha-2 codes; values are partial JSON objects
12314    /// that are deep-merged on top of the loaded pack.
12315    #[serde(default)]
12316    pub overrides: std::collections::HashMap<String, serde_json::Value>,
12317}
12318
12319/// Environmental metrics configuration.
12320#[derive(Debug, Clone, Serialize, Deserialize)]
12321pub struct EnvironmentalConfig {
12322    /// Whether environmental metrics are generated.
12323    #[serde(default = "default_true")]
12324    pub enabled: bool,
12325    /// Scope 1 (direct) emission generation settings.
12326    #[serde(default)]
12327    pub scope1: EmissionScopeConfig,
12328    /// Scope 2 (purchased energy) emission generation settings.
12329    #[serde(default)]
12330    pub scope2: EmissionScopeConfig,
12331    /// Scope 3 (value chain) emission generation settings.
12332    #[serde(default)]
12333    pub scope3: Scope3Config,
12334    /// Energy consumption tracking settings.
12335    #[serde(default)]
12336    pub energy: EnergySchemaConfig,
12337    /// Water usage tracking settings.
12338    #[serde(default)]
12339    pub water: WaterSchemaConfig,
12340    /// Waste management tracking settings.
12341    #[serde(default)]
12342    pub waste: WasteSchemaConfig,
12343}
12344
12345impl Default for EnvironmentalConfig {
12346    fn default() -> Self {
12347        Self {
12348            enabled: true,
12349            scope1: EmissionScopeConfig::default(),
12350            scope2: EmissionScopeConfig::default(),
12351            scope3: Scope3Config::default(),
12352            energy: EnergySchemaConfig::default(),
12353            water: WaterSchemaConfig::default(),
12354            waste: WasteSchemaConfig::default(),
12355        }
12356    }
12357}
12358
12359/// Configuration for a single emission scope (Scope 1 or 2).
12360#[derive(Debug, Clone, Serialize, Deserialize)]
12361pub struct EmissionScopeConfig {
12362    /// Whether this scope is enabled.
12363    #[serde(default = "default_true")]
12364    pub enabled: bool,
12365    /// Emission factor region (e.g., "US", "EU", "global").
12366    #[serde(default = "default_emission_region")]
12367    pub factor_region: String,
12368}
12369
12370fn default_emission_region() -> String {
12371    "US".to_string()
12372}
12373
12374impl Default for EmissionScopeConfig {
12375    fn default() -> Self {
12376        Self {
12377            enabled: true,
12378            factor_region: default_emission_region(),
12379        }
12380    }
12381}
12382
12383/// Scope 3 (value chain) emission configuration.
12384#[derive(Debug, Clone, Serialize, Deserialize)]
12385pub struct Scope3Config {
12386    /// Whether Scope 3 emissions are generated.
12387    #[serde(default = "default_true")]
12388    pub enabled: bool,
12389    /// Categories to include (e.g., "purchased_goods", "business_travel", "commuting").
12390    #[serde(default = "default_scope3_categories")]
12391    pub categories: Vec<String>,
12392    /// Spend-based emission intensity (kg CO2e per USD).
12393    #[serde(default = "default_spend_intensity")]
12394    pub default_spend_intensity_kg_per_usd: f64,
12395}
12396
12397fn default_scope3_categories() -> Vec<String> {
12398    vec![
12399        "purchased_goods".to_string(),
12400        "business_travel".to_string(),
12401        "employee_commuting".to_string(),
12402    ]
12403}
12404
12405fn default_spend_intensity() -> f64 {
12406    0.5
12407}
12408
12409impl Default for Scope3Config {
12410    fn default() -> Self {
12411        Self {
12412            enabled: true,
12413            categories: default_scope3_categories(),
12414            default_spend_intensity_kg_per_usd: default_spend_intensity(),
12415        }
12416    }
12417}
12418
12419/// Energy consumption configuration.
12420#[derive(Debug, Clone, Serialize, Deserialize)]
12421pub struct EnergySchemaConfig {
12422    /// Whether energy consumption tracking is enabled.
12423    #[serde(default = "default_true")]
12424    pub enabled: bool,
12425    /// Number of facilities to generate.
12426    #[serde(default = "default_facility_count")]
12427    pub facility_count: u32,
12428    /// Target percentage of energy from renewable sources (0.0 to 1.0).
12429    #[serde(default = "default_renewable_target")]
12430    pub renewable_target: f64,
12431}
12432
12433fn default_facility_count() -> u32 {
12434    5
12435}
12436
12437fn default_renewable_target() -> f64 {
12438    0.30
12439}
12440
12441impl Default for EnergySchemaConfig {
12442    fn default() -> Self {
12443        Self {
12444            enabled: true,
12445            facility_count: default_facility_count(),
12446            renewable_target: default_renewable_target(),
12447        }
12448    }
12449}
12450
12451/// Water usage configuration.
12452#[derive(Debug, Clone, Serialize, Deserialize)]
12453pub struct WaterSchemaConfig {
12454    /// Whether water usage tracking is enabled.
12455    #[serde(default = "default_true")]
12456    pub enabled: bool,
12457    /// Number of facilities with water tracking.
12458    #[serde(default = "default_water_facility_count")]
12459    pub facility_count: u32,
12460}
12461
12462fn default_water_facility_count() -> u32 {
12463    3
12464}
12465
12466impl Default for WaterSchemaConfig {
12467    fn default() -> Self {
12468        Self {
12469            enabled: true,
12470            facility_count: default_water_facility_count(),
12471        }
12472    }
12473}
12474
12475/// Waste management configuration.
12476#[derive(Debug, Clone, Serialize, Deserialize)]
12477pub struct WasteSchemaConfig {
12478    /// Whether waste tracking is enabled.
12479    #[serde(default = "default_true")]
12480    pub enabled: bool,
12481    /// Target diversion rate (0.0 to 1.0).
12482    #[serde(default = "default_diversion_target")]
12483    pub diversion_target: f64,
12484}
12485
12486fn default_diversion_target() -> f64 {
12487    0.50
12488}
12489
12490impl Default for WasteSchemaConfig {
12491    fn default() -> Self {
12492        Self {
12493            enabled: true,
12494            diversion_target: default_diversion_target(),
12495        }
12496    }
12497}
12498
12499/// Social metrics configuration.
12500#[derive(Debug, Clone, Serialize, Deserialize)]
12501pub struct SocialConfig {
12502    /// Whether social metrics are generated.
12503    #[serde(default = "default_true")]
12504    pub enabled: bool,
12505    /// Workforce diversity tracking settings.
12506    #[serde(default)]
12507    pub diversity: DiversitySchemaConfig,
12508    /// Pay equity analysis settings.
12509    #[serde(default)]
12510    pub pay_equity: PayEquitySchemaConfig,
12511    /// Safety incident and metrics settings.
12512    #[serde(default)]
12513    pub safety: SafetySchemaConfig,
12514}
12515
12516impl Default for SocialConfig {
12517    fn default() -> Self {
12518        Self {
12519            enabled: true,
12520            diversity: DiversitySchemaConfig::default(),
12521            pay_equity: PayEquitySchemaConfig::default(),
12522            safety: SafetySchemaConfig::default(),
12523        }
12524    }
12525}
12526
12527/// Workforce diversity configuration.
12528#[derive(Debug, Clone, Serialize, Deserialize)]
12529pub struct DiversitySchemaConfig {
12530    /// Whether diversity metrics are generated.
12531    #[serde(default = "default_true")]
12532    pub enabled: bool,
12533    /// Dimensions to track (e.g., "gender", "ethnicity", "age_group").
12534    #[serde(default = "default_diversity_dimensions")]
12535    pub dimensions: Vec<String>,
12536}
12537
12538fn default_diversity_dimensions() -> Vec<String> {
12539    vec![
12540        "gender".to_string(),
12541        "ethnicity".to_string(),
12542        "age_group".to_string(),
12543    ]
12544}
12545
12546impl Default for DiversitySchemaConfig {
12547    fn default() -> Self {
12548        Self {
12549            enabled: true,
12550            dimensions: default_diversity_dimensions(),
12551        }
12552    }
12553}
12554
12555/// Pay equity analysis configuration.
12556#[derive(Debug, Clone, Serialize, Deserialize)]
12557pub struct PayEquitySchemaConfig {
12558    /// Whether pay equity analysis is generated.
12559    #[serde(default = "default_true")]
12560    pub enabled: bool,
12561    /// Target pay gap threshold for flagging (e.g., 0.05 = 5% gap).
12562    #[serde(default = "default_pay_gap_threshold")]
12563    pub gap_threshold: f64,
12564}
12565
12566fn default_pay_gap_threshold() -> f64 {
12567    0.05
12568}
12569
12570impl Default for PayEquitySchemaConfig {
12571    fn default() -> Self {
12572        Self {
12573            enabled: true,
12574            gap_threshold: default_pay_gap_threshold(),
12575        }
12576    }
12577}
12578
12579/// Safety metrics configuration.
12580#[derive(Debug, Clone, Serialize, Deserialize)]
12581pub struct SafetySchemaConfig {
12582    /// Whether safety metrics are generated.
12583    #[serde(default = "default_true")]
12584    pub enabled: bool,
12585    /// Average annual recordable incidents per 200,000 hours.
12586    #[serde(default = "default_trir_target")]
12587    pub target_trir: f64,
12588    /// Number of safety incidents to generate.
12589    #[serde(default = "default_incident_count")]
12590    pub incident_count: u32,
12591}
12592
12593fn default_trir_target() -> f64 {
12594    2.5
12595}
12596
12597fn default_incident_count() -> u32 {
12598    20
12599}
12600
12601impl Default for SafetySchemaConfig {
12602    fn default() -> Self {
12603        Self {
12604            enabled: true,
12605            target_trir: default_trir_target(),
12606            incident_count: default_incident_count(),
12607        }
12608    }
12609}
12610
12611/// Governance metrics configuration.
12612#[derive(Debug, Clone, Serialize, Deserialize)]
12613pub struct GovernanceSchemaConfig {
12614    /// Whether governance metrics are generated.
12615    #[serde(default = "default_true")]
12616    pub enabled: bool,
12617    /// Number of board members.
12618    #[serde(default = "default_board_size")]
12619    pub board_size: u32,
12620    /// Target independent director ratio (0.0 to 1.0).
12621    #[serde(default = "default_independence_target")]
12622    pub independence_target: f64,
12623}
12624
12625fn default_board_size() -> u32 {
12626    11
12627}
12628
12629fn default_independence_target() -> f64 {
12630    0.67
12631}
12632
12633impl Default for GovernanceSchemaConfig {
12634    fn default() -> Self {
12635        Self {
12636            enabled: true,
12637            board_size: default_board_size(),
12638            independence_target: default_independence_target(),
12639        }
12640    }
12641}
12642
12643/// Supply-chain ESG assessment configuration.
12644#[derive(Debug, Clone, Serialize, Deserialize)]
12645pub struct SupplyChainEsgConfig {
12646    /// Whether supply chain ESG assessments are generated.
12647    #[serde(default = "default_true")]
12648    pub enabled: bool,
12649    /// Proportion of vendors to assess (0.0 to 1.0).
12650    #[serde(default = "default_assessment_coverage")]
12651    pub assessment_coverage: f64,
12652    /// High-risk country codes for automatic flagging.
12653    #[serde(default = "default_high_risk_countries")]
12654    pub high_risk_countries: Vec<String>,
12655}
12656
12657fn default_assessment_coverage() -> f64 {
12658    0.80
12659}
12660
12661fn default_high_risk_countries() -> Vec<String> {
12662    vec!["CN".to_string(), "BD".to_string(), "MM".to_string()]
12663}
12664
12665impl Default for SupplyChainEsgConfig {
12666    fn default() -> Self {
12667        Self {
12668            enabled: true,
12669            assessment_coverage: default_assessment_coverage(),
12670            high_risk_countries: default_high_risk_countries(),
12671        }
12672    }
12673}
12674
12675/// ESG reporting / disclosure framework configuration.
12676#[derive(Debug, Clone, Serialize, Deserialize)]
12677pub struct EsgReportingConfig {
12678    /// Whether ESG disclosures are generated.
12679    #[serde(default = "default_true")]
12680    pub enabled: bool,
12681    /// Frameworks to generate disclosures for.
12682    #[serde(default = "default_esg_frameworks")]
12683    pub frameworks: Vec<String>,
12684    /// Whether materiality assessment is performed.
12685    #[serde(default = "default_true")]
12686    pub materiality_assessment: bool,
12687    /// Materiality threshold for impact dimension (0.0 to 1.0).
12688    #[serde(default = "default_materiality_threshold")]
12689    pub impact_threshold: f64,
12690    /// Materiality threshold for financial dimension (0.0 to 1.0).
12691    #[serde(default = "default_materiality_threshold")]
12692    pub financial_threshold: f64,
12693}
12694
12695fn default_esg_frameworks() -> Vec<String> {
12696    vec!["GRI".to_string(), "ESRS".to_string()]
12697}
12698
12699fn default_materiality_threshold() -> f64 {
12700    0.6
12701}
12702
12703impl Default for EsgReportingConfig {
12704    fn default() -> Self {
12705        Self {
12706            enabled: true,
12707            frameworks: default_esg_frameworks(),
12708            materiality_assessment: true,
12709            impact_threshold: default_materiality_threshold(),
12710            financial_threshold: default_materiality_threshold(),
12711        }
12712    }
12713}
12714
12715/// Climate scenario analysis configuration.
12716#[derive(Debug, Clone, Serialize, Deserialize)]
12717pub struct ClimateScenarioConfig {
12718    /// Whether climate scenario analysis is generated.
12719    #[serde(default)]
12720    pub enabled: bool,
12721    /// Scenarios to model (e.g., "net_zero_2050", "stated_policies", "current_trajectory").
12722    #[serde(default = "default_climate_scenarios")]
12723    pub scenarios: Vec<String>,
12724    /// Time horizons in years to project.
12725    #[serde(default = "default_time_horizons")]
12726    pub time_horizons: Vec<u32>,
12727}
12728
12729fn default_climate_scenarios() -> Vec<String> {
12730    vec![
12731        "net_zero_2050".to_string(),
12732        "stated_policies".to_string(),
12733        "current_trajectory".to_string(),
12734    ]
12735}
12736
12737fn default_time_horizons() -> Vec<u32> {
12738    vec![5, 10, 30]
12739}
12740
12741impl Default for ClimateScenarioConfig {
12742    fn default() -> Self {
12743        Self {
12744            enabled: false,
12745            scenarios: default_climate_scenarios(),
12746            time_horizons: default_time_horizons(),
12747        }
12748    }
12749}
12750
12751// ===== Counterfactual Simulation Scenarios =====
12752
12753/// Configuration for counterfactual simulation scenarios.
12754#[derive(Debug, Clone, Serialize, Deserialize, Default)]
12755pub struct ScenariosConfig {
12756    /// Whether scenario generation is enabled.
12757    #[serde(default)]
12758    pub enabled: bool,
12759    /// List of scenario definitions.
12760    #[serde(default)]
12761    pub scenarios: Vec<ScenarioSchemaConfig>,
12762    /// Causal model configuration.
12763    #[serde(default)]
12764    pub causal_model: CausalModelSchemaConfig,
12765    /// Default settings applied to all scenarios.
12766    #[serde(default)]
12767    pub defaults: ScenarioDefaultsConfig,
12768    /// Generate counterfactual (original, mutated) JE pairs for ML training.
12769    /// When true, the orchestrator produces paired clean/anomalous journal entries.
12770    #[serde(default)]
12771    pub generate_counterfactuals: bool,
12772}
12773
12774/// A single scenario definition in the config.
12775#[derive(Debug, Clone, Serialize, Deserialize)]
12776pub struct ScenarioSchemaConfig {
12777    /// Scenario name (must be unique).
12778    pub name: String,
12779    /// Human-readable description.
12780    #[serde(default)]
12781    pub description: String,
12782    /// Tags for categorization.
12783    #[serde(default)]
12784    pub tags: Vec<String>,
12785    /// Base scenario name (None = default config).
12786    pub base: Option<String>,
12787    /// IFRS 9-style probability weight.
12788    pub probability_weight: Option<f64>,
12789    /// List of interventions to apply.
12790    #[serde(default)]
12791    pub interventions: Vec<InterventionSchemaConfig>,
12792    /// Constraint overrides for this scenario.
12793    #[serde(default)]
12794    pub constraints: ScenarioConstraintsSchemaConfig,
12795    /// Output configuration for this scenario.
12796    #[serde(default)]
12797    pub output: ScenarioOutputSchemaConfig,
12798    /// Arbitrary metadata.
12799    #[serde(default)]
12800    pub metadata: std::collections::HashMap<String, String>,
12801}
12802
12803/// An intervention definition in the config.
12804#[derive(Debug, Clone, Serialize, Deserialize)]
12805pub struct InterventionSchemaConfig {
12806    /// Intervention type and parameters (flattened tagged enum).
12807    #[serde(flatten)]
12808    pub intervention_type: serde_json::Value,
12809    /// Timing configuration.
12810    #[serde(default)]
12811    pub timing: InterventionTimingSchemaConfig,
12812    /// Human-readable label.
12813    pub label: Option<String>,
12814    /// Priority for conflict resolution (higher wins).
12815    #[serde(default)]
12816    pub priority: u32,
12817}
12818
12819/// Timing configuration for an intervention.
12820#[derive(Debug, Clone, Serialize, Deserialize)]
12821pub struct InterventionTimingSchemaConfig {
12822    /// Month offset from start (1-indexed).
12823    #[serde(default = "default_start_month")]
12824    pub start_month: u32,
12825    /// Duration in months.
12826    pub duration_months: Option<u32>,
12827    /// Onset type: "sudden", "gradual", "oscillating", "custom".
12828    #[serde(default = "default_onset")]
12829    pub onset: String,
12830    /// Ramp period in months.
12831    pub ramp_months: Option<u32>,
12832}
12833
12834fn default_start_month() -> u32 {
12835    1
12836}
12837
12838fn default_onset() -> String {
12839    "sudden".to_string()
12840}
12841
12842impl Default for InterventionTimingSchemaConfig {
12843    fn default() -> Self {
12844        Self {
12845            start_month: 1,
12846            duration_months: None,
12847            onset: "sudden".to_string(),
12848            ramp_months: None,
12849        }
12850    }
12851}
12852
12853/// Scenario constraint overrides.
12854#[derive(Debug, Clone, Serialize, Deserialize)]
12855pub struct ScenarioConstraintsSchemaConfig {
12856    #[serde(default = "default_true")]
12857    pub preserve_accounting_identity: bool,
12858    #[serde(default = "default_true")]
12859    pub preserve_document_chains: bool,
12860    #[serde(default = "default_true")]
12861    pub preserve_period_close: bool,
12862    #[serde(default = "default_true")]
12863    pub preserve_balance_coherence: bool,
12864    #[serde(default)]
12865    pub custom: Vec<CustomConstraintSchemaConfig>,
12866}
12867
12868impl Default for ScenarioConstraintsSchemaConfig {
12869    fn default() -> Self {
12870        Self {
12871            preserve_accounting_identity: true,
12872            preserve_document_chains: true,
12873            preserve_period_close: true,
12874            preserve_balance_coherence: true,
12875            custom: Vec::new(),
12876        }
12877    }
12878}
12879
12880/// Custom constraint in config.
12881#[derive(Debug, Clone, Serialize, Deserialize)]
12882pub struct CustomConstraintSchemaConfig {
12883    pub config_path: String,
12884    pub min: Option<f64>,
12885    pub max: Option<f64>,
12886    #[serde(default)]
12887    pub description: String,
12888}
12889
12890/// Output configuration for a scenario.
12891#[derive(Debug, Clone, Serialize, Deserialize)]
12892pub struct ScenarioOutputSchemaConfig {
12893    #[serde(default = "default_true")]
12894    pub paired: bool,
12895    #[serde(default = "default_diff_formats_schema")]
12896    pub diff_formats: Vec<String>,
12897    #[serde(default)]
12898    pub diff_scope: Vec<String>,
12899}
12900
12901fn default_diff_formats_schema() -> Vec<String> {
12902    vec!["summary".to_string(), "aggregate".to_string()]
12903}
12904
12905impl Default for ScenarioOutputSchemaConfig {
12906    fn default() -> Self {
12907        Self {
12908            paired: true,
12909            diff_formats: default_diff_formats_schema(),
12910            diff_scope: Vec::new(),
12911        }
12912    }
12913}
12914
12915/// Causal model configuration.
12916#[derive(Debug, Clone, Serialize, Deserialize)]
12917pub struct CausalModelSchemaConfig {
12918    /// Preset name: "default", "minimal", or "custom".
12919    #[serde(default = "default_causal_preset")]
12920    pub preset: String,
12921    /// Custom nodes (merged with preset).
12922    #[serde(default)]
12923    pub nodes: Vec<serde_json::Value>,
12924    /// Custom edges (merged with preset).
12925    #[serde(default)]
12926    pub edges: Vec<serde_json::Value>,
12927}
12928
12929fn default_causal_preset() -> String {
12930    "default".to_string()
12931}
12932
12933impl Default for CausalModelSchemaConfig {
12934    fn default() -> Self {
12935        Self {
12936            preset: "default".to_string(),
12937            nodes: Vec::new(),
12938            edges: Vec::new(),
12939        }
12940    }
12941}
12942
12943/// Default settings applied to all scenarios.
12944#[derive(Debug, Clone, Serialize, Deserialize, Default)]
12945pub struct ScenarioDefaultsConfig {
12946    #[serde(default)]
12947    pub constraints: ScenarioConstraintsSchemaConfig,
12948    #[serde(default)]
12949    pub output: ScenarioOutputSchemaConfig,
12950}
12951
12952// =====================================================================
12953// Compliance Regulations Framework Configuration
12954// =====================================================================
12955
12956/// Top-level configuration for the compliance regulations framework.
12957///
12958/// Controls standards registry, jurisdiction profiles, temporal versioning,
12959/// audit procedure templates, compliance graph integration, and output settings.
12960///
12961/// # Example
12962///
12963/// ```yaml
12964/// compliance_regulations:
12965///   enabled: true
12966///   jurisdictions: [US, DE, GB]
12967///   reference_date: "2025-06-30"
12968///   standards_selection:
12969///     categories: [accounting, auditing, regulatory]
12970///     include: ["IFRS-16", "ASC-606"]
12971///   audit_procedures:
12972///     enabled: true
12973///     procedures_per_standard: 3
12974///   findings:
12975///     enabled: true
12976///     finding_rate: 0.05
12977///   filings:
12978///     enabled: true
12979///   graph:
12980///     enabled: true
12981///     include_compliance_nodes: true
12982///     include_compliance_edges: true
12983/// ```
12984#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12985pub struct ComplianceRegulationsConfig {
12986    /// Master switch for the compliance regulations framework.
12987    #[serde(default)]
12988    pub enabled: bool,
12989    /// Jurisdictions to generate compliance data for (ISO 3166-1 alpha-2 codes).
12990    /// If empty, inferred from company countries in the config.
12991    #[serde(default)]
12992    pub jurisdictions: Vec<String>,
12993    /// Reference date for temporal standard resolution (YYYY-MM-DD).
12994    /// Defaults to the global start_date if not set.
12995    #[serde(default)]
12996    pub reference_date: Option<String>,
12997    /// Standards selection filters.
12998    #[serde(default)]
12999    pub standards_selection: StandardsSelectionConfig,
13000    /// Audit procedure generation settings.
13001    #[serde(default)]
13002    pub audit_procedures: AuditProcedureGenConfig,
13003    /// Compliance finding generation settings.
13004    #[serde(default)]
13005    pub findings: ComplianceFindingGenConfig,
13006    /// Regulatory filing generation settings.
13007    #[serde(default)]
13008    pub filings: ComplianceFilingGenConfig,
13009    /// Compliance graph integration settings.
13010    #[serde(default)]
13011    pub graph: ComplianceGraphConfig,
13012    /// Output settings for compliance-specific files.
13013    #[serde(default)]
13014    pub output: ComplianceOutputConfig,
13015}
13016
13017/// Filters which standards are included in the generation.
13018#[derive(Debug, Clone, Default, Serialize, Deserialize)]
13019pub struct StandardsSelectionConfig {
13020    /// Standard categories to include (accounting, auditing, regulatory, tax, esg).
13021    /// Empty = all categories.
13022    #[serde(default)]
13023    pub categories: Vec<String>,
13024    /// Explicit standard IDs to include (e.g., ["IFRS-16", "ASC-606"]).
13025    /// When non-empty, only these standards (plus mandatory ones for selected jurisdictions) are used.
13026    #[serde(default)]
13027    pub include: Vec<String>,
13028    /// Standard IDs to exclude.
13029    #[serde(default)]
13030    pub exclude: Vec<String>,
13031    /// Include superseded standards in the output (for historical analysis).
13032    #[serde(default)]
13033    pub include_superseded: bool,
13034}
13035
13036/// Configuration for audit procedure template generation.
13037#[derive(Debug, Clone, Serialize, Deserialize)]
13038pub struct AuditProcedureGenConfig {
13039    /// Whether audit procedure generation is enabled.
13040    #[serde(default)]
13041    pub enabled: bool,
13042    /// Number of procedures to generate per applicable standard.
13043    #[serde(default = "default_procedures_per_standard")]
13044    pub procedures_per_standard: usize,
13045    /// Sampling methodology: "statistical", "non_statistical", "mixed".
13046    #[serde(default = "default_sampling_method")]
13047    pub sampling_method: String,
13048    /// Confidence level for statistical sampling (0.0-1.0).
13049    #[serde(default = "default_confidence_level")]
13050    pub confidence_level: f64,
13051    /// Tolerable misstatement rate for sampling (0.0-1.0).
13052    #[serde(default = "default_tolerable_misstatement")]
13053    pub tolerable_misstatement: f64,
13054}
13055
13056fn default_procedures_per_standard() -> usize {
13057    3
13058}
13059
13060fn default_sampling_method() -> String {
13061    "statistical".to_string()
13062}
13063
13064fn default_confidence_level() -> f64 {
13065    0.95
13066}
13067
13068fn default_tolerable_misstatement() -> f64 {
13069    0.05
13070}
13071
13072impl Default for AuditProcedureGenConfig {
13073    fn default() -> Self {
13074        Self {
13075            enabled: false,
13076            procedures_per_standard: default_procedures_per_standard(),
13077            sampling_method: default_sampling_method(),
13078            confidence_level: default_confidence_level(),
13079            tolerable_misstatement: default_tolerable_misstatement(),
13080        }
13081    }
13082}
13083
13084/// Configuration for compliance finding generation.
13085#[derive(Debug, Clone, Serialize, Deserialize)]
13086pub struct ComplianceFindingGenConfig {
13087    /// Whether finding generation is enabled.
13088    #[serde(default)]
13089    pub enabled: bool,
13090    /// Rate of findings per audit procedure (0.0-1.0).
13091    #[serde(default = "default_finding_rate")]
13092    pub finding_rate: f64,
13093    /// Rate of material weakness findings among all findings (0.0-1.0).
13094    #[serde(default = "default_cr_material_weakness_rate")]
13095    pub material_weakness_rate: f64,
13096    /// Rate of significant deficiency findings among all findings (0.0-1.0).
13097    #[serde(default = "default_cr_significant_deficiency_rate")]
13098    pub significant_deficiency_rate: f64,
13099    /// Whether to generate remediation plans for findings.
13100    #[serde(default = "default_true")]
13101    pub generate_remediation: bool,
13102}
13103
13104fn default_finding_rate() -> f64 {
13105    0.05
13106}
13107
13108fn default_cr_material_weakness_rate() -> f64 {
13109    0.02
13110}
13111
13112fn default_cr_significant_deficiency_rate() -> f64 {
13113    0.08
13114}
13115
13116impl Default for ComplianceFindingGenConfig {
13117    fn default() -> Self {
13118        Self {
13119            enabled: false,
13120            finding_rate: default_finding_rate(),
13121            material_weakness_rate: default_cr_material_weakness_rate(),
13122            significant_deficiency_rate: default_cr_significant_deficiency_rate(),
13123            generate_remediation: true,
13124        }
13125    }
13126}
13127
13128/// Configuration for regulatory filing generation.
13129#[derive(Debug, Clone, Serialize, Deserialize)]
13130pub struct ComplianceFilingGenConfig {
13131    /// Whether filing generation is enabled.
13132    #[serde(default)]
13133    pub enabled: bool,
13134    /// Filing types to include (e.g., ["10-K", "10-Q", "Jahresabschluss"]).
13135    /// Empty = all applicable filings for the selected jurisdictions.
13136    #[serde(default)]
13137    pub filing_types: Vec<String>,
13138    /// Generate filing status progression (draft → filed → accepted).
13139    #[serde(default = "default_true")]
13140    pub generate_status_progression: bool,
13141}
13142
13143impl Default for ComplianceFilingGenConfig {
13144    fn default() -> Self {
13145        Self {
13146            enabled: false,
13147            filing_types: Vec::new(),
13148            generate_status_progression: true,
13149        }
13150    }
13151}
13152
13153/// Configuration for compliance graph integration.
13154#[derive(Debug, Clone, Serialize, Deserialize)]
13155pub struct ComplianceGraphConfig {
13156    /// Whether compliance graph integration is enabled.
13157    #[serde(default)]
13158    pub enabled: bool,
13159    /// Include compliance nodes (Standard, Regulation, Jurisdiction, etc.).
13160    #[serde(default = "default_true")]
13161    pub include_compliance_nodes: bool,
13162    /// Include compliance edges (MapsToStandard, TestsControl, etc.).
13163    #[serde(default = "default_true")]
13164    pub include_compliance_edges: bool,
13165    /// Include cross-reference edges between standards.
13166    #[serde(default = "default_true")]
13167    pub include_cross_references: bool,
13168    /// Include temporal supersession edges.
13169    #[serde(default)]
13170    pub include_supersession_edges: bool,
13171    /// Include edges linking standards to the GL account types they govern.
13172    #[serde(default = "default_true")]
13173    pub include_account_links: bool,
13174    /// Include edges linking standards to the internal controls that implement them.
13175    #[serde(default = "default_true")]
13176    pub include_control_links: bool,
13177    /// Include edges linking filings and jurisdictions to the originating company.
13178    #[serde(default = "default_true")]
13179    pub include_company_links: bool,
13180}
13181
13182impl Default for ComplianceGraphConfig {
13183    fn default() -> Self {
13184        Self {
13185            enabled: false,
13186            include_compliance_nodes: true,
13187            include_compliance_edges: true,
13188            include_cross_references: true,
13189            include_supersession_edges: false,
13190            include_account_links: true,
13191            include_control_links: true,
13192            include_company_links: true,
13193        }
13194    }
13195}
13196
13197/// Output settings for compliance-specific data files.
13198#[derive(Debug, Clone, Serialize, Deserialize)]
13199pub struct ComplianceOutputConfig {
13200    /// Export the standards registry catalog.
13201    #[serde(default = "default_true")]
13202    pub export_registry: bool,
13203    /// Export jurisdiction profiles.
13204    #[serde(default = "default_true")]
13205    pub export_jurisdictions: bool,
13206    /// Export cross-reference map.
13207    #[serde(default = "default_true")]
13208    pub export_cross_references: bool,
13209    /// Export temporal version history.
13210    #[serde(default)]
13211    pub export_version_history: bool,
13212}
13213
13214impl Default for ComplianceOutputConfig {
13215    fn default() -> Self {
13216        Self {
13217            export_registry: true,
13218            export_jurisdictions: true,
13219            export_cross_references: true,
13220            export_version_history: false,
13221        }
13222    }
13223}
13224
13225#[cfg(test)]
13226#[allow(clippy::unwrap_used)]
13227mod tests {
13228    use super::*;
13229    use crate::presets::demo_preset;
13230
13231    // ==========================================================================
13232    // Serialization/Deserialization Tests
13233    // ==========================================================================
13234
13235    #[test]
13236    fn test_config_yaml_roundtrip() {
13237        let config = demo_preset();
13238        let yaml = serde_yaml::to_string(&config).expect("Failed to serialize to YAML");
13239        let deserialized: GeneratorConfig =
13240            serde_yaml::from_str(&yaml).expect("Failed to deserialize from YAML");
13241
13242        assert_eq!(
13243            config.global.period_months,
13244            deserialized.global.period_months
13245        );
13246        assert_eq!(config.global.industry, deserialized.global.industry);
13247        assert_eq!(config.companies.len(), deserialized.companies.len());
13248        assert_eq!(config.companies[0].code, deserialized.companies[0].code);
13249    }
13250
13251    #[test]
13252    fn test_config_json_roundtrip() {
13253        // Create a config without infinity values (JSON can't serialize f64::INFINITY)
13254        let mut config = demo_preset();
13255        // Replace infinity with a large but finite value for JSON compatibility
13256        config.master_data.employees.approval_limits.executive = 1e12;
13257
13258        let json = serde_json::to_string(&config).expect("Failed to serialize to JSON");
13259        let deserialized: GeneratorConfig =
13260            serde_json::from_str(&json).expect("Failed to deserialize from JSON");
13261
13262        assert_eq!(
13263            config.global.period_months,
13264            deserialized.global.period_months
13265        );
13266        assert_eq!(config.global.industry, deserialized.global.industry);
13267        assert_eq!(config.companies.len(), deserialized.companies.len());
13268    }
13269
13270    #[test]
13271    fn test_transaction_volume_serialization() {
13272        // Test various transaction volumes serialize correctly
13273        let volumes = vec![
13274            (TransactionVolume::TenK, "ten_k"),
13275            (TransactionVolume::HundredK, "hundred_k"),
13276            (TransactionVolume::OneM, "one_m"),
13277            (TransactionVolume::TenM, "ten_m"),
13278            (TransactionVolume::HundredM, "hundred_m"),
13279        ];
13280
13281        for (volume, expected_key) in volumes {
13282            let json = serde_json::to_string(&volume).expect("Failed to serialize");
13283            assert!(
13284                json.contains(expected_key),
13285                "Expected {} in JSON: {}",
13286                expected_key,
13287                json
13288            );
13289        }
13290    }
13291
13292    #[test]
13293    fn test_transaction_volume_custom_serialization() {
13294        let volume = TransactionVolume::Custom(12345);
13295        let json = serde_json::to_string(&volume).expect("Failed to serialize");
13296        let deserialized: TransactionVolume =
13297            serde_json::from_str(&json).expect("Failed to deserialize");
13298        assert_eq!(deserialized.count(), 12345);
13299    }
13300
13301    #[test]
13302    fn test_output_mode_serialization() {
13303        let modes = vec![
13304            OutputMode::Streaming,
13305            OutputMode::FlatFile,
13306            OutputMode::Both,
13307        ];
13308
13309        for mode in modes {
13310            let json = serde_json::to_string(&mode).expect("Failed to serialize");
13311            let deserialized: OutputMode =
13312                serde_json::from_str(&json).expect("Failed to deserialize");
13313            assert!(format!("{:?}", mode) == format!("{:?}", deserialized));
13314        }
13315    }
13316
13317    #[test]
13318    fn test_file_format_serialization() {
13319        let formats = vec![
13320            FileFormat::Csv,
13321            FileFormat::Parquet,
13322            FileFormat::Json,
13323            FileFormat::JsonLines,
13324        ];
13325
13326        for format in formats {
13327            let json = serde_json::to_string(&format).expect("Failed to serialize");
13328            let deserialized: FileFormat =
13329                serde_json::from_str(&json).expect("Failed to deserialize");
13330            assert!(format!("{:?}", format) == format!("{:?}", deserialized));
13331        }
13332    }
13333
13334    #[test]
13335    fn test_compression_algorithm_serialization() {
13336        let algos = vec![
13337            CompressionAlgorithm::Gzip,
13338            CompressionAlgorithm::Zstd,
13339            CompressionAlgorithm::Lz4,
13340            CompressionAlgorithm::Snappy,
13341        ];
13342
13343        for algo in algos {
13344            let json = serde_json::to_string(&algo).expect("Failed to serialize");
13345            let deserialized: CompressionAlgorithm =
13346                serde_json::from_str(&json).expect("Failed to deserialize");
13347            assert!(format!("{:?}", algo) == format!("{:?}", deserialized));
13348        }
13349    }
13350
13351    #[test]
13352    fn test_transfer_pricing_method_serialization() {
13353        let methods = vec![
13354            TransferPricingMethod::CostPlus,
13355            TransferPricingMethod::ComparableUncontrolled,
13356            TransferPricingMethod::ResalePrice,
13357            TransferPricingMethod::TransactionalNetMargin,
13358            TransferPricingMethod::ProfitSplit,
13359        ];
13360
13361        for method in methods {
13362            let json = serde_json::to_string(&method).expect("Failed to serialize");
13363            let deserialized: TransferPricingMethod =
13364                serde_json::from_str(&json).expect("Failed to deserialize");
13365            assert!(format!("{:?}", method) == format!("{:?}", deserialized));
13366        }
13367    }
13368
13369    #[test]
13370    fn test_benford_exemption_serialization() {
13371        let exemptions = vec![
13372            BenfordExemption::Recurring,
13373            BenfordExemption::Payroll,
13374            BenfordExemption::FixedFees,
13375            BenfordExemption::RoundAmounts,
13376        ];
13377
13378        for exemption in exemptions {
13379            let json = serde_json::to_string(&exemption).expect("Failed to serialize");
13380            let deserialized: BenfordExemption =
13381                serde_json::from_str(&json).expect("Failed to deserialize");
13382            assert!(format!("{:?}", exemption) == format!("{:?}", deserialized));
13383        }
13384    }
13385
13386    // ==========================================================================
13387    // Default Value Tests
13388    // ==========================================================================
13389
13390    #[test]
13391    fn test_global_config_defaults() {
13392        let yaml = r#"
13393            industry: manufacturing
13394            start_date: "2024-01-01"
13395            period_months: 6
13396        "#;
13397        let config: GlobalConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13398        assert_eq!(config.group_currency, "USD");
13399        assert!(config.parallel);
13400        assert_eq!(config.worker_threads, 0);
13401        assert_eq!(config.memory_limit_mb, 0);
13402    }
13403
13404    #[test]
13405    fn test_fraud_config_defaults() {
13406        let config = FraudConfig::default();
13407        assert!(!config.enabled);
13408        assert_eq!(config.fraud_rate, 0.005);
13409        assert!(!config.clustering_enabled);
13410    }
13411
13412    #[test]
13413    fn test_internal_controls_config_defaults() {
13414        let config = InternalControlsConfig::default();
13415        assert!(!config.enabled);
13416        assert_eq!(config.exception_rate, 0.02);
13417        assert_eq!(config.sod_violation_rate, 0.01);
13418        assert!(config.export_control_master_data);
13419        assert_eq!(config.sox_materiality_threshold, 10000.0);
13420        // COSO fields
13421        assert!(config.coso_enabled);
13422        assert!(!config.include_entity_level_controls);
13423        assert_eq!(config.target_maturity_level, "mixed");
13424    }
13425
13426    #[test]
13427    fn test_output_config_defaults() {
13428        let config = OutputConfig::default();
13429        assert!(matches!(config.mode, OutputMode::FlatFile));
13430        assert_eq!(config.formats, vec![FileFormat::Parquet]);
13431        assert!(config.compression.enabled);
13432        assert!(matches!(
13433            config.compression.algorithm,
13434            CompressionAlgorithm::Zstd
13435        ));
13436        assert!(config.include_acdoca);
13437        assert!(!config.include_bseg);
13438        assert!(config.partition_by_period);
13439        assert!(!config.partition_by_company);
13440    }
13441
13442    #[test]
13443    fn test_approval_config_defaults() {
13444        let config = ApprovalConfig::default();
13445        assert!(!config.enabled);
13446        assert_eq!(config.auto_approve_threshold, 1000.0);
13447        assert_eq!(config.rejection_rate, 0.02);
13448        assert_eq!(config.revision_rate, 0.05);
13449        assert_eq!(config.average_approval_delay_hours, 4.0);
13450        assert_eq!(config.thresholds.len(), 4);
13451    }
13452
13453    #[test]
13454    fn test_p2p_flow_config_defaults() {
13455        let config = P2PFlowConfig::default();
13456        assert!(config.enabled);
13457        assert_eq!(config.three_way_match_rate, 0.95);
13458        assert_eq!(config.partial_delivery_rate, 0.15);
13459        assert_eq!(config.average_po_to_gr_days, 14);
13460    }
13461
13462    #[test]
13463    fn test_o2c_flow_config_defaults() {
13464        let config = O2CFlowConfig::default();
13465        assert!(config.enabled);
13466        assert_eq!(config.credit_check_failure_rate, 0.02);
13467        assert_eq!(config.return_rate, 0.03);
13468        assert_eq!(config.bad_debt_rate, 0.01);
13469    }
13470
13471    #[test]
13472    fn test_balance_config_defaults() {
13473        let config = BalanceConfig::default();
13474        assert!(!config.generate_opening_balances);
13475        assert!(config.generate_trial_balances);
13476        assert_eq!(config.target_gross_margin, 0.35);
13477        assert!(config.validate_balance_equation);
13478        assert!(config.reconcile_subledgers);
13479    }
13480
13481    // ==========================================================================
13482    // Partial Config Deserialization Tests
13483    // ==========================================================================
13484
13485    #[test]
13486    fn test_partial_config_with_defaults() {
13487        // Minimal config that should use all defaults
13488        let yaml = r#"
13489            global:
13490              industry: manufacturing
13491              start_date: "2024-01-01"
13492              period_months: 3
13493            companies:
13494              - code: "TEST"
13495                name: "Test Company"
13496                currency: "USD"
13497                country: "US"
13498                annual_transaction_volume: ten_k
13499            chart_of_accounts:
13500              complexity: small
13501            output:
13502              output_directory: "./output"
13503        "#;
13504
13505        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13506        assert_eq!(config.global.period_months, 3);
13507        assert_eq!(config.companies.len(), 1);
13508        assert!(!config.fraud.enabled); // Default
13509        assert!(!config.internal_controls.enabled); // Default
13510    }
13511
13512    #[test]
13513    fn test_config_with_fraud_enabled() {
13514        let yaml = r#"
13515            global:
13516              industry: retail
13517              start_date: "2024-01-01"
13518              period_months: 12
13519            companies:
13520              - code: "RETAIL"
13521                name: "Retail Co"
13522                currency: "USD"
13523                country: "US"
13524                annual_transaction_volume: hundred_k
13525            chart_of_accounts:
13526              complexity: medium
13527            output:
13528              output_directory: "./output"
13529            fraud:
13530              enabled: true
13531              fraud_rate: 0.05
13532              clustering_enabled: true
13533        "#;
13534
13535        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13536        assert!(config.fraud.enabled);
13537        assert_eq!(config.fraud.fraud_rate, 0.05);
13538        assert!(config.fraud.clustering_enabled);
13539    }
13540
13541    #[test]
13542    fn test_config_with_multiple_companies() {
13543        let yaml = r#"
13544            global:
13545              industry: manufacturing
13546              start_date: "2024-01-01"
13547              period_months: 6
13548            companies:
13549              - code: "HQ"
13550                name: "Headquarters"
13551                currency: "USD"
13552                country: "US"
13553                annual_transaction_volume: hundred_k
13554                volume_weight: 1.0
13555              - code: "EU"
13556                name: "European Subsidiary"
13557                currency: "EUR"
13558                country: "DE"
13559                annual_transaction_volume: hundred_k
13560                volume_weight: 0.5
13561              - code: "APAC"
13562                name: "Asia Pacific"
13563                currency: "JPY"
13564                country: "JP"
13565                annual_transaction_volume: ten_k
13566                volume_weight: 0.3
13567            chart_of_accounts:
13568              complexity: large
13569            output:
13570              output_directory: "./output"
13571        "#;
13572
13573        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13574        assert_eq!(config.companies.len(), 3);
13575        assert_eq!(config.companies[0].code, "HQ");
13576        assert_eq!(config.companies[1].currency, "EUR");
13577        assert_eq!(config.companies[2].volume_weight, 0.3);
13578    }
13579
13580    #[test]
13581    fn test_intercompany_config() {
13582        let yaml = r#"
13583            enabled: true
13584            ic_transaction_rate: 0.20
13585            transfer_pricing_method: cost_plus
13586            markup_percent: 0.08
13587            generate_matched_pairs: true
13588            generate_eliminations: true
13589        "#;
13590
13591        let config: IntercompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13592        assert!(config.enabled);
13593        assert_eq!(config.ic_transaction_rate, 0.20);
13594        assert!(matches!(
13595            config.transfer_pricing_method,
13596            TransferPricingMethod::CostPlus
13597        ));
13598        assert_eq!(config.markup_percent, 0.08);
13599        assert!(config.generate_eliminations);
13600    }
13601
13602    // ==========================================================================
13603    // Company Config Tests
13604    // ==========================================================================
13605
13606    #[test]
13607    fn test_company_config_defaults() {
13608        let yaml = r#"
13609            code: "TEST"
13610            name: "Test Company"
13611            currency: "USD"
13612            country: "US"
13613            annual_transaction_volume: ten_k
13614        "#;
13615
13616        let config: CompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13617        assert_eq!(config.fiscal_year_variant, "K4"); // Default
13618        assert_eq!(config.volume_weight, 1.0); // Default
13619    }
13620
13621    // ==========================================================================
13622    // Chart of Accounts Config Tests
13623    // ==========================================================================
13624
13625    #[test]
13626    fn test_coa_config_defaults() {
13627        let yaml = r#"
13628            complexity: medium
13629        "#;
13630
13631        let config: ChartOfAccountsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13632        assert!(config.industry_specific); // Default true
13633        assert!(config.custom_accounts.is_none());
13634        assert_eq!(config.min_hierarchy_depth, 2); // Default
13635        assert_eq!(config.max_hierarchy_depth, 5); // Default
13636    }
13637
13638    // ==========================================================================
13639    // Accounting Standards Config Tests
13640    // ==========================================================================
13641
13642    #[test]
13643    fn test_accounting_standards_config_defaults() {
13644        let config = AccountingStandardsConfig::default();
13645        assert!(!config.enabled);
13646        assert!(config.framework.is_none());
13647        assert!(!config.revenue_recognition.enabled);
13648        assert!(!config.leases.enabled);
13649        assert!(!config.fair_value.enabled);
13650        assert!(!config.impairment.enabled);
13651        assert!(!config.generate_differences);
13652    }
13653
13654    #[test]
13655    fn test_accounting_standards_config_yaml() {
13656        let yaml = r#"
13657            enabled: true
13658            framework: ifrs
13659            revenue_recognition:
13660              enabled: true
13661              generate_contracts: true
13662              avg_obligations_per_contract: 2.5
13663              variable_consideration_rate: 0.20
13664              over_time_recognition_rate: 0.35
13665              contract_count: 150
13666            leases:
13667              enabled: true
13668              lease_count: 75
13669              finance_lease_percent: 0.25
13670              avg_lease_term_months: 48
13671            generate_differences: true
13672        "#;
13673
13674        let config: AccountingStandardsConfig =
13675            serde_yaml::from_str(yaml).expect("Failed to parse");
13676        assert!(config.enabled);
13677        assert!(matches!(
13678            config.framework,
13679            Some(AccountingFrameworkConfig::Ifrs)
13680        ));
13681        assert!(config.revenue_recognition.enabled);
13682        assert_eq!(config.revenue_recognition.contract_count, 150);
13683        assert_eq!(config.revenue_recognition.avg_obligations_per_contract, 2.5);
13684        assert!(config.leases.enabled);
13685        assert_eq!(config.leases.lease_count, 75);
13686        assert_eq!(config.leases.finance_lease_percent, 0.25);
13687        assert!(config.generate_differences);
13688    }
13689
13690    #[test]
13691    fn test_accounting_framework_serialization() {
13692        let frameworks = [
13693            AccountingFrameworkConfig::UsGaap,
13694            AccountingFrameworkConfig::Ifrs,
13695            AccountingFrameworkConfig::DualReporting,
13696            AccountingFrameworkConfig::FrenchGaap,
13697            AccountingFrameworkConfig::GermanGaap,
13698        ];
13699
13700        for framework in frameworks {
13701            let json = serde_json::to_string(&framework).expect("Failed to serialize");
13702            let deserialized: AccountingFrameworkConfig =
13703                serde_json::from_str(&json).expect("Failed to deserialize");
13704            assert!(format!("{:?}", framework) == format!("{:?}", deserialized));
13705        }
13706    }
13707
13708    #[test]
13709    fn test_revenue_recognition_config_defaults() {
13710        let config = RevenueRecognitionConfig::default();
13711        assert!(!config.enabled);
13712        assert!(config.generate_contracts);
13713        assert_eq!(config.avg_obligations_per_contract, 2.0);
13714        assert_eq!(config.variable_consideration_rate, 0.15);
13715        assert_eq!(config.over_time_recognition_rate, 0.30);
13716        assert_eq!(config.contract_count, 100);
13717    }
13718
13719    #[test]
13720    fn test_lease_accounting_config_defaults() {
13721        let config = LeaseAccountingConfig::default();
13722        assert!(!config.enabled);
13723        assert_eq!(config.lease_count, 50);
13724        assert_eq!(config.finance_lease_percent, 0.30);
13725        assert_eq!(config.avg_lease_term_months, 60);
13726        assert!(config.generate_amortization);
13727        assert_eq!(config.real_estate_percent, 0.40);
13728    }
13729
13730    #[test]
13731    fn test_fair_value_config_defaults() {
13732        let config = FairValueConfig::default();
13733        assert!(!config.enabled);
13734        assert_eq!(config.measurement_count, 25);
13735        assert_eq!(config.level1_percent, 0.40);
13736        assert_eq!(config.level2_percent, 0.35);
13737        assert_eq!(config.level3_percent, 0.25);
13738        assert!(!config.include_sensitivity_analysis);
13739    }
13740
13741    #[test]
13742    fn test_impairment_config_defaults() {
13743        let config = ImpairmentConfig::default();
13744        assert!(!config.enabled);
13745        assert_eq!(config.test_count, 15);
13746        assert_eq!(config.impairment_rate, 0.10);
13747        assert!(config.generate_projections);
13748        assert!(!config.include_goodwill);
13749    }
13750
13751    // ==========================================================================
13752    // Audit Standards Config Tests
13753    // ==========================================================================
13754
13755    #[test]
13756    fn test_audit_standards_config_defaults() {
13757        let config = AuditStandardsConfig::default();
13758        assert!(!config.enabled);
13759        assert!(!config.isa_compliance.enabled);
13760        assert!(!config.analytical_procedures.enabled);
13761        assert!(!config.confirmations.enabled);
13762        assert!(!config.opinion.enabled);
13763        assert!(!config.generate_audit_trail);
13764        assert!(!config.sox.enabled);
13765        assert!(!config.pcaob.enabled);
13766    }
13767
13768    #[test]
13769    fn test_audit_standards_config_yaml() {
13770        let yaml = r#"
13771            enabled: true
13772            isa_compliance:
13773              enabled: true
13774              compliance_level: comprehensive
13775              generate_isa_mappings: true
13776              include_pcaob: true
13777              framework: dual
13778            analytical_procedures:
13779              enabled: true
13780              procedures_per_account: 5
13781              variance_probability: 0.25
13782            confirmations:
13783              enabled: true
13784              confirmation_count: 75
13785              positive_response_rate: 0.90
13786              exception_rate: 0.08
13787            opinion:
13788              enabled: true
13789              generate_kam: true
13790              average_kam_count: 4
13791            sox:
13792              enabled: true
13793              generate_302_certifications: true
13794              generate_404_assessments: true
13795              material_weakness_rate: 0.03
13796            pcaob:
13797              enabled: true
13798              is_pcaob_audit: true
13799              include_icfr_opinion: true
13800            generate_audit_trail: true
13801        "#;
13802
13803        let config: AuditStandardsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13804        assert!(config.enabled);
13805        assert!(config.isa_compliance.enabled);
13806        assert_eq!(config.isa_compliance.compliance_level, "comprehensive");
13807        assert!(config.isa_compliance.include_pcaob);
13808        assert_eq!(config.isa_compliance.framework, "dual");
13809        assert!(config.analytical_procedures.enabled);
13810        assert_eq!(config.analytical_procedures.procedures_per_account, 5);
13811        assert!(config.confirmations.enabled);
13812        assert_eq!(config.confirmations.confirmation_count, 75);
13813        assert!(config.opinion.enabled);
13814        assert_eq!(config.opinion.average_kam_count, 4);
13815        assert!(config.sox.enabled);
13816        assert!(config.sox.generate_302_certifications);
13817        assert_eq!(config.sox.material_weakness_rate, 0.03);
13818        assert!(config.pcaob.enabled);
13819        assert!(config.pcaob.is_pcaob_audit);
13820        assert!(config.pcaob.include_icfr_opinion);
13821        assert!(config.generate_audit_trail);
13822    }
13823
13824    #[test]
13825    fn test_isa_compliance_config_defaults() {
13826        let config = IsaComplianceConfig::default();
13827        assert!(!config.enabled);
13828        assert_eq!(config.compliance_level, "standard");
13829        assert!(config.generate_isa_mappings);
13830        assert!(config.generate_coverage_summary);
13831        assert!(!config.include_pcaob);
13832        assert_eq!(config.framework, "isa");
13833    }
13834
13835    #[test]
13836    fn test_sox_compliance_config_defaults() {
13837        let config = SoxComplianceConfig::default();
13838        assert!(!config.enabled);
13839        assert!(config.generate_302_certifications);
13840        assert!(config.generate_404_assessments);
13841        assert_eq!(config.materiality_threshold, 10000.0);
13842        assert_eq!(config.material_weakness_rate, 0.02);
13843        assert_eq!(config.significant_deficiency_rate, 0.08);
13844    }
13845
13846    #[test]
13847    fn test_pcaob_config_defaults() {
13848        let config = PcaobConfig::default();
13849        assert!(!config.enabled);
13850        assert!(!config.is_pcaob_audit);
13851        assert!(config.generate_cam);
13852        assert!(!config.include_icfr_opinion);
13853        assert!(!config.generate_standard_mappings);
13854    }
13855
13856    #[test]
13857    fn test_config_with_standards_enabled() {
13858        let yaml = r#"
13859            global:
13860              industry: financial_services
13861              start_date: "2024-01-01"
13862              period_months: 12
13863            companies:
13864              - code: "BANK"
13865                name: "Test Bank"
13866                currency: "USD"
13867                country: "US"
13868                annual_transaction_volume: hundred_k
13869            chart_of_accounts:
13870              complexity: large
13871            output:
13872              output_directory: "./output"
13873            accounting_standards:
13874              enabled: true
13875              framework: us_gaap
13876              revenue_recognition:
13877                enabled: true
13878              leases:
13879                enabled: true
13880            audit_standards:
13881              enabled: true
13882              isa_compliance:
13883                enabled: true
13884              sox:
13885                enabled: true
13886        "#;
13887
13888        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13889        assert!(config.accounting_standards.enabled);
13890        assert!(matches!(
13891            config.accounting_standards.framework,
13892            Some(AccountingFrameworkConfig::UsGaap)
13893        ));
13894        assert!(config.accounting_standards.revenue_recognition.enabled);
13895        assert!(config.accounting_standards.leases.enabled);
13896        assert!(config.audit_standards.enabled);
13897        assert!(config.audit_standards.isa_compliance.enabled);
13898        assert!(config.audit_standards.sox.enabled);
13899    }
13900
13901    // ==========================================================================
13902    // Industry-Specific Config Tests
13903    // ==========================================================================
13904
13905    #[test]
13906    fn test_industry_specific_config_defaults() {
13907        let config = IndustrySpecificConfig::default();
13908        assert!(!config.enabled);
13909        assert!(!config.manufacturing.enabled);
13910        assert!(!config.retail.enabled);
13911        assert!(!config.healthcare.enabled);
13912        assert!(!config.technology.enabled);
13913        assert!(!config.financial_services.enabled);
13914        assert!(!config.professional_services.enabled);
13915    }
13916
13917    #[test]
13918    fn test_manufacturing_config_defaults() {
13919        let config = ManufacturingConfig::default();
13920        assert!(!config.enabled);
13921        assert_eq!(config.bom_depth, 4);
13922        assert!(!config.just_in_time);
13923        assert_eq!(config.supplier_tiers, 2);
13924        assert_eq!(config.target_yield_rate, 0.97);
13925        assert_eq!(config.scrap_alert_threshold, 0.03);
13926    }
13927
13928    #[test]
13929    fn test_retail_config_defaults() {
13930        let config = RetailConfig::default();
13931        assert!(!config.enabled);
13932        assert_eq!(config.avg_daily_transactions, 500);
13933        assert!(config.loss_prevention);
13934        assert_eq!(config.shrinkage_rate, 0.015);
13935    }
13936
13937    #[test]
13938    fn test_healthcare_config_defaults() {
13939        let config = HealthcareConfig::default();
13940        assert!(!config.enabled);
13941        assert_eq!(config.facility_type, "hospital");
13942        assert_eq!(config.avg_daily_encounters, 150);
13943        assert!(config.compliance.hipaa);
13944        assert!(config.compliance.stark_law);
13945        assert!(config.coding_systems.icd10);
13946        assert!(config.coding_systems.cpt);
13947    }
13948
13949    #[test]
13950    fn test_technology_config_defaults() {
13951        let config = TechnologyConfig::default();
13952        assert!(!config.enabled);
13953        assert_eq!(config.revenue_model, "saas");
13954        assert_eq!(config.subscription_revenue_pct, 0.60);
13955        assert!(config.rd_capitalization.enabled);
13956    }
13957
13958    #[test]
13959    fn test_config_with_industry_specific() {
13960        let yaml = r#"
13961            global:
13962              industry: healthcare
13963              start_date: "2024-01-01"
13964              period_months: 12
13965            companies:
13966              - code: "HOSP"
13967                name: "Test Hospital"
13968                currency: "USD"
13969                country: "US"
13970                annual_transaction_volume: hundred_k
13971            chart_of_accounts:
13972              complexity: medium
13973            output:
13974              output_directory: "./output"
13975            industry_specific:
13976              enabled: true
13977              healthcare:
13978                enabled: true
13979                facility_type: hospital
13980                payer_mix:
13981                  medicare: 0.45
13982                  medicaid: 0.15
13983                  commercial: 0.35
13984                  self_pay: 0.05
13985                coding_systems:
13986                  icd10: true
13987                  cpt: true
13988                  drg: true
13989                compliance:
13990                  hipaa: true
13991                  stark_law: true
13992                anomaly_rates:
13993                  upcoding: 0.03
13994                  unbundling: 0.02
13995        "#;
13996
13997        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13998        assert!(config.industry_specific.enabled);
13999        assert!(config.industry_specific.healthcare.enabled);
14000        assert_eq!(
14001            config.industry_specific.healthcare.facility_type,
14002            "hospital"
14003        );
14004        assert_eq!(config.industry_specific.healthcare.payer_mix.medicare, 0.45);
14005        assert_eq!(config.industry_specific.healthcare.payer_mix.self_pay, 0.05);
14006        assert!(config.industry_specific.healthcare.coding_systems.icd10);
14007        assert!(config.industry_specific.healthcare.compliance.hipaa);
14008        assert_eq!(
14009            config.industry_specific.healthcare.anomaly_rates.upcoding,
14010            0.03
14011        );
14012    }
14013
14014    #[test]
14015    fn test_config_with_manufacturing_specific() {
14016        let yaml = r#"
14017            global:
14018              industry: manufacturing
14019              start_date: "2024-01-01"
14020              period_months: 12
14021            companies:
14022              - code: "MFG"
14023                name: "Test Manufacturing"
14024                currency: "USD"
14025                country: "US"
14026                annual_transaction_volume: hundred_k
14027            chart_of_accounts:
14028              complexity: medium
14029            output:
14030              output_directory: "./output"
14031            industry_specific:
14032              enabled: true
14033              manufacturing:
14034                enabled: true
14035                bom_depth: 5
14036                just_in_time: true
14037                supplier_tiers: 3
14038                target_yield_rate: 0.98
14039                anomaly_rates:
14040                  yield_manipulation: 0.02
14041                  phantom_production: 0.01
14042        "#;
14043
14044        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14045        assert!(config.industry_specific.enabled);
14046        assert!(config.industry_specific.manufacturing.enabled);
14047        assert_eq!(config.industry_specific.manufacturing.bom_depth, 5);
14048        assert!(config.industry_specific.manufacturing.just_in_time);
14049        assert_eq!(config.industry_specific.manufacturing.supplier_tiers, 3);
14050        assert_eq!(
14051            config.industry_specific.manufacturing.target_yield_rate,
14052            0.98
14053        );
14054        assert_eq!(
14055            config
14056                .industry_specific
14057                .manufacturing
14058                .anomaly_rates
14059                .yield_manipulation,
14060            0.02
14061        );
14062    }
14063
14064    // ==========================================================================
14065    // Tax Configuration Tests
14066    // ==========================================================================
14067
14068    #[test]
14069    fn test_tax_config_defaults() {
14070        let tax = TaxConfig::default();
14071        assert!(!tax.enabled);
14072        assert!(tax.jurisdictions.countries.is_empty());
14073        assert!(!tax.jurisdictions.include_subnational);
14074        assert!(!tax.vat_gst.enabled);
14075        assert!(tax.vat_gst.standard_rates.is_empty());
14076        assert!(tax.vat_gst.reduced_rates.is_empty());
14077        assert!(tax.vat_gst.exempt_categories.is_empty());
14078        assert!(tax.vat_gst.reverse_charge);
14079        assert!(!tax.sales_tax.enabled);
14080        assert!(tax.sales_tax.nexus_states.is_empty());
14081        assert!(!tax.withholding.enabled);
14082        assert!(tax.withholding.treaty_network);
14083        assert_eq!(tax.withholding.default_rate, 0.30);
14084        assert_eq!(tax.withholding.treaty_reduced_rate, 0.15);
14085        assert!(tax.provisions.enabled);
14086        assert_eq!(tax.provisions.statutory_rate, 0.21);
14087        assert!(tax.provisions.uncertain_positions);
14088        assert!(!tax.payroll_tax.enabled);
14089        assert_eq!(tax.anomaly_rate, 0.03);
14090    }
14091
14092    #[test]
14093    fn test_tax_config_from_yaml() {
14094        let yaml = r#"
14095            global:
14096              seed: 42
14097              start_date: "2024-01-01"
14098              period_months: 12
14099              industry: retail
14100            companies:
14101              - code: C001
14102                name: Test Corp
14103                currency: USD
14104                country: US
14105                annual_transaction_volume: ten_k
14106            chart_of_accounts:
14107              complexity: small
14108            output:
14109              output_directory: ./output
14110            tax:
14111              enabled: true
14112              anomaly_rate: 0.05
14113              jurisdictions:
14114                countries: ["US", "DE", "GB"]
14115                include_subnational: true
14116              vat_gst:
14117                enabled: true
14118                standard_rates:
14119                  DE: 0.19
14120                  GB: 0.20
14121                reduced_rates:
14122                  DE: 0.07
14123                  GB: 0.05
14124                exempt_categories:
14125                  - financial_services
14126                  - healthcare
14127                reverse_charge: false
14128              sales_tax:
14129                enabled: true
14130                nexus_states: ["CA", "NY", "TX"]
14131              withholding:
14132                enabled: true
14133                treaty_network: false
14134                default_rate: 0.25
14135                treaty_reduced_rate: 0.10
14136              provisions:
14137                enabled: false
14138                statutory_rate: 0.28
14139                uncertain_positions: false
14140              payroll_tax:
14141                enabled: true
14142        "#;
14143
14144        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14145        assert!(config.tax.enabled);
14146        assert_eq!(config.tax.anomaly_rate, 0.05);
14147
14148        // Jurisdictions
14149        assert_eq!(config.tax.jurisdictions.countries.len(), 3);
14150        assert!(config
14151            .tax
14152            .jurisdictions
14153            .countries
14154            .contains(&"DE".to_string()));
14155        assert!(config.tax.jurisdictions.include_subnational);
14156
14157        // VAT/GST
14158        assert!(config.tax.vat_gst.enabled);
14159        assert_eq!(config.tax.vat_gst.standard_rates.get("DE"), Some(&0.19));
14160        assert_eq!(config.tax.vat_gst.standard_rates.get("GB"), Some(&0.20));
14161        assert_eq!(config.tax.vat_gst.reduced_rates.get("DE"), Some(&0.07));
14162        assert_eq!(config.tax.vat_gst.exempt_categories.len(), 2);
14163        assert!(!config.tax.vat_gst.reverse_charge);
14164
14165        // Sales tax
14166        assert!(config.tax.sales_tax.enabled);
14167        assert_eq!(config.tax.sales_tax.nexus_states.len(), 3);
14168        assert!(config
14169            .tax
14170            .sales_tax
14171            .nexus_states
14172            .contains(&"CA".to_string()));
14173
14174        // Withholding
14175        assert!(config.tax.withholding.enabled);
14176        assert!(!config.tax.withholding.treaty_network);
14177        assert_eq!(config.tax.withholding.default_rate, 0.25);
14178        assert_eq!(config.tax.withholding.treaty_reduced_rate, 0.10);
14179
14180        // Provisions
14181        assert!(!config.tax.provisions.enabled);
14182        assert_eq!(config.tax.provisions.statutory_rate, 0.28);
14183        assert!(!config.tax.provisions.uncertain_positions);
14184
14185        // Payroll tax
14186        assert!(config.tax.payroll_tax.enabled);
14187    }
14188
14189    #[test]
14190    fn test_generator_config_with_tax_default() {
14191        let yaml = r#"
14192            global:
14193              seed: 42
14194              start_date: "2024-01-01"
14195              period_months: 12
14196              industry: retail
14197            companies:
14198              - code: C001
14199                name: Test Corp
14200                currency: USD
14201                country: US
14202                annual_transaction_volume: ten_k
14203            chart_of_accounts:
14204              complexity: small
14205            output:
14206              output_directory: ./output
14207        "#;
14208
14209        let config: GeneratorConfig =
14210            serde_yaml::from_str(yaml).expect("Failed to parse config without tax section");
14211        // Tax should be present with defaults when not specified in YAML
14212        assert!(!config.tax.enabled);
14213        assert!(config.tax.jurisdictions.countries.is_empty());
14214        assert_eq!(config.tax.anomaly_rate, 0.03);
14215        assert!(config.tax.provisions.enabled); // provisions default to enabled=true
14216        assert_eq!(config.tax.provisions.statutory_rate, 0.21);
14217    }
14218
14219    // ==========================================================================
14220    // SessionSchemaConfig Tests
14221    // ==========================================================================
14222
14223    #[test]
14224    fn test_session_config_default_disabled() {
14225        let yaml = "{}";
14226        let config: SessionSchemaConfig =
14227            serde_yaml::from_str(yaml).expect("Failed to parse empty session config");
14228        assert!(!config.enabled);
14229        assert!(config.checkpoint_path.is_none());
14230        assert!(config.per_period_output);
14231        assert!(config.consolidated_output);
14232    }
14233
14234    #[test]
14235    fn test_config_backward_compatible_without_session() {
14236        let yaml = r#"
14237            global:
14238              seed: 42
14239              start_date: "2024-01-01"
14240              period_months: 12
14241              industry: retail
14242            companies:
14243              - code: C001
14244                name: Test Corp
14245                currency: USD
14246                country: US
14247                annual_transaction_volume: ten_k
14248            chart_of_accounts:
14249              complexity: small
14250            output:
14251              output_directory: ./output
14252        "#;
14253
14254        let config: GeneratorConfig =
14255            serde_yaml::from_str(yaml).expect("Failed to parse config without session");
14256        // Session should default to disabled
14257        assert!(!config.session.enabled);
14258        assert!(config.session.per_period_output);
14259        assert!(config.session.consolidated_output);
14260        // fiscal_year_months should be None
14261        assert!(config.global.fiscal_year_months.is_none());
14262    }
14263
14264    #[test]
14265    fn test_fiscal_year_months_parsed() {
14266        let yaml = r#"
14267            global:
14268              seed: 42
14269              start_date: "2024-01-01"
14270              period_months: 24
14271              industry: retail
14272              fiscal_year_months: 12
14273            companies:
14274              - code: C001
14275                name: Test Corp
14276                currency: USD
14277                country: US
14278                annual_transaction_volume: ten_k
14279            chart_of_accounts:
14280              complexity: small
14281            output:
14282              output_directory: ./output
14283            session:
14284              enabled: true
14285              checkpoint_path: /tmp/checkpoints
14286              per_period_output: true
14287              consolidated_output: false
14288        "#;
14289
14290        let config: GeneratorConfig =
14291            serde_yaml::from_str(yaml).expect("Failed to parse config with fiscal_year_months");
14292        assert_eq!(config.global.fiscal_year_months, Some(12));
14293        assert!(config.session.enabled);
14294        assert_eq!(
14295            config.session.checkpoint_path,
14296            Some("/tmp/checkpoints".to_string())
14297        );
14298        assert!(config.session.per_period_output);
14299        assert!(!config.session.consolidated_output);
14300    }
14301}