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    ///
1588    /// Accepts both `export_layout` (canonical / YAML) and `exportLayout`
1589    /// (camelCase / SDK JSON) so SDKs that follow camelCase conventions
1590    /// hit the flat path rather than silently getting the Nested default.
1591    /// Before v3.1.1 the missing camelCase alias meant SDK requests with
1592    /// `exportLayout: "flat"` were silently ignored, which SDK operators
1593    /// reported as "flat hangs generation" (the job completed with Nested
1594    /// layout, but manifests didn't match the expected flat shape).
1595    #[serde(default, alias = "exportLayout")]
1596    pub export_layout: ExportLayout,
1597}
1598
1599fn default_formats() -> Vec<FileFormat> {
1600    vec![FileFormat::Parquet]
1601}
1602fn default_batch_size() -> usize {
1603    100_000
1604}
1605
1606impl Default for OutputConfig {
1607    fn default() -> Self {
1608        Self {
1609            mode: OutputMode::FlatFile,
1610            output_directory: PathBuf::from("./output"),
1611            formats: default_formats(),
1612            compression: CompressionConfig::default(),
1613            batch_size: default_batch_size(),
1614            include_acdoca: true,
1615            include_bseg: false,
1616            partition_by_period: true,
1617            partition_by_company: false,
1618            numeric_mode: NumericMode::default(),
1619            export_layout: ExportLayout::default(),
1620        }
1621    }
1622}
1623
1624/// Numeric serialization mode for JSON decimal fields.
1625#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
1626#[serde(rename_all = "snake_case")]
1627pub enum NumericMode {
1628    /// Decimals as JSON strings (e.g. `"1729237.30"`). Preserves full precision.
1629    #[default]
1630    String,
1631    /// Decimals as JSON numbers (e.g. `1729237.30`). Friendlier for pandas/analytics.
1632    Native,
1633}
1634
1635/// JSON export layout for nested structures (journal entries, document flows).
1636#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
1637#[serde(rename_all = "snake_case")]
1638pub enum ExportLayout {
1639    /// Nested structure: `{"header": {...}, "lines": [...]}`. Natural ERP format.
1640    #[default]
1641    Nested,
1642    /// Flat structure: header fields repeated on every line. Analytics-friendly.
1643    Flat,
1644}
1645
1646/// Output mode.
1647#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1648#[serde(rename_all = "snake_case")]
1649pub enum OutputMode {
1650    /// Stream records as generated
1651    Streaming,
1652    /// Write to flat files
1653    #[default]
1654    FlatFile,
1655    /// Both streaming and flat file
1656    Both,
1657}
1658
1659/// Supported file formats.
1660#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1661#[serde(rename_all = "snake_case")]
1662pub enum FileFormat {
1663    Csv,
1664    Parquet,
1665    Json,
1666    JsonLines,
1667}
1668
1669/// Compression configuration.
1670#[derive(Debug, Clone, Serialize, Deserialize)]
1671pub struct CompressionConfig {
1672    /// Enable compression
1673    #[serde(default = "default_true")]
1674    pub enabled: bool,
1675    /// Compression algorithm
1676    #[serde(default)]
1677    pub algorithm: CompressionAlgorithm,
1678    /// Compression level (1-9)
1679    #[serde(default = "default_compression_level")]
1680    pub level: u8,
1681}
1682
1683fn default_compression_level() -> u8 {
1684    3
1685}
1686
1687impl Default for CompressionConfig {
1688    fn default() -> Self {
1689        Self {
1690            enabled: true,
1691            algorithm: CompressionAlgorithm::default(),
1692            level: default_compression_level(),
1693        }
1694    }
1695}
1696
1697/// Compression algorithms.
1698#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1699#[serde(rename_all = "snake_case")]
1700pub enum CompressionAlgorithm {
1701    Gzip,
1702    #[default]
1703    Zstd,
1704    Lz4,
1705    Snappy,
1706}
1707
1708/// Fraud simulation configuration.
1709///
1710/// ## Document-level vs. line-level fraud
1711///
1712/// `fraud_rate` applies to individual journal-entry lines (line-level).
1713/// `document_fraud_rate` (optional) applies to source documents
1714/// (purchase orders, vendor invoices, customer invoices, payments), and when
1715/// `propagate_to_lines` is true, every JE derived from a fraudulent document
1716/// also gets `is_fraud = true`. This lets users express either:
1717///
1718///  * pure line-level fraud (`document_fraud_rate = None`): legacy behaviour;
1719///  * pure document-level fraud (`fraud_rate ≈ 0` and `document_fraud_rate` set):
1720///    fraud rings expressed at document granularity — realistic for PO/invoice
1721///    fraud schemes where one fraudulent document spawns multiple derived JEs;
1722///  * hybrid (both set): document-level scheme fraud plus unrelated line-level
1723///    slip-ups.
1724///
1725/// `propagate_to_document` does the inverse: when a JE is tagged as fraud by
1726/// the anomaly injector, its source document is also marked fraudulent.
1727#[derive(Debug, Clone, Serialize, Deserialize)]
1728pub struct FraudConfig {
1729    /// Enable fraud scenario generation
1730    #[serde(default)]
1731    pub enabled: bool,
1732    /// Line-level fraud rate: fraction of individual JE lines flagged as fraud (0.0 to 1.0).
1733    ///
1734    /// # Effective line-level prevalence
1735    ///
1736    /// If `document_fraud_rate = Some(d)` and `propagate_to_lines = true`,
1737    /// the observed line-level fraud prevalence is roughly:
1738    ///
1739    ///     P(line is_fraud) ≈ fraud_rate + d × avg_lines_per_fraud_doc / total_lines
1740    ///
1741    /// For a typical retail job (avg 3 lines per document, ~30 % of lines
1742    /// come from doc-flow-derived JEs) the combined rate lands near:
1743    ///
1744    ///     fraud_rate + 0.3 × d
1745    ///
1746    /// so setting `fraud_rate=0.02, document_fraud_rate=0.05, propagate_to_lines=true`
1747    /// produces ~3.5 % line-level fraud, not 2 %. To target a specific
1748    /// line-level prevalence X, choose `fraud_rate = X - 0.3 × d`.
1749    #[serde(default = "default_fraud_rate", alias = "fraudRate")]
1750    pub fraud_rate: f64,
1751    /// Document-level fraud rate: fraction of source documents (PO, vendor
1752    /// invoice, customer invoice, payment) flagged as fraud. `None` disables
1753    /// document-level injection; `Some(r)` marks ~r × document-count as fraud
1754    /// independently of the line-level rate.
1755    #[serde(default, alias = "documentFraudRate")]
1756    pub document_fraud_rate: Option<f64>,
1757    /// When true, flagging a document as fraudulent cascades `is_fraud = true`
1758    /// and `fraud_type` to every journal entry derived from that document,
1759    /// and records `fraud_source_document_id` on the JE header.
1760    /// Default: `true`.
1761    #[serde(default = "default_true", alias = "propagateToLines")]
1762    pub propagate_to_lines: bool,
1763    /// When true, tagging a JE as fraud via line-level anomaly injection also
1764    /// marks the JE's source document as fraudulent (if it can be resolved).
1765    /// Default: `true`.
1766    #[serde(default = "default_true", alias = "propagateToDocument")]
1767    pub propagate_to_document: bool,
1768    /// Fraud type distribution
1769    #[serde(default)]
1770    pub fraud_type_distribution: FraudTypeDistribution,
1771    /// Enable fraud clustering
1772    #[serde(default)]
1773    pub clustering_enabled: bool,
1774    /// Clustering factor
1775    #[serde(default = "default_clustering_factor")]
1776    pub clustering_factor: f64,
1777    /// Approval thresholds for threshold-adjacent fraud pattern
1778    #[serde(default = "default_approval_thresholds")]
1779    pub approval_thresholds: Vec<f64>,
1780}
1781
1782fn default_approval_thresholds() -> Vec<f64> {
1783    vec![1000.0, 5000.0, 10000.0, 25000.0, 50000.0, 100000.0]
1784}
1785
1786fn default_fraud_rate() -> f64 {
1787    0.005
1788}
1789fn default_clustering_factor() -> f64 {
1790    3.0
1791}
1792
1793impl Default for FraudConfig {
1794    fn default() -> Self {
1795        Self {
1796            enabled: false,
1797            fraud_rate: default_fraud_rate(),
1798            document_fraud_rate: None,
1799            propagate_to_lines: true,
1800            propagate_to_document: true,
1801            fraud_type_distribution: FraudTypeDistribution::default(),
1802            clustering_enabled: false,
1803            clustering_factor: default_clustering_factor(),
1804            approval_thresholds: default_approval_thresholds(),
1805        }
1806    }
1807}
1808
1809/// Distribution of fraud types.
1810#[derive(Debug, Clone, Serialize, Deserialize)]
1811pub struct FraudTypeDistribution {
1812    pub suspense_account_abuse: f64,
1813    pub fictitious_transaction: f64,
1814    pub revenue_manipulation: f64,
1815    pub expense_capitalization: f64,
1816    pub split_transaction: f64,
1817    pub timing_anomaly: f64,
1818    pub unauthorized_access: f64,
1819    pub duplicate_payment: f64,
1820}
1821
1822impl Default for FraudTypeDistribution {
1823    fn default() -> Self {
1824        Self {
1825            suspense_account_abuse: 0.25,
1826            fictitious_transaction: 0.15,
1827            revenue_manipulation: 0.10,
1828            expense_capitalization: 0.10,
1829            split_transaction: 0.15,
1830            timing_anomaly: 0.10,
1831            unauthorized_access: 0.10,
1832            duplicate_payment: 0.05,
1833        }
1834    }
1835}
1836
1837/// Internal Controls System (ICS) configuration.
1838#[derive(Debug, Clone, Serialize, Deserialize)]
1839pub struct InternalControlsConfig {
1840    /// Enable internal controls system
1841    #[serde(default)]
1842    pub enabled: bool,
1843    /// Rate at which controls result in exceptions (0.0 - 1.0)
1844    #[serde(default = "default_exception_rate")]
1845    pub exception_rate: f64,
1846    /// Rate at which SoD violations occur (0.0 - 1.0)
1847    #[serde(default = "default_sod_violation_rate")]
1848    pub sod_violation_rate: f64,
1849    /// Export control master data to separate files
1850    #[serde(default = "default_true")]
1851    pub export_control_master_data: bool,
1852    /// SOX materiality threshold for marking transactions as SOX-relevant
1853    #[serde(default = "default_sox_materiality_threshold")]
1854    pub sox_materiality_threshold: f64,
1855    /// Enable COSO 2013 framework integration
1856    #[serde(default = "default_true")]
1857    pub coso_enabled: bool,
1858    /// Include entity-level controls in generation
1859    #[serde(default)]
1860    pub include_entity_level_controls: bool,
1861    /// Target maturity level for controls
1862    /// Valid values: "ad_hoc", "repeatable", "defined", "managed", "optimized", "mixed"
1863    #[serde(default = "default_target_maturity_level")]
1864    pub target_maturity_level: String,
1865}
1866
1867fn default_exception_rate() -> f64 {
1868    0.02
1869}
1870
1871fn default_sod_violation_rate() -> f64 {
1872    0.01
1873}
1874
1875fn default_sox_materiality_threshold() -> f64 {
1876    10000.0
1877}
1878
1879fn default_target_maturity_level() -> String {
1880    "mixed".to_string()
1881}
1882
1883impl Default for InternalControlsConfig {
1884    fn default() -> Self {
1885        Self {
1886            enabled: false,
1887            exception_rate: default_exception_rate(),
1888            sod_violation_rate: default_sod_violation_rate(),
1889            export_control_master_data: true,
1890            sox_materiality_threshold: default_sox_materiality_threshold(),
1891            coso_enabled: true,
1892            include_entity_level_controls: false,
1893            target_maturity_level: default_target_maturity_level(),
1894        }
1895    }
1896}
1897
1898/// Business process configuration.
1899#[derive(Debug, Clone, Serialize, Deserialize)]
1900pub struct BusinessProcessConfig {
1901    /// Order-to-Cash weight
1902    #[serde(default = "default_o2c")]
1903    pub o2c_weight: f64,
1904    /// Procure-to-Pay weight
1905    #[serde(default = "default_p2p")]
1906    pub p2p_weight: f64,
1907    /// Record-to-Report weight
1908    #[serde(default = "default_r2r")]
1909    pub r2r_weight: f64,
1910    /// Hire-to-Retire weight
1911    #[serde(default = "default_h2r")]
1912    pub h2r_weight: f64,
1913    /// Acquire-to-Retire weight
1914    #[serde(default = "default_a2r")]
1915    pub a2r_weight: f64,
1916}
1917
1918fn default_o2c() -> f64 {
1919    0.35
1920}
1921fn default_p2p() -> f64 {
1922    0.30
1923}
1924fn default_r2r() -> f64 {
1925    0.20
1926}
1927fn default_h2r() -> f64 {
1928    0.10
1929}
1930fn default_a2r() -> f64 {
1931    0.05
1932}
1933
1934impl Default for BusinessProcessConfig {
1935    fn default() -> Self {
1936        Self {
1937            o2c_weight: default_o2c(),
1938            p2p_weight: default_p2p(),
1939            r2r_weight: default_r2r(),
1940            h2r_weight: default_h2r(),
1941            a2r_weight: default_a2r(),
1942        }
1943    }
1944}
1945
1946/// User persona configuration.
1947#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1948pub struct UserPersonaConfig {
1949    /// Distribution of user personas
1950    #[serde(default)]
1951    pub persona_distribution: PersonaDistribution,
1952    /// Users per persona type
1953    #[serde(default)]
1954    pub users_per_persona: UsersPerPersona,
1955}
1956
1957/// Distribution of user personas for transaction generation.
1958#[derive(Debug, Clone, Serialize, Deserialize)]
1959pub struct PersonaDistribution {
1960    pub junior_accountant: f64,
1961    pub senior_accountant: f64,
1962    pub controller: f64,
1963    pub manager: f64,
1964    pub automated_system: f64,
1965}
1966
1967impl Default for PersonaDistribution {
1968    fn default() -> Self {
1969        Self {
1970            junior_accountant: 0.15,
1971            senior_accountant: 0.15,
1972            controller: 0.05,
1973            manager: 0.05,
1974            automated_system: 0.60,
1975        }
1976    }
1977}
1978
1979/// Number of users per persona type.
1980#[derive(Debug, Clone, Serialize, Deserialize)]
1981pub struct UsersPerPersona {
1982    pub junior_accountant: usize,
1983    pub senior_accountant: usize,
1984    pub controller: usize,
1985    pub manager: usize,
1986    pub automated_system: usize,
1987}
1988
1989impl Default for UsersPerPersona {
1990    fn default() -> Self {
1991        Self {
1992            junior_accountant: 10,
1993            senior_accountant: 5,
1994            controller: 2,
1995            manager: 3,
1996            automated_system: 20,
1997        }
1998    }
1999}
2000
2001/// Template configuration for realistic data generation.
2002#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2003pub struct TemplateConfig {
2004    /// Name generation settings
2005    #[serde(default)]
2006    pub names: NameTemplateConfig,
2007    /// Description generation settings
2008    #[serde(default)]
2009    pub descriptions: DescriptionTemplateConfig,
2010    /// Reference number settings
2011    #[serde(default)]
2012    pub references: ReferenceTemplateConfig,
2013}
2014
2015/// Name template configuration.
2016#[derive(Debug, Clone, Serialize, Deserialize)]
2017pub struct NameTemplateConfig {
2018    /// Distribution of name cultures
2019    #[serde(default)]
2020    pub culture_distribution: CultureDistribution,
2021    /// Email domain for generated users
2022    #[serde(default = "default_email_domain")]
2023    pub email_domain: String,
2024    /// Generate realistic display names
2025    #[serde(default = "default_true")]
2026    pub generate_realistic_names: bool,
2027}
2028
2029fn default_email_domain() -> String {
2030    "company.com".to_string()
2031}
2032
2033impl Default for NameTemplateConfig {
2034    fn default() -> Self {
2035        Self {
2036            culture_distribution: CultureDistribution::default(),
2037            email_domain: default_email_domain(),
2038            generate_realistic_names: true,
2039        }
2040    }
2041}
2042
2043/// Distribution of name cultures for generation.
2044#[derive(Debug, Clone, Serialize, Deserialize)]
2045pub struct CultureDistribution {
2046    pub western_us: f64,
2047    pub hispanic: f64,
2048    pub german: f64,
2049    pub french: f64,
2050    pub chinese: f64,
2051    pub japanese: f64,
2052    pub indian: f64,
2053}
2054
2055impl Default for CultureDistribution {
2056    fn default() -> Self {
2057        Self {
2058            western_us: 0.40,
2059            hispanic: 0.20,
2060            german: 0.10,
2061            french: 0.05,
2062            chinese: 0.10,
2063            japanese: 0.05,
2064            indian: 0.10,
2065        }
2066    }
2067}
2068
2069/// Description template configuration.
2070#[derive(Debug, Clone, Serialize, Deserialize)]
2071pub struct DescriptionTemplateConfig {
2072    /// Generate header text for journal entries
2073    #[serde(default = "default_true")]
2074    pub generate_header_text: bool,
2075    /// Generate line text for journal entry lines
2076    #[serde(default = "default_true")]
2077    pub generate_line_text: bool,
2078}
2079
2080impl Default for DescriptionTemplateConfig {
2081    fn default() -> Self {
2082        Self {
2083            generate_header_text: true,
2084            generate_line_text: true,
2085        }
2086    }
2087}
2088
2089/// Reference number template configuration.
2090#[derive(Debug, Clone, Serialize, Deserialize)]
2091pub struct ReferenceTemplateConfig {
2092    /// Generate reference numbers
2093    #[serde(default = "default_true")]
2094    pub generate_references: bool,
2095    /// Invoice prefix
2096    #[serde(default = "default_invoice_prefix")]
2097    pub invoice_prefix: String,
2098    /// Purchase order prefix
2099    #[serde(default = "default_po_prefix")]
2100    pub po_prefix: String,
2101    /// Sales order prefix
2102    #[serde(default = "default_so_prefix")]
2103    pub so_prefix: String,
2104}
2105
2106fn default_invoice_prefix() -> String {
2107    "INV".to_string()
2108}
2109fn default_po_prefix() -> String {
2110    "PO".to_string()
2111}
2112fn default_so_prefix() -> String {
2113    "SO".to_string()
2114}
2115
2116impl Default for ReferenceTemplateConfig {
2117    fn default() -> Self {
2118        Self {
2119            generate_references: true,
2120            invoice_prefix: default_invoice_prefix(),
2121            po_prefix: default_po_prefix(),
2122            so_prefix: default_so_prefix(),
2123        }
2124    }
2125}
2126
2127/// Approval workflow configuration.
2128#[derive(Debug, Clone, Serialize, Deserialize)]
2129pub struct ApprovalConfig {
2130    /// Enable approval workflow generation
2131    #[serde(default)]
2132    pub enabled: bool,
2133    /// Threshold below which transactions are auto-approved
2134    #[serde(default = "default_auto_approve_threshold")]
2135    pub auto_approve_threshold: f64,
2136    /// Rate at which approvals are rejected (0.0 to 1.0)
2137    #[serde(default = "default_rejection_rate")]
2138    pub rejection_rate: f64,
2139    /// Rate at which approvals require revision (0.0 to 1.0)
2140    #[serde(default = "default_revision_rate")]
2141    pub revision_rate: f64,
2142    /// Average delay in hours for approval processing
2143    #[serde(default = "default_approval_delay_hours")]
2144    pub average_approval_delay_hours: f64,
2145    /// Approval chain thresholds
2146    #[serde(default)]
2147    pub thresholds: Vec<ApprovalThresholdConfig>,
2148}
2149
2150fn default_auto_approve_threshold() -> f64 {
2151    1000.0
2152}
2153fn default_rejection_rate() -> f64 {
2154    0.02
2155}
2156fn default_revision_rate() -> f64 {
2157    0.05
2158}
2159fn default_approval_delay_hours() -> f64 {
2160    4.0
2161}
2162
2163impl Default for ApprovalConfig {
2164    fn default() -> Self {
2165        Self {
2166            enabled: false,
2167            auto_approve_threshold: default_auto_approve_threshold(),
2168            rejection_rate: default_rejection_rate(),
2169            revision_rate: default_revision_rate(),
2170            average_approval_delay_hours: default_approval_delay_hours(),
2171            thresholds: vec![
2172                ApprovalThresholdConfig {
2173                    amount: 1000.0,
2174                    level: 1,
2175                    roles: vec!["senior_accountant".to_string()],
2176                },
2177                ApprovalThresholdConfig {
2178                    amount: 10000.0,
2179                    level: 2,
2180                    roles: vec!["senior_accountant".to_string(), "controller".to_string()],
2181                },
2182                ApprovalThresholdConfig {
2183                    amount: 100000.0,
2184                    level: 3,
2185                    roles: vec![
2186                        "senior_accountant".to_string(),
2187                        "controller".to_string(),
2188                        "manager".to_string(),
2189                    ],
2190                },
2191                ApprovalThresholdConfig {
2192                    amount: 500000.0,
2193                    level: 4,
2194                    roles: vec![
2195                        "senior_accountant".to_string(),
2196                        "controller".to_string(),
2197                        "manager".to_string(),
2198                        "executive".to_string(),
2199                    ],
2200                },
2201            ],
2202        }
2203    }
2204}
2205
2206/// Configuration for a single approval threshold.
2207#[derive(Debug, Clone, Serialize, Deserialize)]
2208pub struct ApprovalThresholdConfig {
2209    /// Amount threshold
2210    pub amount: f64,
2211    /// Approval level required
2212    pub level: u8,
2213    /// Roles that can approve at this level
2214    pub roles: Vec<String>,
2215}
2216
2217/// Department configuration.
2218#[derive(Debug, Clone, Serialize, Deserialize)]
2219pub struct DepartmentConfig {
2220    /// Enable department assignment
2221    #[serde(default)]
2222    pub enabled: bool,
2223    /// Multiplier for department headcounts
2224    #[serde(default = "default_headcount_multiplier")]
2225    pub headcount_multiplier: f64,
2226    /// Custom department definitions (optional)
2227    #[serde(default)]
2228    pub custom_departments: Vec<CustomDepartmentConfig>,
2229}
2230
2231fn default_headcount_multiplier() -> f64 {
2232    1.0
2233}
2234
2235impl Default for DepartmentConfig {
2236    fn default() -> Self {
2237        Self {
2238            enabled: false,
2239            headcount_multiplier: default_headcount_multiplier(),
2240            custom_departments: Vec::new(),
2241        }
2242    }
2243}
2244
2245/// Custom department definition.
2246#[derive(Debug, Clone, Serialize, Deserialize)]
2247pub struct CustomDepartmentConfig {
2248    /// Department code
2249    pub code: String,
2250    /// Department name
2251    pub name: String,
2252    /// Associated cost center
2253    #[serde(default)]
2254    pub cost_center: Option<String>,
2255    /// Primary business processes
2256    #[serde(default)]
2257    pub primary_processes: Vec<String>,
2258    /// Parent department code
2259    #[serde(default)]
2260    pub parent_code: Option<String>,
2261}
2262
2263// ============================================================================
2264// Master Data Configuration
2265// ============================================================================
2266
2267/// Master data generation configuration.
2268#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2269pub struct MasterDataConfig {
2270    /// Vendor master data settings
2271    #[serde(default)]
2272    pub vendors: VendorMasterConfig,
2273    /// Customer master data settings
2274    #[serde(default)]
2275    pub customers: CustomerMasterConfig,
2276    /// Material master data settings
2277    #[serde(default)]
2278    pub materials: MaterialMasterConfig,
2279    /// Fixed asset master data settings
2280    #[serde(default)]
2281    pub fixed_assets: FixedAssetMasterConfig,
2282    /// Employee master data settings
2283    #[serde(default)]
2284    pub employees: EmployeeMasterConfig,
2285    /// Cost center master data settings
2286    #[serde(default)]
2287    pub cost_centers: CostCenterMasterConfig,
2288}
2289
2290/// Vendor master data configuration.
2291#[derive(Debug, Clone, Serialize, Deserialize)]
2292pub struct VendorMasterConfig {
2293    /// Number of vendors to generate
2294    #[serde(default = "default_vendor_count")]
2295    pub count: usize,
2296    /// Percentage of vendors that are intercompany (0.0 to 1.0)
2297    #[serde(default = "default_intercompany_percent")]
2298    pub intercompany_percent: f64,
2299    /// Payment terms distribution
2300    #[serde(default)]
2301    pub payment_terms_distribution: PaymentTermsDistribution,
2302    /// Vendor behavior distribution
2303    #[serde(default)]
2304    pub behavior_distribution: VendorBehaviorDistribution,
2305    /// Generate bank account details
2306    #[serde(default = "default_true")]
2307    pub generate_bank_accounts: bool,
2308    /// Generate tax IDs
2309    #[serde(default = "default_true")]
2310    pub generate_tax_ids: bool,
2311}
2312
2313fn default_vendor_count() -> usize {
2314    500
2315}
2316
2317fn default_intercompany_percent() -> f64 {
2318    0.05
2319}
2320
2321impl Default for VendorMasterConfig {
2322    fn default() -> Self {
2323        Self {
2324            count: default_vendor_count(),
2325            intercompany_percent: default_intercompany_percent(),
2326            payment_terms_distribution: PaymentTermsDistribution::default(),
2327            behavior_distribution: VendorBehaviorDistribution::default(),
2328            generate_bank_accounts: true,
2329            generate_tax_ids: true,
2330        }
2331    }
2332}
2333
2334/// Payment terms distribution for vendors.
2335#[derive(Debug, Clone, Serialize, Deserialize)]
2336pub struct PaymentTermsDistribution {
2337    /// Net 30 days
2338    pub net_30: f64,
2339    /// Net 60 days
2340    pub net_60: f64,
2341    /// Net 90 days
2342    pub net_90: f64,
2343    /// 2% 10 Net 30 (early payment discount)
2344    pub two_ten_net_30: f64,
2345    /// Due on receipt
2346    pub due_on_receipt: f64,
2347    /// End of month
2348    pub end_of_month: f64,
2349}
2350
2351impl Default for PaymentTermsDistribution {
2352    fn default() -> Self {
2353        Self {
2354            net_30: 0.40,
2355            net_60: 0.20,
2356            net_90: 0.10,
2357            two_ten_net_30: 0.15,
2358            due_on_receipt: 0.05,
2359            end_of_month: 0.10,
2360        }
2361    }
2362}
2363
2364/// Vendor behavior distribution.
2365#[derive(Debug, Clone, Serialize, Deserialize)]
2366pub struct VendorBehaviorDistribution {
2367    /// Reliable vendors (consistent delivery, quality)
2368    pub reliable: f64,
2369    /// Sometimes late vendors
2370    pub sometimes_late: f64,
2371    /// Inconsistent quality vendors
2372    pub inconsistent_quality: f64,
2373    /// Premium vendors (high quality, premium pricing)
2374    pub premium: f64,
2375    /// Budget vendors (lower quality, lower pricing)
2376    pub budget: f64,
2377}
2378
2379impl Default for VendorBehaviorDistribution {
2380    fn default() -> Self {
2381        Self {
2382            reliable: 0.50,
2383            sometimes_late: 0.20,
2384            inconsistent_quality: 0.10,
2385            premium: 0.10,
2386            budget: 0.10,
2387        }
2388    }
2389}
2390
2391/// Customer master data configuration.
2392#[derive(Debug, Clone, Serialize, Deserialize)]
2393pub struct CustomerMasterConfig {
2394    /// Number of customers to generate
2395    #[serde(default = "default_customer_count")]
2396    pub count: usize,
2397    /// Percentage of customers that are intercompany (0.0 to 1.0)
2398    #[serde(default = "default_intercompany_percent")]
2399    pub intercompany_percent: f64,
2400    /// Credit rating distribution
2401    #[serde(default)]
2402    pub credit_rating_distribution: CreditRatingDistribution,
2403    /// Payment behavior distribution
2404    #[serde(default)]
2405    pub payment_behavior_distribution: PaymentBehaviorDistribution,
2406    /// Generate credit limits based on rating
2407    #[serde(default = "default_true")]
2408    pub generate_credit_limits: bool,
2409}
2410
2411fn default_customer_count() -> usize {
2412    2000
2413}
2414
2415impl Default for CustomerMasterConfig {
2416    fn default() -> Self {
2417        Self {
2418            count: default_customer_count(),
2419            intercompany_percent: default_intercompany_percent(),
2420            credit_rating_distribution: CreditRatingDistribution::default(),
2421            payment_behavior_distribution: PaymentBehaviorDistribution::default(),
2422            generate_credit_limits: true,
2423        }
2424    }
2425}
2426
2427/// Credit rating distribution for customers.
2428#[derive(Debug, Clone, Serialize, Deserialize)]
2429pub struct CreditRatingDistribution {
2430    /// AAA rating
2431    pub aaa: f64,
2432    /// AA rating
2433    pub aa: f64,
2434    /// A rating
2435    pub a: f64,
2436    /// BBB rating
2437    pub bbb: f64,
2438    /// BB rating
2439    pub bb: f64,
2440    /// B rating
2441    pub b: f64,
2442    /// Below B rating
2443    pub below_b: f64,
2444}
2445
2446impl Default for CreditRatingDistribution {
2447    fn default() -> Self {
2448        Self {
2449            aaa: 0.05,
2450            aa: 0.10,
2451            a: 0.20,
2452            bbb: 0.30,
2453            bb: 0.20,
2454            b: 0.10,
2455            below_b: 0.05,
2456        }
2457    }
2458}
2459
2460/// Payment behavior distribution for customers.
2461#[derive(Debug, Clone, Serialize, Deserialize)]
2462pub struct PaymentBehaviorDistribution {
2463    /// Always pays early
2464    pub early_payer: f64,
2465    /// Pays on time
2466    pub on_time: f64,
2467    /// Occasionally late
2468    pub occasional_late: f64,
2469    /// Frequently late
2470    pub frequent_late: f64,
2471    /// Takes early payment discounts
2472    pub discount_taker: f64,
2473}
2474
2475impl Default for PaymentBehaviorDistribution {
2476    fn default() -> Self {
2477        Self {
2478            early_payer: 0.10,
2479            on_time: 0.50,
2480            occasional_late: 0.25,
2481            frequent_late: 0.10,
2482            discount_taker: 0.05,
2483        }
2484    }
2485}
2486
2487/// Material master data configuration.
2488#[derive(Debug, Clone, Serialize, Deserialize)]
2489pub struct MaterialMasterConfig {
2490    /// Number of materials to generate
2491    #[serde(default = "default_material_count")]
2492    pub count: usize,
2493    /// Material type distribution
2494    #[serde(default)]
2495    pub type_distribution: MaterialTypeDistribution,
2496    /// Valuation method distribution
2497    #[serde(default)]
2498    pub valuation_distribution: ValuationMethodDistribution,
2499    /// Percentage of materials with BOM (bill of materials)
2500    #[serde(default = "default_bom_percent")]
2501    pub bom_percent: f64,
2502    /// Maximum BOM depth
2503    #[serde(default = "default_max_bom_depth")]
2504    pub max_bom_depth: u8,
2505}
2506
2507fn default_material_count() -> usize {
2508    5000
2509}
2510
2511fn default_bom_percent() -> f64 {
2512    0.20
2513}
2514
2515fn default_max_bom_depth() -> u8 {
2516    3
2517}
2518
2519impl Default for MaterialMasterConfig {
2520    fn default() -> Self {
2521        Self {
2522            count: default_material_count(),
2523            type_distribution: MaterialTypeDistribution::default(),
2524            valuation_distribution: ValuationMethodDistribution::default(),
2525            bom_percent: default_bom_percent(),
2526            max_bom_depth: default_max_bom_depth(),
2527        }
2528    }
2529}
2530
2531/// Material type distribution.
2532#[derive(Debug, Clone, Serialize, Deserialize)]
2533pub struct MaterialTypeDistribution {
2534    /// Raw materials
2535    pub raw_material: f64,
2536    /// Semi-finished goods
2537    pub semi_finished: f64,
2538    /// Finished goods
2539    pub finished_good: f64,
2540    /// Trading goods (purchased for resale)
2541    pub trading_good: f64,
2542    /// Operating supplies
2543    pub operating_supply: f64,
2544    /// Services
2545    pub service: f64,
2546}
2547
2548impl Default for MaterialTypeDistribution {
2549    fn default() -> Self {
2550        Self {
2551            raw_material: 0.30,
2552            semi_finished: 0.15,
2553            finished_good: 0.25,
2554            trading_good: 0.15,
2555            operating_supply: 0.10,
2556            service: 0.05,
2557        }
2558    }
2559}
2560
2561/// Valuation method distribution for materials.
2562#[derive(Debug, Clone, Serialize, Deserialize)]
2563pub struct ValuationMethodDistribution {
2564    /// Standard cost
2565    pub standard_cost: f64,
2566    /// Moving average
2567    pub moving_average: f64,
2568    /// FIFO (First In, First Out)
2569    pub fifo: f64,
2570    /// LIFO (Last In, First Out)
2571    pub lifo: f64,
2572}
2573
2574impl Default for ValuationMethodDistribution {
2575    fn default() -> Self {
2576        Self {
2577            standard_cost: 0.50,
2578            moving_average: 0.30,
2579            fifo: 0.15,
2580            lifo: 0.05,
2581        }
2582    }
2583}
2584
2585/// Fixed asset master data configuration.
2586#[derive(Debug, Clone, Serialize, Deserialize)]
2587pub struct FixedAssetMasterConfig {
2588    /// Number of fixed assets to generate
2589    #[serde(default = "default_asset_count")]
2590    pub count: usize,
2591    /// Asset class distribution
2592    #[serde(default)]
2593    pub class_distribution: AssetClassDistribution,
2594    /// Depreciation method distribution
2595    #[serde(default)]
2596    pub depreciation_distribution: DepreciationMethodDistribution,
2597    /// Percentage of assets that are fully depreciated
2598    #[serde(default = "default_fully_depreciated_percent")]
2599    pub fully_depreciated_percent: f64,
2600    /// Generate acquisition history
2601    #[serde(default = "default_true")]
2602    pub generate_acquisition_history: bool,
2603}
2604
2605fn default_asset_count() -> usize {
2606    800
2607}
2608
2609fn default_fully_depreciated_percent() -> f64 {
2610    0.15
2611}
2612
2613impl Default for FixedAssetMasterConfig {
2614    fn default() -> Self {
2615        Self {
2616            count: default_asset_count(),
2617            class_distribution: AssetClassDistribution::default(),
2618            depreciation_distribution: DepreciationMethodDistribution::default(),
2619            fully_depreciated_percent: default_fully_depreciated_percent(),
2620            generate_acquisition_history: true,
2621        }
2622    }
2623}
2624
2625/// Asset class distribution.
2626#[derive(Debug, Clone, Serialize, Deserialize)]
2627pub struct AssetClassDistribution {
2628    /// Buildings and structures
2629    pub buildings: f64,
2630    /// Machinery and equipment
2631    pub machinery: f64,
2632    /// Vehicles
2633    pub vehicles: f64,
2634    /// IT equipment
2635    pub it_equipment: f64,
2636    /// Furniture and fixtures
2637    pub furniture: f64,
2638    /// Land (non-depreciable)
2639    pub land: f64,
2640    /// Leasehold improvements
2641    pub leasehold: f64,
2642}
2643
2644impl Default for AssetClassDistribution {
2645    fn default() -> Self {
2646        Self {
2647            buildings: 0.15,
2648            machinery: 0.30,
2649            vehicles: 0.15,
2650            it_equipment: 0.20,
2651            furniture: 0.10,
2652            land: 0.05,
2653            leasehold: 0.05,
2654        }
2655    }
2656}
2657
2658/// Depreciation method distribution.
2659#[derive(Debug, Clone, Serialize, Deserialize)]
2660pub struct DepreciationMethodDistribution {
2661    /// Straight line
2662    pub straight_line: f64,
2663    /// Declining balance
2664    pub declining_balance: f64,
2665    /// Double declining balance
2666    pub double_declining: f64,
2667    /// Sum of years' digits
2668    pub sum_of_years: f64,
2669    /// Units of production
2670    pub units_of_production: f64,
2671}
2672
2673impl Default for DepreciationMethodDistribution {
2674    fn default() -> Self {
2675        Self {
2676            straight_line: 0.60,
2677            declining_balance: 0.20,
2678            double_declining: 0.10,
2679            sum_of_years: 0.05,
2680            units_of_production: 0.05,
2681        }
2682    }
2683}
2684
2685/// Employee master data configuration.
2686#[derive(Debug, Clone, Serialize, Deserialize)]
2687pub struct EmployeeMasterConfig {
2688    /// Number of employees to generate
2689    #[serde(default = "default_employee_count")]
2690    pub count: usize,
2691    /// Generate organizational hierarchy
2692    #[serde(default = "default_true")]
2693    pub generate_hierarchy: bool,
2694    /// Maximum hierarchy depth
2695    #[serde(default = "default_hierarchy_depth")]
2696    pub max_hierarchy_depth: u8,
2697    /// Average span of control (direct reports per manager)
2698    #[serde(default = "default_span_of_control")]
2699    pub average_span_of_control: f64,
2700    /// Approval limit distribution by job level
2701    #[serde(default)]
2702    pub approval_limits: ApprovalLimitDistribution,
2703    /// Department distribution
2704    #[serde(default)]
2705    pub department_distribution: EmployeeDepartmentDistribution,
2706}
2707
2708fn default_employee_count() -> usize {
2709    1500
2710}
2711
2712fn default_hierarchy_depth() -> u8 {
2713    6
2714}
2715
2716fn default_span_of_control() -> f64 {
2717    5.0
2718}
2719
2720impl Default for EmployeeMasterConfig {
2721    fn default() -> Self {
2722        Self {
2723            count: default_employee_count(),
2724            generate_hierarchy: true,
2725            max_hierarchy_depth: default_hierarchy_depth(),
2726            average_span_of_control: default_span_of_control(),
2727            approval_limits: ApprovalLimitDistribution::default(),
2728            department_distribution: EmployeeDepartmentDistribution::default(),
2729        }
2730    }
2731}
2732
2733/// Approval limit distribution by job level.
2734#[derive(Debug, Clone, Serialize, Deserialize)]
2735pub struct ApprovalLimitDistribution {
2736    /// Staff level approval limit
2737    #[serde(default = "default_staff_limit")]
2738    pub staff: f64,
2739    /// Senior staff approval limit
2740    #[serde(default = "default_senior_limit")]
2741    pub senior: f64,
2742    /// Manager approval limit
2743    #[serde(default = "default_manager_limit")]
2744    pub manager: f64,
2745    /// Director approval limit
2746    #[serde(default = "default_director_limit")]
2747    pub director: f64,
2748    /// VP approval limit
2749    #[serde(default = "default_vp_limit")]
2750    pub vp: f64,
2751    /// Executive approval limit
2752    #[serde(default = "default_executive_limit")]
2753    pub executive: f64,
2754}
2755
2756fn default_staff_limit() -> f64 {
2757    1000.0
2758}
2759fn default_senior_limit() -> f64 {
2760    5000.0
2761}
2762fn default_manager_limit() -> f64 {
2763    25000.0
2764}
2765fn default_director_limit() -> f64 {
2766    100000.0
2767}
2768fn default_vp_limit() -> f64 {
2769    500000.0
2770}
2771fn default_executive_limit() -> f64 {
2772    f64::INFINITY
2773}
2774
2775impl Default for ApprovalLimitDistribution {
2776    fn default() -> Self {
2777        Self {
2778            staff: default_staff_limit(),
2779            senior: default_senior_limit(),
2780            manager: default_manager_limit(),
2781            director: default_director_limit(),
2782            vp: default_vp_limit(),
2783            executive: default_executive_limit(),
2784        }
2785    }
2786}
2787
2788/// Employee distribution across departments.
2789#[derive(Debug, Clone, Serialize, Deserialize)]
2790pub struct EmployeeDepartmentDistribution {
2791    /// Finance and Accounting
2792    pub finance: f64,
2793    /// Procurement
2794    pub procurement: f64,
2795    /// Sales
2796    pub sales: f64,
2797    /// Warehouse and Logistics
2798    pub warehouse: f64,
2799    /// IT
2800    pub it: f64,
2801    /// Human Resources
2802    pub hr: f64,
2803    /// Operations
2804    pub operations: f64,
2805    /// Executive
2806    pub executive: f64,
2807}
2808
2809impl Default for EmployeeDepartmentDistribution {
2810    fn default() -> Self {
2811        Self {
2812            finance: 0.12,
2813            procurement: 0.10,
2814            sales: 0.25,
2815            warehouse: 0.15,
2816            it: 0.10,
2817            hr: 0.05,
2818            operations: 0.20,
2819            executive: 0.03,
2820        }
2821    }
2822}
2823
2824/// Cost center master data configuration.
2825#[derive(Debug, Clone, Serialize, Deserialize)]
2826pub struct CostCenterMasterConfig {
2827    /// Number of cost centers to generate
2828    #[serde(default = "default_cost_center_count")]
2829    pub count: usize,
2830    /// Generate cost center hierarchy
2831    #[serde(default = "default_true")]
2832    pub generate_hierarchy: bool,
2833    /// Maximum hierarchy depth
2834    #[serde(default = "default_cc_hierarchy_depth")]
2835    pub max_hierarchy_depth: u8,
2836}
2837
2838fn default_cost_center_count() -> usize {
2839    50
2840}
2841
2842fn default_cc_hierarchy_depth() -> u8 {
2843    3
2844}
2845
2846impl Default for CostCenterMasterConfig {
2847    fn default() -> Self {
2848        Self {
2849            count: default_cost_center_count(),
2850            generate_hierarchy: true,
2851            max_hierarchy_depth: default_cc_hierarchy_depth(),
2852        }
2853    }
2854}
2855
2856// ============================================================================
2857// Document Flow Configuration
2858// ============================================================================
2859
2860/// Document flow generation configuration.
2861#[derive(Debug, Clone, Serialize, Deserialize)]
2862pub struct DocumentFlowConfig {
2863    /// P2P (Procure-to-Pay) flow configuration
2864    #[serde(default)]
2865    pub p2p: P2PFlowConfig,
2866    /// O2C (Order-to-Cash) flow configuration
2867    #[serde(default)]
2868    pub o2c: O2CFlowConfig,
2869    /// Generate document reference chains
2870    #[serde(default = "default_true")]
2871    pub generate_document_references: bool,
2872    /// Export document flow graph
2873    #[serde(default)]
2874    pub export_flow_graph: bool,
2875}
2876
2877impl Default for DocumentFlowConfig {
2878    fn default() -> Self {
2879        Self {
2880            p2p: P2PFlowConfig::default(),
2881            o2c: O2CFlowConfig::default(),
2882            generate_document_references: true,
2883            export_flow_graph: false,
2884        }
2885    }
2886}
2887
2888/// P2P (Procure-to-Pay) flow configuration.
2889#[derive(Debug, Clone, Serialize, Deserialize)]
2890pub struct P2PFlowConfig {
2891    /// Enable P2P document flow generation
2892    #[serde(default = "default_true")]
2893    pub enabled: bool,
2894    /// Three-way match success rate (PO-GR-Invoice)
2895    #[serde(default = "default_three_way_match_rate")]
2896    pub three_way_match_rate: f64,
2897    /// Rate of partial deliveries
2898    #[serde(default = "default_partial_delivery_rate")]
2899    pub partial_delivery_rate: f64,
2900    /// Rate of price variances between PO and Invoice
2901    #[serde(default = "default_price_variance_rate")]
2902    pub price_variance_rate: f64,
2903    /// Maximum price variance percentage
2904    #[serde(default = "default_max_price_variance")]
2905    pub max_price_variance_percent: f64,
2906    /// Rate of quantity variances between PO/GR and Invoice
2907    #[serde(default = "default_quantity_variance_rate")]
2908    pub quantity_variance_rate: f64,
2909    /// Average days from PO to goods receipt
2910    #[serde(default = "default_po_to_gr_days")]
2911    pub average_po_to_gr_days: u32,
2912    /// Average days from GR to invoice
2913    #[serde(default = "default_gr_to_invoice_days")]
2914    pub average_gr_to_invoice_days: u32,
2915    /// Average days from invoice to payment
2916    #[serde(default = "default_invoice_to_payment_days")]
2917    pub average_invoice_to_payment_days: u32,
2918    /// PO line count distribution
2919    #[serde(default)]
2920    pub line_count_distribution: DocumentLineCountDistribution,
2921    /// Payment behavior configuration
2922    #[serde(default)]
2923    pub payment_behavior: P2PPaymentBehaviorConfig,
2924    /// Rate of over-deliveries (quantity received exceeds PO quantity)
2925    #[serde(default)]
2926    pub over_delivery_rate: Option<f64>,
2927    /// Rate of early payment discounts being taken
2928    #[serde(default)]
2929    pub early_payment_discount_rate: Option<f64>,
2930}
2931
2932fn default_three_way_match_rate() -> f64 {
2933    0.95
2934}
2935
2936fn default_partial_delivery_rate() -> f64 {
2937    0.15
2938}
2939
2940fn default_price_variance_rate() -> f64 {
2941    0.08
2942}
2943
2944fn default_max_price_variance() -> f64 {
2945    0.05
2946}
2947
2948fn default_quantity_variance_rate() -> f64 {
2949    0.05
2950}
2951
2952fn default_po_to_gr_days() -> u32 {
2953    14
2954}
2955
2956fn default_gr_to_invoice_days() -> u32 {
2957    5
2958}
2959
2960fn default_invoice_to_payment_days() -> u32 {
2961    30
2962}
2963
2964impl Default for P2PFlowConfig {
2965    fn default() -> Self {
2966        Self {
2967            enabled: true,
2968            three_way_match_rate: default_three_way_match_rate(),
2969            partial_delivery_rate: default_partial_delivery_rate(),
2970            price_variance_rate: default_price_variance_rate(),
2971            max_price_variance_percent: default_max_price_variance(),
2972            quantity_variance_rate: default_quantity_variance_rate(),
2973            average_po_to_gr_days: default_po_to_gr_days(),
2974            average_gr_to_invoice_days: default_gr_to_invoice_days(),
2975            average_invoice_to_payment_days: default_invoice_to_payment_days(),
2976            line_count_distribution: DocumentLineCountDistribution::default(),
2977            payment_behavior: P2PPaymentBehaviorConfig::default(),
2978            over_delivery_rate: None,
2979            early_payment_discount_rate: None,
2980        }
2981    }
2982}
2983
2984// ============================================================================
2985// P2P Payment Behavior Configuration
2986// ============================================================================
2987
2988/// P2P payment behavior configuration.
2989#[derive(Debug, Clone, Serialize, Deserialize)]
2990pub struct P2PPaymentBehaviorConfig {
2991    /// Rate of late payments (beyond due date)
2992    #[serde(default = "default_p2p_late_payment_rate")]
2993    pub late_payment_rate: f64,
2994    /// Distribution of late payment days
2995    #[serde(default)]
2996    pub late_payment_days_distribution: LatePaymentDaysDistribution,
2997    /// Rate of partial payments
2998    #[serde(default = "default_p2p_partial_payment_rate")]
2999    pub partial_payment_rate: f64,
3000    /// Rate of payment corrections (NSF, chargebacks, reversals)
3001    #[serde(default = "default_p2p_payment_correction_rate")]
3002    pub payment_correction_rate: f64,
3003    /// Average days until partial payment remainder is paid
3004    #[serde(default = "default_p2p_avg_days_until_remainder")]
3005    pub avg_days_until_remainder: u32,
3006}
3007
3008fn default_p2p_late_payment_rate() -> f64 {
3009    0.15
3010}
3011
3012fn default_p2p_partial_payment_rate() -> f64 {
3013    0.05
3014}
3015
3016fn default_p2p_payment_correction_rate() -> f64 {
3017    0.02
3018}
3019
3020fn default_p2p_avg_days_until_remainder() -> u32 {
3021    30
3022}
3023
3024impl Default for P2PPaymentBehaviorConfig {
3025    fn default() -> Self {
3026        Self {
3027            late_payment_rate: default_p2p_late_payment_rate(),
3028            late_payment_days_distribution: LatePaymentDaysDistribution::default(),
3029            partial_payment_rate: default_p2p_partial_payment_rate(),
3030            payment_correction_rate: default_p2p_payment_correction_rate(),
3031            avg_days_until_remainder: default_p2p_avg_days_until_remainder(),
3032        }
3033    }
3034}
3035
3036/// Distribution of late payment days for P2P.
3037#[derive(Debug, Clone, Serialize, Deserialize)]
3038pub struct LatePaymentDaysDistribution {
3039    /// 1-7 days late (slightly late)
3040    #[serde(default = "default_slightly_late")]
3041    pub slightly_late_1_to_7: f64,
3042    /// 8-14 days late
3043    #[serde(default = "default_late_8_14")]
3044    pub late_8_to_14: f64,
3045    /// 15-30 days late (very late)
3046    #[serde(default = "default_very_late")]
3047    pub very_late_15_to_30: f64,
3048    /// 31-60 days late (severely late)
3049    #[serde(default = "default_severely_late")]
3050    pub severely_late_31_to_60: f64,
3051    /// Over 60 days late (extremely late)
3052    #[serde(default = "default_extremely_late")]
3053    pub extremely_late_over_60: f64,
3054}
3055
3056fn default_slightly_late() -> f64 {
3057    0.50
3058}
3059
3060fn default_late_8_14() -> f64 {
3061    0.25
3062}
3063
3064fn default_very_late() -> f64 {
3065    0.15
3066}
3067
3068fn default_severely_late() -> f64 {
3069    0.07
3070}
3071
3072fn default_extremely_late() -> f64 {
3073    0.03
3074}
3075
3076impl Default for LatePaymentDaysDistribution {
3077    fn default() -> Self {
3078        Self {
3079            slightly_late_1_to_7: default_slightly_late(),
3080            late_8_to_14: default_late_8_14(),
3081            very_late_15_to_30: default_very_late(),
3082            severely_late_31_to_60: default_severely_late(),
3083            extremely_late_over_60: default_extremely_late(),
3084        }
3085    }
3086}
3087
3088/// O2C (Order-to-Cash) flow configuration.
3089#[derive(Debug, Clone, Serialize, Deserialize)]
3090pub struct O2CFlowConfig {
3091    /// Enable O2C document flow generation
3092    #[serde(default = "default_true")]
3093    pub enabled: bool,
3094    /// Credit check failure rate
3095    #[serde(default = "default_credit_check_failure_rate")]
3096    pub credit_check_failure_rate: f64,
3097    /// Rate of partial shipments
3098    #[serde(default = "default_partial_shipment_rate")]
3099    pub partial_shipment_rate: f64,
3100    /// Rate of returns
3101    #[serde(default = "default_return_rate")]
3102    pub return_rate: f64,
3103    /// Bad debt write-off rate
3104    #[serde(default = "default_bad_debt_rate")]
3105    pub bad_debt_rate: f64,
3106    /// Average days from SO to delivery
3107    #[serde(default = "default_so_to_delivery_days")]
3108    pub average_so_to_delivery_days: u32,
3109    /// Average days from delivery to invoice
3110    #[serde(default = "default_delivery_to_invoice_days")]
3111    pub average_delivery_to_invoice_days: u32,
3112    /// Average days from invoice to receipt
3113    #[serde(default = "default_invoice_to_receipt_days")]
3114    pub average_invoice_to_receipt_days: u32,
3115    /// SO line count distribution
3116    #[serde(default)]
3117    pub line_count_distribution: DocumentLineCountDistribution,
3118    /// Cash discount configuration
3119    #[serde(default)]
3120    pub cash_discount: CashDiscountConfig,
3121    /// Payment behavior configuration
3122    #[serde(default)]
3123    pub payment_behavior: O2CPaymentBehaviorConfig,
3124    /// Rate of late payments
3125    #[serde(default)]
3126    pub late_payment_rate: Option<f64>,
3127}
3128
3129fn default_credit_check_failure_rate() -> f64 {
3130    0.02
3131}
3132
3133fn default_partial_shipment_rate() -> f64 {
3134    0.10
3135}
3136
3137fn default_return_rate() -> f64 {
3138    0.03
3139}
3140
3141fn default_bad_debt_rate() -> f64 {
3142    0.01
3143}
3144
3145fn default_so_to_delivery_days() -> u32 {
3146    7
3147}
3148
3149fn default_delivery_to_invoice_days() -> u32 {
3150    1
3151}
3152
3153fn default_invoice_to_receipt_days() -> u32 {
3154    45
3155}
3156
3157impl Default for O2CFlowConfig {
3158    fn default() -> Self {
3159        Self {
3160            enabled: true,
3161            credit_check_failure_rate: default_credit_check_failure_rate(),
3162            partial_shipment_rate: default_partial_shipment_rate(),
3163            return_rate: default_return_rate(),
3164            bad_debt_rate: default_bad_debt_rate(),
3165            average_so_to_delivery_days: default_so_to_delivery_days(),
3166            average_delivery_to_invoice_days: default_delivery_to_invoice_days(),
3167            average_invoice_to_receipt_days: default_invoice_to_receipt_days(),
3168            line_count_distribution: DocumentLineCountDistribution::default(),
3169            cash_discount: CashDiscountConfig::default(),
3170            payment_behavior: O2CPaymentBehaviorConfig::default(),
3171            late_payment_rate: None,
3172        }
3173    }
3174}
3175
3176// ============================================================================
3177// O2C Payment Behavior Configuration
3178// ============================================================================
3179
3180/// O2C payment behavior configuration.
3181#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3182pub struct O2CPaymentBehaviorConfig {
3183    /// Dunning (Mahnung) configuration
3184    #[serde(default)]
3185    pub dunning: DunningConfig,
3186    /// Partial payment configuration
3187    #[serde(default)]
3188    pub partial_payments: PartialPaymentConfig,
3189    /// Short payment configuration (unauthorized deductions)
3190    #[serde(default)]
3191    pub short_payments: ShortPaymentConfig,
3192    /// On-account payment configuration (unapplied payments)
3193    #[serde(default)]
3194    pub on_account_payments: OnAccountPaymentConfig,
3195    /// Payment correction configuration (NSF, chargebacks)
3196    #[serde(default)]
3197    pub payment_corrections: PaymentCorrectionConfig,
3198}
3199
3200/// Dunning (Mahnungen) configuration for AR collections.
3201#[derive(Debug, Clone, Serialize, Deserialize)]
3202pub struct DunningConfig {
3203    /// Enable dunning process
3204    #[serde(default)]
3205    pub enabled: bool,
3206    /// Days overdue for level 1 dunning (1st reminder)
3207    #[serde(default = "default_dunning_level_1_days")]
3208    pub level_1_days_overdue: u32,
3209    /// Days overdue for level 2 dunning (2nd reminder)
3210    #[serde(default = "default_dunning_level_2_days")]
3211    pub level_2_days_overdue: u32,
3212    /// Days overdue for level 3 dunning (final notice)
3213    #[serde(default = "default_dunning_level_3_days")]
3214    pub level_3_days_overdue: u32,
3215    /// Days overdue for collection handover
3216    #[serde(default = "default_collection_days")]
3217    pub collection_days_overdue: u32,
3218    /// Payment rates after each dunning level
3219    #[serde(default)]
3220    pub payment_after_dunning_rates: DunningPaymentRates,
3221    /// Rate of invoices blocked from dunning (disputes)
3222    #[serde(default = "default_dunning_block_rate")]
3223    pub dunning_block_rate: f64,
3224    /// Interest rate per year for overdue amounts
3225    #[serde(default = "default_dunning_interest_rate")]
3226    pub interest_rate_per_year: f64,
3227    /// Fixed dunning charge per letter
3228    #[serde(default = "default_dunning_charge")]
3229    pub dunning_charge: f64,
3230}
3231
3232fn default_dunning_level_1_days() -> u32 {
3233    14
3234}
3235
3236fn default_dunning_level_2_days() -> u32 {
3237    28
3238}
3239
3240fn default_dunning_level_3_days() -> u32 {
3241    42
3242}
3243
3244fn default_collection_days() -> u32 {
3245    60
3246}
3247
3248fn default_dunning_block_rate() -> f64 {
3249    0.05
3250}
3251
3252fn default_dunning_interest_rate() -> f64 {
3253    0.09
3254}
3255
3256fn default_dunning_charge() -> f64 {
3257    25.0
3258}
3259
3260impl Default for DunningConfig {
3261    fn default() -> Self {
3262        Self {
3263            enabled: false,
3264            level_1_days_overdue: default_dunning_level_1_days(),
3265            level_2_days_overdue: default_dunning_level_2_days(),
3266            level_3_days_overdue: default_dunning_level_3_days(),
3267            collection_days_overdue: default_collection_days(),
3268            payment_after_dunning_rates: DunningPaymentRates::default(),
3269            dunning_block_rate: default_dunning_block_rate(),
3270            interest_rate_per_year: default_dunning_interest_rate(),
3271            dunning_charge: default_dunning_charge(),
3272        }
3273    }
3274}
3275
3276/// Payment rates after each dunning level.
3277#[derive(Debug, Clone, Serialize, Deserialize)]
3278pub struct DunningPaymentRates {
3279    /// Rate that pays after level 1 reminder
3280    #[serde(default = "default_after_level_1")]
3281    pub after_level_1: f64,
3282    /// Rate that pays after level 2 reminder
3283    #[serde(default = "default_after_level_2")]
3284    pub after_level_2: f64,
3285    /// Rate that pays after level 3 final notice
3286    #[serde(default = "default_after_level_3")]
3287    pub after_level_3: f64,
3288    /// Rate that pays during collection
3289    #[serde(default = "default_during_collection")]
3290    pub during_collection: f64,
3291    /// Rate that never pays (becomes bad debt)
3292    #[serde(default = "default_never_pay")]
3293    pub never_pay: f64,
3294}
3295
3296fn default_after_level_1() -> f64 {
3297    0.40
3298}
3299
3300fn default_after_level_2() -> f64 {
3301    0.30
3302}
3303
3304fn default_after_level_3() -> f64 {
3305    0.15
3306}
3307
3308fn default_during_collection() -> f64 {
3309    0.05
3310}
3311
3312fn default_never_pay() -> f64 {
3313    0.10
3314}
3315
3316impl Default for DunningPaymentRates {
3317    fn default() -> Self {
3318        Self {
3319            after_level_1: default_after_level_1(),
3320            after_level_2: default_after_level_2(),
3321            after_level_3: default_after_level_3(),
3322            during_collection: default_during_collection(),
3323            never_pay: default_never_pay(),
3324        }
3325    }
3326}
3327
3328/// Partial payment configuration.
3329#[derive(Debug, Clone, Serialize, Deserialize)]
3330pub struct PartialPaymentConfig {
3331    /// Rate of invoices paid partially
3332    #[serde(default = "default_partial_payment_rate")]
3333    pub rate: f64,
3334    /// Distribution of partial payment percentages
3335    #[serde(default)]
3336    pub percentage_distribution: PartialPaymentPercentageDistribution,
3337    /// Average days until remainder is paid
3338    #[serde(default = "default_avg_days_until_remainder")]
3339    pub avg_days_until_remainder: u32,
3340}
3341
3342fn default_partial_payment_rate() -> f64 {
3343    0.08
3344}
3345
3346fn default_avg_days_until_remainder() -> u32 {
3347    30
3348}
3349
3350impl Default for PartialPaymentConfig {
3351    fn default() -> Self {
3352        Self {
3353            rate: default_partial_payment_rate(),
3354            percentage_distribution: PartialPaymentPercentageDistribution::default(),
3355            avg_days_until_remainder: default_avg_days_until_remainder(),
3356        }
3357    }
3358}
3359
3360/// Distribution of partial payment percentages.
3361#[derive(Debug, Clone, Serialize, Deserialize)]
3362pub struct PartialPaymentPercentageDistribution {
3363    /// Pay 25% of invoice
3364    #[serde(default = "default_partial_25")]
3365    pub pay_25_percent: f64,
3366    /// Pay 50% of invoice
3367    #[serde(default = "default_partial_50")]
3368    pub pay_50_percent: f64,
3369    /// Pay 75% of invoice
3370    #[serde(default = "default_partial_75")]
3371    pub pay_75_percent: f64,
3372    /// Pay random percentage
3373    #[serde(default = "default_partial_random")]
3374    pub pay_random_percent: f64,
3375}
3376
3377fn default_partial_25() -> f64 {
3378    0.15
3379}
3380
3381fn default_partial_50() -> f64 {
3382    0.50
3383}
3384
3385fn default_partial_75() -> f64 {
3386    0.25
3387}
3388
3389fn default_partial_random() -> f64 {
3390    0.10
3391}
3392
3393impl Default for PartialPaymentPercentageDistribution {
3394    fn default() -> Self {
3395        Self {
3396            pay_25_percent: default_partial_25(),
3397            pay_50_percent: default_partial_50(),
3398            pay_75_percent: default_partial_75(),
3399            pay_random_percent: default_partial_random(),
3400        }
3401    }
3402}
3403
3404/// Short payment configuration (unauthorized deductions).
3405#[derive(Debug, Clone, Serialize, Deserialize)]
3406pub struct ShortPaymentConfig {
3407    /// Rate of payments that are short
3408    #[serde(default = "default_short_payment_rate")]
3409    pub rate: f64,
3410    /// Distribution of short payment reasons
3411    #[serde(default)]
3412    pub reason_distribution: ShortPaymentReasonDistribution,
3413    /// Maximum percentage that can be short
3414    #[serde(default = "default_max_short_percent")]
3415    pub max_short_percent: f64,
3416}
3417
3418fn default_short_payment_rate() -> f64 {
3419    0.03
3420}
3421
3422fn default_max_short_percent() -> f64 {
3423    0.10
3424}
3425
3426impl Default for ShortPaymentConfig {
3427    fn default() -> Self {
3428        Self {
3429            rate: default_short_payment_rate(),
3430            reason_distribution: ShortPaymentReasonDistribution::default(),
3431            max_short_percent: default_max_short_percent(),
3432        }
3433    }
3434}
3435
3436/// Distribution of short payment reasons.
3437#[derive(Debug, Clone, Serialize, Deserialize)]
3438pub struct ShortPaymentReasonDistribution {
3439    /// Pricing dispute
3440    #[serde(default = "default_pricing_dispute")]
3441    pub pricing_dispute: f64,
3442    /// Quality issue
3443    #[serde(default = "default_quality_issue")]
3444    pub quality_issue: f64,
3445    /// Quantity discrepancy
3446    #[serde(default = "default_quantity_discrepancy")]
3447    pub quantity_discrepancy: f64,
3448    /// Unauthorized deduction
3449    #[serde(default = "default_unauthorized_deduction")]
3450    pub unauthorized_deduction: f64,
3451    /// Early payment discount taken incorrectly
3452    #[serde(default = "default_incorrect_discount")]
3453    pub incorrect_discount: f64,
3454}
3455
3456fn default_pricing_dispute() -> f64 {
3457    0.30
3458}
3459
3460fn default_quality_issue() -> f64 {
3461    0.20
3462}
3463
3464fn default_quantity_discrepancy() -> f64 {
3465    0.20
3466}
3467
3468fn default_unauthorized_deduction() -> f64 {
3469    0.15
3470}
3471
3472fn default_incorrect_discount() -> f64 {
3473    0.15
3474}
3475
3476impl Default for ShortPaymentReasonDistribution {
3477    fn default() -> Self {
3478        Self {
3479            pricing_dispute: default_pricing_dispute(),
3480            quality_issue: default_quality_issue(),
3481            quantity_discrepancy: default_quantity_discrepancy(),
3482            unauthorized_deduction: default_unauthorized_deduction(),
3483            incorrect_discount: default_incorrect_discount(),
3484        }
3485    }
3486}
3487
3488/// On-account payment configuration (unapplied payments).
3489#[derive(Debug, Clone, Serialize, Deserialize)]
3490pub struct OnAccountPaymentConfig {
3491    /// Rate of payments that are on-account (unapplied)
3492    #[serde(default = "default_on_account_rate")]
3493    pub rate: f64,
3494    /// Average days until on-account payments are applied
3495    #[serde(default = "default_avg_days_until_applied")]
3496    pub avg_days_until_applied: u32,
3497}
3498
3499fn default_on_account_rate() -> f64 {
3500    0.02
3501}
3502
3503fn default_avg_days_until_applied() -> u32 {
3504    14
3505}
3506
3507impl Default for OnAccountPaymentConfig {
3508    fn default() -> Self {
3509        Self {
3510            rate: default_on_account_rate(),
3511            avg_days_until_applied: default_avg_days_until_applied(),
3512        }
3513    }
3514}
3515
3516/// Payment correction configuration.
3517#[derive(Debug, Clone, Serialize, Deserialize)]
3518pub struct PaymentCorrectionConfig {
3519    /// Rate of payments requiring correction
3520    #[serde(default = "default_payment_correction_rate")]
3521    pub rate: f64,
3522    /// Distribution of correction types
3523    #[serde(default)]
3524    pub type_distribution: PaymentCorrectionTypeDistribution,
3525}
3526
3527fn default_payment_correction_rate() -> f64 {
3528    0.02
3529}
3530
3531impl Default for PaymentCorrectionConfig {
3532    fn default() -> Self {
3533        Self {
3534            rate: default_payment_correction_rate(),
3535            type_distribution: PaymentCorrectionTypeDistribution::default(),
3536        }
3537    }
3538}
3539
3540/// Distribution of payment correction types.
3541#[derive(Debug, Clone, Serialize, Deserialize)]
3542pub struct PaymentCorrectionTypeDistribution {
3543    /// NSF (Non-sufficient funds) / bounced check
3544    #[serde(default = "default_nsf_rate")]
3545    pub nsf: f64,
3546    /// Chargeback
3547    #[serde(default = "default_chargeback_rate")]
3548    pub chargeback: f64,
3549    /// Wrong amount applied
3550    #[serde(default = "default_wrong_amount_rate")]
3551    pub wrong_amount: f64,
3552    /// Wrong customer applied
3553    #[serde(default = "default_wrong_customer_rate")]
3554    pub wrong_customer: f64,
3555    /// Duplicate payment
3556    #[serde(default = "default_duplicate_payment_rate")]
3557    pub duplicate_payment: f64,
3558}
3559
3560fn default_nsf_rate() -> f64 {
3561    0.30
3562}
3563
3564fn default_chargeback_rate() -> f64 {
3565    0.20
3566}
3567
3568fn default_wrong_amount_rate() -> f64 {
3569    0.20
3570}
3571
3572fn default_wrong_customer_rate() -> f64 {
3573    0.15
3574}
3575
3576fn default_duplicate_payment_rate() -> f64 {
3577    0.15
3578}
3579
3580impl Default for PaymentCorrectionTypeDistribution {
3581    fn default() -> Self {
3582        Self {
3583            nsf: default_nsf_rate(),
3584            chargeback: default_chargeback_rate(),
3585            wrong_amount: default_wrong_amount_rate(),
3586            wrong_customer: default_wrong_customer_rate(),
3587            duplicate_payment: default_duplicate_payment_rate(),
3588        }
3589    }
3590}
3591
3592/// Document line count distribution.
3593#[derive(Debug, Clone, Serialize, Deserialize)]
3594pub struct DocumentLineCountDistribution {
3595    /// Minimum number of lines
3596    #[serde(default = "default_min_lines")]
3597    pub min_lines: u32,
3598    /// Maximum number of lines
3599    #[serde(default = "default_max_lines")]
3600    pub max_lines: u32,
3601    /// Most common line count (mode)
3602    #[serde(default = "default_mode_lines")]
3603    pub mode_lines: u32,
3604}
3605
3606fn default_min_lines() -> u32 {
3607    1
3608}
3609
3610fn default_max_lines() -> u32 {
3611    20
3612}
3613
3614fn default_mode_lines() -> u32 {
3615    3
3616}
3617
3618impl Default for DocumentLineCountDistribution {
3619    fn default() -> Self {
3620        Self {
3621            min_lines: default_min_lines(),
3622            max_lines: default_max_lines(),
3623            mode_lines: default_mode_lines(),
3624        }
3625    }
3626}
3627
3628/// Cash discount configuration.
3629#[derive(Debug, Clone, Serialize, Deserialize)]
3630pub struct CashDiscountConfig {
3631    /// Percentage of invoices eligible for cash discount
3632    #[serde(default = "default_discount_eligible_rate")]
3633    pub eligible_rate: f64,
3634    /// Rate at which customers take the discount
3635    #[serde(default = "default_discount_taken_rate")]
3636    pub taken_rate: f64,
3637    /// Standard discount percentage
3638    #[serde(default = "default_discount_percent")]
3639    pub discount_percent: f64,
3640    /// Days within which discount must be taken
3641    #[serde(default = "default_discount_days")]
3642    pub discount_days: u32,
3643}
3644
3645fn default_discount_eligible_rate() -> f64 {
3646    0.30
3647}
3648
3649fn default_discount_taken_rate() -> f64 {
3650    0.60
3651}
3652
3653fn default_discount_percent() -> f64 {
3654    0.02
3655}
3656
3657fn default_discount_days() -> u32 {
3658    10
3659}
3660
3661impl Default for CashDiscountConfig {
3662    fn default() -> Self {
3663        Self {
3664            eligible_rate: default_discount_eligible_rate(),
3665            taken_rate: default_discount_taken_rate(),
3666            discount_percent: default_discount_percent(),
3667            discount_days: default_discount_days(),
3668        }
3669    }
3670}
3671
3672// ============================================================================
3673// Intercompany Configuration
3674// ============================================================================
3675
3676/// Intercompany transaction configuration.
3677#[derive(Debug, Clone, Serialize, Deserialize)]
3678pub struct IntercompanyConfig {
3679    /// Enable intercompany transaction generation
3680    #[serde(default)]
3681    pub enabled: bool,
3682    /// Rate of transactions that are intercompany
3683    #[serde(default = "default_ic_transaction_rate")]
3684    pub ic_transaction_rate: f64,
3685    /// Transfer pricing method
3686    #[serde(default)]
3687    pub transfer_pricing_method: TransferPricingMethod,
3688    /// Transfer pricing markup percentage (for cost-plus)
3689    #[serde(default = "default_markup_percent")]
3690    pub markup_percent: f64,
3691    /// Generate matched IC pairs (offsetting entries)
3692    #[serde(default = "default_true")]
3693    pub generate_matched_pairs: bool,
3694    /// IC transaction type distribution
3695    #[serde(default)]
3696    pub transaction_type_distribution: ICTransactionTypeDistribution,
3697    /// Generate elimination entries for consolidation
3698    #[serde(default)]
3699    pub generate_eliminations: bool,
3700}
3701
3702fn default_ic_transaction_rate() -> f64 {
3703    0.15
3704}
3705
3706fn default_markup_percent() -> f64 {
3707    0.05
3708}
3709
3710impl Default for IntercompanyConfig {
3711    fn default() -> Self {
3712        Self {
3713            enabled: false,
3714            ic_transaction_rate: default_ic_transaction_rate(),
3715            transfer_pricing_method: TransferPricingMethod::default(),
3716            markup_percent: default_markup_percent(),
3717            generate_matched_pairs: true,
3718            transaction_type_distribution: ICTransactionTypeDistribution::default(),
3719            generate_eliminations: false,
3720        }
3721    }
3722}
3723
3724/// Transfer pricing method.
3725#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
3726#[serde(rename_all = "snake_case")]
3727pub enum TransferPricingMethod {
3728    /// Cost plus a markup
3729    #[default]
3730    CostPlus,
3731    /// Comparable uncontrolled price
3732    ComparableUncontrolled,
3733    /// Resale price method
3734    ResalePrice,
3735    /// Transactional net margin method
3736    TransactionalNetMargin,
3737    /// Profit split method
3738    ProfitSplit,
3739}
3740
3741/// IC transaction type distribution.
3742#[derive(Debug, Clone, Serialize, Deserialize)]
3743pub struct ICTransactionTypeDistribution {
3744    /// Goods sales between entities
3745    pub goods_sale: f64,
3746    /// Services provided
3747    pub service_provided: f64,
3748    /// Intercompany loans
3749    pub loan: f64,
3750    /// Dividends
3751    pub dividend: f64,
3752    /// Management fees
3753    pub management_fee: f64,
3754    /// Royalties
3755    pub royalty: f64,
3756    /// Cost sharing
3757    pub cost_sharing: f64,
3758}
3759
3760impl Default for ICTransactionTypeDistribution {
3761    fn default() -> Self {
3762        Self {
3763            goods_sale: 0.35,
3764            service_provided: 0.20,
3765            loan: 0.10,
3766            dividend: 0.05,
3767            management_fee: 0.15,
3768            royalty: 0.10,
3769            cost_sharing: 0.05,
3770        }
3771    }
3772}
3773
3774// ============================================================================
3775// Balance Configuration
3776// ============================================================================
3777
3778/// Balance and trial balance configuration.
3779#[derive(Debug, Clone, Serialize, Deserialize)]
3780pub struct BalanceConfig {
3781    /// Generate opening balances
3782    #[serde(default)]
3783    pub generate_opening_balances: bool,
3784    /// Generate trial balances
3785    #[serde(default = "default_true")]
3786    pub generate_trial_balances: bool,
3787    /// Target gross margin (for revenue/COGS coherence)
3788    #[serde(default = "default_gross_margin")]
3789    pub target_gross_margin: f64,
3790    /// Target DSO (Days Sales Outstanding)
3791    #[serde(default = "default_dso")]
3792    pub target_dso_days: u32,
3793    /// Target DPO (Days Payable Outstanding)
3794    #[serde(default = "default_dpo")]
3795    pub target_dpo_days: u32,
3796    /// Target current ratio
3797    #[serde(default = "default_current_ratio")]
3798    pub target_current_ratio: f64,
3799    /// Target debt-to-equity ratio
3800    #[serde(default = "default_debt_equity")]
3801    pub target_debt_to_equity: f64,
3802    /// Validate balance sheet equation (A = L + E)
3803    #[serde(default = "default_true")]
3804    pub validate_balance_equation: bool,
3805    /// Reconcile subledgers to GL control accounts
3806    #[serde(default = "default_true")]
3807    pub reconcile_subledgers: bool,
3808}
3809
3810fn default_gross_margin() -> f64 {
3811    0.35
3812}
3813
3814fn default_dso() -> u32 {
3815    45
3816}
3817
3818fn default_dpo() -> u32 {
3819    30
3820}
3821
3822fn default_current_ratio() -> f64 {
3823    1.5
3824}
3825
3826fn default_debt_equity() -> f64 {
3827    0.5
3828}
3829
3830impl Default for BalanceConfig {
3831    fn default() -> Self {
3832        Self {
3833            generate_opening_balances: false,
3834            generate_trial_balances: true,
3835            target_gross_margin: default_gross_margin(),
3836            target_dso_days: default_dso(),
3837            target_dpo_days: default_dpo(),
3838            target_current_ratio: default_current_ratio(),
3839            target_debt_to_equity: default_debt_equity(),
3840            validate_balance_equation: true,
3841            reconcile_subledgers: true,
3842        }
3843    }
3844}
3845
3846// ==========================================================================
3847// OCPM (Object-Centric Process Mining) Configuration
3848// ==========================================================================
3849
3850/// OCPM (Object-Centric Process Mining) configuration.
3851///
3852/// Controls generation of OCEL 2.0 compatible event logs with
3853/// many-to-many event-to-object relationships.
3854#[derive(Debug, Clone, Serialize, Deserialize)]
3855pub struct OcpmConfig {
3856    /// Enable OCPM event log generation
3857    #[serde(default)]
3858    pub enabled: bool,
3859
3860    /// Generate lifecycle events (Start/Complete pairs vs atomic events)
3861    #[serde(default = "default_true")]
3862    pub generate_lifecycle_events: bool,
3863
3864    /// Include object-to-object relationships in output
3865    #[serde(default = "default_true")]
3866    pub include_object_relationships: bool,
3867
3868    /// Compute and export process variants
3869    #[serde(default = "default_true")]
3870    pub compute_variants: bool,
3871
3872    /// Maximum variants to track (0 = unlimited)
3873    #[serde(default)]
3874    pub max_variants: usize,
3875
3876    /// P2P process configuration
3877    #[serde(default)]
3878    pub p2p_process: OcpmProcessConfig,
3879
3880    /// O2C process configuration
3881    #[serde(default)]
3882    pub o2c_process: OcpmProcessConfig,
3883
3884    /// Output format configuration
3885    #[serde(default)]
3886    pub output: OcpmOutputConfig,
3887}
3888
3889impl Default for OcpmConfig {
3890    fn default() -> Self {
3891        Self {
3892            enabled: false,
3893            generate_lifecycle_events: true,
3894            include_object_relationships: true,
3895            compute_variants: true,
3896            max_variants: 0,
3897            p2p_process: OcpmProcessConfig::default(),
3898            o2c_process: OcpmProcessConfig::default(),
3899            output: OcpmOutputConfig::default(),
3900        }
3901    }
3902}
3903
3904/// Process-specific OCPM configuration.
3905#[derive(Debug, Clone, Serialize, Deserialize)]
3906pub struct OcpmProcessConfig {
3907    /// Rework probability (0.0-1.0)
3908    #[serde(default = "default_rework_probability")]
3909    pub rework_probability: f64,
3910
3911    /// Skip step probability (0.0-1.0)
3912    #[serde(default = "default_skip_probability")]
3913    pub skip_step_probability: f64,
3914
3915    /// Out-of-order step probability (0.0-1.0)
3916    #[serde(default = "default_out_of_order_probability")]
3917    pub out_of_order_probability: f64,
3918}
3919
3920// Defaults deliberately produce variant counts and Inductive-Miner fitness
3921// in the range seen in real ERP data (dozens of variants, ~0.7–0.9 fitness).
3922// Lowering them all to 0 yields a single-variant happy-path log.
3923fn default_rework_probability() -> f64 {
3924    0.15
3925}
3926
3927fn default_skip_probability() -> f64 {
3928    0.10
3929}
3930
3931fn default_out_of_order_probability() -> f64 {
3932    0.08
3933}
3934
3935impl Default for OcpmProcessConfig {
3936    fn default() -> Self {
3937        Self {
3938            rework_probability: default_rework_probability(),
3939            skip_step_probability: default_skip_probability(),
3940            out_of_order_probability: default_out_of_order_probability(),
3941        }
3942    }
3943}
3944
3945/// OCPM output format configuration.
3946#[derive(Debug, Clone, Serialize, Deserialize)]
3947pub struct OcpmOutputConfig {
3948    /// Export OCEL 2.0 JSON format
3949    #[serde(default = "default_true")]
3950    pub ocel_json: bool,
3951
3952    /// Export OCEL 2.0 XML format
3953    #[serde(default)]
3954    pub ocel_xml: bool,
3955
3956    /// Export XES 2.0 XML format (IEEE standard for process mining tools)
3957    #[serde(default)]
3958    pub xes: bool,
3959
3960    /// Include lifecycle transitions in XES output (start/complete pairs)
3961    #[serde(default = "default_true")]
3962    pub xes_include_lifecycle: bool,
3963
3964    /// Include resource attributes in XES output
3965    #[serde(default = "default_true")]
3966    pub xes_include_resources: bool,
3967
3968    /// Export flattened CSV for each object type
3969    #[serde(default = "default_true")]
3970    pub flattened_csv: bool,
3971
3972    /// Export event-object relationship table
3973    #[serde(default = "default_true")]
3974    pub event_object_csv: bool,
3975
3976    /// Export object-object relationship table
3977    #[serde(default = "default_true")]
3978    pub object_relationship_csv: bool,
3979
3980    /// Export process variants summary
3981    #[serde(default = "default_true")]
3982    pub variants_csv: bool,
3983
3984    /// Export reference process models (canonical P2P, O2C, R2R)
3985    #[serde(default)]
3986    pub export_reference_models: bool,
3987}
3988
3989impl Default for OcpmOutputConfig {
3990    fn default() -> Self {
3991        Self {
3992            ocel_json: true,
3993            ocel_xml: false,
3994            xes: false,
3995            xes_include_lifecycle: true,
3996            xes_include_resources: true,
3997            flattened_csv: true,
3998            event_object_csv: true,
3999            object_relationship_csv: true,
4000            variants_csv: true,
4001            export_reference_models: false,
4002        }
4003    }
4004}
4005
4006/// Audit engagement and workpaper generation configuration.
4007#[derive(Debug, Clone, Serialize, Deserialize)]
4008pub struct AuditGenerationConfig {
4009    /// Enable audit engagement generation
4010    #[serde(default)]
4011    pub enabled: bool,
4012
4013    /// [Not yet wired] Generate workpaper data — reserved for future fine-grained control.
4014    /// Currently, workpapers are always generated when `enabled = true`.
4015    #[serde(default = "default_true")]
4016    pub generate_workpapers: bool,
4017
4018    /// [Not yet wired] Default engagement type distribution — reserved for future fine-grained control.
4019    /// Currently, engagement types are determined by the audit generator's internal defaults.
4020    #[serde(default)]
4021    pub engagement_types: AuditEngagementTypesConfig,
4022
4023    /// [Not yet wired] Workpaper configuration — reserved for future fine-grained control.
4024    /// Currently, workpaper settings are determined by the audit generator's internal defaults.
4025    #[serde(default)]
4026    pub workpapers: WorkpaperConfig,
4027
4028    /// [Not yet wired] Team configuration — reserved for future fine-grained control.
4029    /// Currently, team composition is determined by the audit generator's internal defaults.
4030    #[serde(default)]
4031    pub team: AuditTeamConfig,
4032
4033    /// [Not yet wired] Review workflow configuration — reserved for future fine-grained control.
4034    /// Currently, review workflow is determined by the audit generator's internal defaults.
4035    #[serde(default)]
4036    pub review: ReviewWorkflowConfig,
4037
4038    /// FSM-driven audit generation configuration.
4039    #[serde(default)]
4040    pub fsm: Option<AuditFsmConfig>,
4041}
4042
4043impl Default for AuditGenerationConfig {
4044    fn default() -> Self {
4045        Self {
4046            enabled: false,
4047            generate_workpapers: true,
4048            engagement_types: AuditEngagementTypesConfig::default(),
4049            workpapers: WorkpaperConfig::default(),
4050            team: AuditTeamConfig::default(),
4051            review: ReviewWorkflowConfig::default(),
4052            fsm: None,
4053        }
4054    }
4055}
4056
4057/// FSM-driven audit generation configuration.
4058#[derive(Debug, Clone, Serialize, Deserialize)]
4059pub struct AuditFsmConfig {
4060    /// Enable FSM-driven audit generation.
4061    #[serde(default)]
4062    pub enabled: bool,
4063
4064    /// Blueprint source: "builtin:fsa", "builtin:ia", or a file path.
4065    #[serde(default = "default_audit_fsm_blueprint")]
4066    pub blueprint: String,
4067
4068    /// Overlay source: "builtin:default", "builtin:thorough", "builtin:rushed", or a file path.
4069    #[serde(default = "default_audit_fsm_overlay")]
4070    pub overlay: String,
4071
4072    /// Depth level override.
4073    #[serde(default)]
4074    pub depth: Option<String>,
4075
4076    /// Discriminator filter.
4077    #[serde(default)]
4078    pub discriminators: std::collections::HashMap<String, Vec<String>>,
4079
4080    /// Event trail output config.
4081    #[serde(default)]
4082    pub event_trail: AuditEventTrailConfig,
4083
4084    /// RNG seed override.
4085    #[serde(default)]
4086    pub seed: Option<u64>,
4087}
4088
4089impl Default for AuditFsmConfig {
4090    fn default() -> Self {
4091        Self {
4092            enabled: false,
4093            blueprint: default_audit_fsm_blueprint(),
4094            overlay: default_audit_fsm_overlay(),
4095            depth: None,
4096            discriminators: std::collections::HashMap::new(),
4097            event_trail: AuditEventTrailConfig::default(),
4098            seed: None,
4099        }
4100    }
4101}
4102
4103fn default_audit_fsm_blueprint() -> String {
4104    "builtin:fsa".to_string()
4105}
4106
4107fn default_audit_fsm_overlay() -> String {
4108    "builtin:default".to_string()
4109}
4110
4111/// Event trail output configuration for FSM-driven audit generation.
4112#[derive(Debug, Clone, Serialize, Deserialize)]
4113pub struct AuditEventTrailConfig {
4114    /// Emit a flat event log.
4115    #[serde(default = "default_true")]
4116    pub flat_log: bool,
4117    /// Project events to OCEL 2.0 format.
4118    #[serde(default)]
4119    pub ocel_projection: bool,
4120}
4121
4122impl Default for AuditEventTrailConfig {
4123    fn default() -> Self {
4124        Self {
4125            flat_log: true,
4126            ocel_projection: false,
4127        }
4128    }
4129}
4130
4131/// Engagement type distribution configuration.
4132#[derive(Debug, Clone, Serialize, Deserialize)]
4133pub struct AuditEngagementTypesConfig {
4134    /// Financial statement audit probability
4135    #[serde(default = "default_financial_audit_prob")]
4136    pub financial_statement: f64,
4137    /// SOX/ICFR audit probability
4138    #[serde(default = "default_sox_audit_prob")]
4139    pub sox_icfr: f64,
4140    /// Integrated audit probability
4141    #[serde(default = "default_integrated_audit_prob")]
4142    pub integrated: f64,
4143    /// Review engagement probability
4144    #[serde(default = "default_review_prob")]
4145    pub review: f64,
4146    /// Agreed-upon procedures probability
4147    #[serde(default = "default_aup_prob")]
4148    pub agreed_upon_procedures: f64,
4149}
4150
4151fn default_financial_audit_prob() -> f64 {
4152    0.40
4153}
4154fn default_sox_audit_prob() -> f64 {
4155    0.20
4156}
4157fn default_integrated_audit_prob() -> f64 {
4158    0.25
4159}
4160fn default_review_prob() -> f64 {
4161    0.10
4162}
4163fn default_aup_prob() -> f64 {
4164    0.05
4165}
4166
4167impl Default for AuditEngagementTypesConfig {
4168    fn default() -> Self {
4169        Self {
4170            financial_statement: default_financial_audit_prob(),
4171            sox_icfr: default_sox_audit_prob(),
4172            integrated: default_integrated_audit_prob(),
4173            review: default_review_prob(),
4174            agreed_upon_procedures: default_aup_prob(),
4175        }
4176    }
4177}
4178
4179/// Workpaper generation configuration.
4180#[derive(Debug, Clone, Serialize, Deserialize)]
4181pub struct WorkpaperConfig {
4182    /// Average workpapers per engagement phase
4183    #[serde(default = "default_workpapers_per_phase")]
4184    pub average_per_phase: usize,
4185
4186    /// Include ISA compliance references
4187    #[serde(default = "default_true")]
4188    pub include_isa_references: bool,
4189
4190    /// Generate sample details
4191    #[serde(default = "default_true")]
4192    pub include_sample_details: bool,
4193
4194    /// Include cross-references between workpapers
4195    #[serde(default = "default_true")]
4196    pub include_cross_references: bool,
4197
4198    /// Sampling configuration
4199    #[serde(default)]
4200    pub sampling: SamplingConfig,
4201}
4202
4203fn default_workpapers_per_phase() -> usize {
4204    5
4205}
4206
4207impl Default for WorkpaperConfig {
4208    fn default() -> Self {
4209        Self {
4210            average_per_phase: default_workpapers_per_phase(),
4211            include_isa_references: true,
4212            include_sample_details: true,
4213            include_cross_references: true,
4214            sampling: SamplingConfig::default(),
4215        }
4216    }
4217}
4218
4219/// Sampling method configuration.
4220#[derive(Debug, Clone, Serialize, Deserialize)]
4221pub struct SamplingConfig {
4222    /// Statistical sampling rate (0.0-1.0)
4223    #[serde(default = "default_statistical_rate")]
4224    pub statistical_rate: f64,
4225    /// Judgmental sampling rate (0.0-1.0)
4226    #[serde(default = "default_judgmental_rate")]
4227    pub judgmental_rate: f64,
4228    /// Haphazard sampling rate (0.0-1.0)
4229    #[serde(default = "default_haphazard_rate")]
4230    pub haphazard_rate: f64,
4231    /// 100% examination rate (0.0-1.0)
4232    #[serde(default = "default_complete_examination_rate")]
4233    pub complete_examination_rate: f64,
4234}
4235
4236fn default_statistical_rate() -> f64 {
4237    0.40
4238}
4239fn default_judgmental_rate() -> f64 {
4240    0.30
4241}
4242fn default_haphazard_rate() -> f64 {
4243    0.20
4244}
4245fn default_complete_examination_rate() -> f64 {
4246    0.10
4247}
4248
4249impl Default for SamplingConfig {
4250    fn default() -> Self {
4251        Self {
4252            statistical_rate: default_statistical_rate(),
4253            judgmental_rate: default_judgmental_rate(),
4254            haphazard_rate: default_haphazard_rate(),
4255            complete_examination_rate: default_complete_examination_rate(),
4256        }
4257    }
4258}
4259
4260/// Audit team configuration.
4261#[derive(Debug, Clone, Serialize, Deserialize)]
4262pub struct AuditTeamConfig {
4263    /// Minimum team size
4264    #[serde(default = "default_min_team_size")]
4265    pub min_team_size: usize,
4266    /// Maximum team size
4267    #[serde(default = "default_max_team_size")]
4268    pub max_team_size: usize,
4269    /// Probability of having a specialist on the team
4270    #[serde(default = "default_specialist_probability")]
4271    pub specialist_probability: f64,
4272}
4273
4274fn default_min_team_size() -> usize {
4275    3
4276}
4277fn default_max_team_size() -> usize {
4278    8
4279}
4280fn default_specialist_probability() -> f64 {
4281    0.30
4282}
4283
4284impl Default for AuditTeamConfig {
4285    fn default() -> Self {
4286        Self {
4287            min_team_size: default_min_team_size(),
4288            max_team_size: default_max_team_size(),
4289            specialist_probability: default_specialist_probability(),
4290        }
4291    }
4292}
4293
4294/// Review workflow configuration.
4295#[derive(Debug, Clone, Serialize, Deserialize)]
4296pub struct ReviewWorkflowConfig {
4297    /// Average days between preparer completion and first review
4298    #[serde(default = "default_review_delay_days")]
4299    pub average_review_delay_days: u32,
4300    /// Probability of review notes requiring rework
4301    #[serde(default = "default_rework_probability_review")]
4302    pub rework_probability: f64,
4303    /// Require partner sign-off for all workpapers
4304    #[serde(default = "default_true")]
4305    pub require_partner_signoff: bool,
4306}
4307
4308fn default_review_delay_days() -> u32 {
4309    2
4310}
4311fn default_rework_probability_review() -> f64 {
4312    0.15
4313}
4314
4315impl Default for ReviewWorkflowConfig {
4316    fn default() -> Self {
4317        Self {
4318            average_review_delay_days: default_review_delay_days(),
4319            rework_probability: default_rework_probability_review(),
4320            require_partner_signoff: true,
4321        }
4322    }
4323}
4324
4325// =============================================================================
4326// Data Quality Configuration
4327// =============================================================================
4328
4329/// Data quality variation settings for realistic flakiness injection.
4330#[derive(Debug, Clone, Serialize, Deserialize)]
4331pub struct DataQualitySchemaConfig {
4332    /// Enable data quality variations
4333    #[serde(default)]
4334    pub enabled: bool,
4335    /// Preset to use (overrides individual settings if set)
4336    #[serde(default)]
4337    pub preset: DataQualityPreset,
4338    /// Missing value injection settings
4339    #[serde(default)]
4340    pub missing_values: MissingValuesSchemaConfig,
4341    /// Typo injection settings
4342    #[serde(default)]
4343    pub typos: TypoSchemaConfig,
4344    /// Format variation settings
4345    #[serde(default)]
4346    pub format_variations: FormatVariationSchemaConfig,
4347    /// Duplicate injection settings
4348    #[serde(default)]
4349    pub duplicates: DuplicateSchemaConfig,
4350    /// Encoding issue settings
4351    #[serde(default)]
4352    pub encoding_issues: EncodingIssueSchemaConfig,
4353    /// Generate quality issue labels for ML training
4354    #[serde(default)]
4355    pub generate_labels: bool,
4356    /// Per-sink quality profiles (different settings for CSV vs JSON etc.)
4357    #[serde(default)]
4358    pub sink_profiles: SinkQualityProfiles,
4359}
4360
4361impl Default for DataQualitySchemaConfig {
4362    fn default() -> Self {
4363        Self {
4364            enabled: false,
4365            preset: DataQualityPreset::None,
4366            missing_values: MissingValuesSchemaConfig::default(),
4367            typos: TypoSchemaConfig::default(),
4368            format_variations: FormatVariationSchemaConfig::default(),
4369            duplicates: DuplicateSchemaConfig::default(),
4370            encoding_issues: EncodingIssueSchemaConfig::default(),
4371            generate_labels: true,
4372            sink_profiles: SinkQualityProfiles::default(),
4373        }
4374    }
4375}
4376
4377impl DataQualitySchemaConfig {
4378    /// Creates a config for a specific preset profile.
4379    pub fn with_preset(preset: DataQualityPreset) -> Self {
4380        let mut config = Self {
4381            preset,
4382            ..Default::default()
4383        };
4384        config.apply_preset();
4385        config
4386    }
4387
4388    /// Applies the preset settings to the individual configuration fields.
4389    /// Call this after deserializing if preset is not Custom or None.
4390    pub fn apply_preset(&mut self) {
4391        if !self.preset.overrides_settings() {
4392            return;
4393        }
4394
4395        self.enabled = true;
4396
4397        // Missing values
4398        self.missing_values.enabled = self.preset.missing_rate() > 0.0;
4399        self.missing_values.rate = self.preset.missing_rate();
4400
4401        // Typos
4402        self.typos.enabled = self.preset.typo_rate() > 0.0;
4403        self.typos.char_error_rate = self.preset.typo_rate();
4404
4405        // Duplicates
4406        self.duplicates.enabled = self.preset.duplicate_rate() > 0.0;
4407        self.duplicates.exact_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
4408        self.duplicates.near_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
4409        self.duplicates.fuzzy_duplicate_ratio = self.preset.duplicate_rate() * 0.2;
4410
4411        // Format variations
4412        self.format_variations.enabled = self.preset.format_variations_enabled();
4413
4414        // Encoding issues
4415        self.encoding_issues.enabled = self.preset.encoding_issues_enabled();
4416        self.encoding_issues.rate = self.preset.encoding_issue_rate();
4417
4418        // OCR errors for typos in legacy preset
4419        if self.preset.ocr_errors_enabled() {
4420            self.typos.type_weights.ocr_errors = 0.3;
4421        }
4422    }
4423
4424    /// Returns the effective missing value rate (considering preset).
4425    pub fn effective_missing_rate(&self) -> f64 {
4426        if self.preset.overrides_settings() {
4427            self.preset.missing_rate()
4428        } else {
4429            self.missing_values.rate
4430        }
4431    }
4432
4433    /// Returns the effective typo rate (considering preset).
4434    pub fn effective_typo_rate(&self) -> f64 {
4435        if self.preset.overrides_settings() {
4436            self.preset.typo_rate()
4437        } else {
4438            self.typos.char_error_rate
4439        }
4440    }
4441
4442    /// Returns the effective duplicate rate (considering preset).
4443    pub fn effective_duplicate_rate(&self) -> f64 {
4444        if self.preset.overrides_settings() {
4445            self.preset.duplicate_rate()
4446        } else {
4447            self.duplicates.exact_duplicate_ratio
4448                + self.duplicates.near_duplicate_ratio
4449                + self.duplicates.fuzzy_duplicate_ratio
4450        }
4451    }
4452
4453    /// Creates a clean profile config.
4454    pub fn clean() -> Self {
4455        Self::with_preset(DataQualityPreset::Clean)
4456    }
4457
4458    /// Creates a noisy profile config.
4459    pub fn noisy() -> Self {
4460        Self::with_preset(DataQualityPreset::Noisy)
4461    }
4462
4463    /// Creates a legacy profile config.
4464    pub fn legacy() -> Self {
4465        Self::with_preset(DataQualityPreset::Legacy)
4466    }
4467}
4468
4469/// Preset configurations for common data quality scenarios.
4470#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4471#[serde(rename_all = "snake_case")]
4472pub enum DataQualityPreset {
4473    /// No data quality variations (clean data)
4474    #[default]
4475    None,
4476    /// Minimal variations (very clean data with rare issues)
4477    Minimal,
4478    /// Normal variations (realistic enterprise data quality)
4479    Normal,
4480    /// High variations (messy data for stress testing)
4481    High,
4482    /// Custom (use individual settings)
4483    Custom,
4484
4485    // ========================================
4486    // ML-Oriented Profiles (Phase 2.1)
4487    // ========================================
4488    /// Clean profile for ML training - minimal data quality issues
4489    /// Missing: 0.1%, Typos: 0.05%, Duplicates: 0%, Format: None
4490    Clean,
4491    /// Noisy profile simulating typical production data issues
4492    /// Missing: 5%, Typos: 2%, Duplicates: 1%, Format: Medium
4493    Noisy,
4494    /// Legacy profile simulating migrated/OCR'd historical data
4495    /// Missing: 10%, Typos: 5%, Duplicates: 3%, Format: Heavy + OCR
4496    Legacy,
4497}
4498
4499impl DataQualityPreset {
4500    /// Returns the missing value rate for this preset.
4501    pub fn missing_rate(&self) -> f64 {
4502        match self {
4503            DataQualityPreset::None => 0.0,
4504            DataQualityPreset::Minimal => 0.005,
4505            DataQualityPreset::Normal => 0.02,
4506            DataQualityPreset::High => 0.08,
4507            DataQualityPreset::Custom => 0.01, // Use config value
4508            DataQualityPreset::Clean => 0.001,
4509            DataQualityPreset::Noisy => 0.05,
4510            DataQualityPreset::Legacy => 0.10,
4511        }
4512    }
4513
4514    /// Returns the typo rate for this preset.
4515    pub fn typo_rate(&self) -> f64 {
4516        match self {
4517            DataQualityPreset::None => 0.0,
4518            DataQualityPreset::Minimal => 0.0005,
4519            DataQualityPreset::Normal => 0.002,
4520            DataQualityPreset::High => 0.01,
4521            DataQualityPreset::Custom => 0.001, // Use config value
4522            DataQualityPreset::Clean => 0.0005,
4523            DataQualityPreset::Noisy => 0.02,
4524            DataQualityPreset::Legacy => 0.05,
4525        }
4526    }
4527
4528    /// Returns the duplicate rate for this preset.
4529    pub fn duplicate_rate(&self) -> f64 {
4530        match self {
4531            DataQualityPreset::None => 0.0,
4532            DataQualityPreset::Minimal => 0.001,
4533            DataQualityPreset::Normal => 0.005,
4534            DataQualityPreset::High => 0.02,
4535            DataQualityPreset::Custom => 0.0, // Use config value
4536            DataQualityPreset::Clean => 0.0,
4537            DataQualityPreset::Noisy => 0.01,
4538            DataQualityPreset::Legacy => 0.03,
4539        }
4540    }
4541
4542    /// Returns whether format variations are enabled for this preset.
4543    pub fn format_variations_enabled(&self) -> bool {
4544        match self {
4545            DataQualityPreset::None | DataQualityPreset::Clean => false,
4546            DataQualityPreset::Minimal => true,
4547            DataQualityPreset::Normal => true,
4548            DataQualityPreset::High => true,
4549            DataQualityPreset::Custom => true,
4550            DataQualityPreset::Noisy => true,
4551            DataQualityPreset::Legacy => true,
4552        }
4553    }
4554
4555    /// Returns whether OCR-style errors are enabled for this preset.
4556    pub fn ocr_errors_enabled(&self) -> bool {
4557        matches!(self, DataQualityPreset::Legacy | DataQualityPreset::High)
4558    }
4559
4560    /// Returns whether encoding issues are enabled for this preset.
4561    pub fn encoding_issues_enabled(&self) -> bool {
4562        matches!(
4563            self,
4564            DataQualityPreset::Legacy | DataQualityPreset::High | DataQualityPreset::Noisy
4565        )
4566    }
4567
4568    /// Returns the encoding issue rate for this preset.
4569    pub fn encoding_issue_rate(&self) -> f64 {
4570        match self {
4571            DataQualityPreset::None | DataQualityPreset::Clean | DataQualityPreset::Minimal => 0.0,
4572            DataQualityPreset::Normal => 0.002,
4573            DataQualityPreset::High => 0.01,
4574            DataQualityPreset::Custom => 0.0,
4575            DataQualityPreset::Noisy => 0.005,
4576            DataQualityPreset::Legacy => 0.02,
4577        }
4578    }
4579
4580    /// Returns true if this preset overrides individual settings.
4581    pub fn overrides_settings(&self) -> bool {
4582        !matches!(self, DataQualityPreset::Custom | DataQualityPreset::None)
4583    }
4584
4585    /// Returns a human-readable description of this preset.
4586    pub fn description(&self) -> &'static str {
4587        match self {
4588            DataQualityPreset::None => "No data quality issues (pristine data)",
4589            DataQualityPreset::Minimal => "Very rare data quality issues",
4590            DataQualityPreset::Normal => "Realistic enterprise data quality",
4591            DataQualityPreset::High => "Messy data for stress testing",
4592            DataQualityPreset::Custom => "Custom settings from configuration",
4593            DataQualityPreset::Clean => "ML-ready clean data with minimal issues",
4594            DataQualityPreset::Noisy => "Typical production data with moderate issues",
4595            DataQualityPreset::Legacy => "Legacy/migrated data with heavy issues and OCR errors",
4596        }
4597    }
4598}
4599
4600/// Missing value injection configuration.
4601#[derive(Debug, Clone, Serialize, Deserialize)]
4602pub struct MissingValuesSchemaConfig {
4603    /// Enable missing value injection
4604    #[serde(default)]
4605    pub enabled: bool,
4606    /// Global missing rate (0.0 to 1.0)
4607    #[serde(default = "default_missing_rate")]
4608    pub rate: f64,
4609    /// Missing value strategy
4610    #[serde(default)]
4611    pub strategy: MissingValueStrategy,
4612    /// Field-specific rates (field name -> rate)
4613    #[serde(default)]
4614    pub field_rates: std::collections::HashMap<String, f64>,
4615    /// Fields that should never have missing values
4616    #[serde(default)]
4617    pub protected_fields: Vec<String>,
4618}
4619
4620fn default_missing_rate() -> f64 {
4621    0.01
4622}
4623
4624impl Default for MissingValuesSchemaConfig {
4625    fn default() -> Self {
4626        Self {
4627            enabled: false,
4628            rate: default_missing_rate(),
4629            strategy: MissingValueStrategy::Mcar,
4630            field_rates: std::collections::HashMap::new(),
4631            protected_fields: vec![
4632                "document_id".to_string(),
4633                "company_code".to_string(),
4634                "posting_date".to_string(),
4635            ],
4636        }
4637    }
4638}
4639
4640/// Missing value strategy types.
4641#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4642#[serde(rename_all = "snake_case")]
4643pub enum MissingValueStrategy {
4644    /// Missing Completely At Random - equal probability for all values
4645    #[default]
4646    Mcar,
4647    /// Missing At Random - depends on other observed values
4648    Mar,
4649    /// Missing Not At Random - depends on the value itself
4650    Mnar,
4651    /// Systematic - entire field groups missing together
4652    Systematic,
4653}
4654
4655/// Typo injection configuration.
4656#[derive(Debug, Clone, Serialize, Deserialize)]
4657pub struct TypoSchemaConfig {
4658    /// Enable typo injection
4659    #[serde(default)]
4660    pub enabled: bool,
4661    /// Character error rate (per character, not per field)
4662    #[serde(default = "default_typo_rate")]
4663    pub char_error_rate: f64,
4664    /// Typo type weights
4665    #[serde(default)]
4666    pub type_weights: TypoTypeWeights,
4667    /// Fields that should never have typos
4668    #[serde(default)]
4669    pub protected_fields: Vec<String>,
4670}
4671
4672fn default_typo_rate() -> f64 {
4673    0.001
4674}
4675
4676impl Default for TypoSchemaConfig {
4677    fn default() -> Self {
4678        Self {
4679            enabled: false,
4680            char_error_rate: default_typo_rate(),
4681            type_weights: TypoTypeWeights::default(),
4682            protected_fields: vec![
4683                "document_id".to_string(),
4684                "gl_account".to_string(),
4685                "company_code".to_string(),
4686            ],
4687        }
4688    }
4689}
4690
4691/// Weights for different typo types.
4692#[derive(Debug, Clone, Serialize, Deserialize)]
4693pub struct TypoTypeWeights {
4694    /// Keyboard-adjacent substitution (e.g., 'a' -> 's')
4695    #[serde(default = "default_substitution_weight")]
4696    pub substitution: f64,
4697    /// Adjacent character transposition (e.g., 'ab' -> 'ba')
4698    #[serde(default = "default_transposition_weight")]
4699    pub transposition: f64,
4700    /// Character insertion
4701    #[serde(default = "default_insertion_weight")]
4702    pub insertion: f64,
4703    /// Character deletion
4704    #[serde(default = "default_deletion_weight")]
4705    pub deletion: f64,
4706    /// OCR-style errors (e.g., '0' -> 'O')
4707    #[serde(default = "default_ocr_weight")]
4708    pub ocr_errors: f64,
4709    /// Homophone substitution (e.g., 'their' -> 'there')
4710    #[serde(default = "default_homophone_weight")]
4711    pub homophones: f64,
4712}
4713
4714fn default_substitution_weight() -> f64 {
4715    0.35
4716}
4717fn default_transposition_weight() -> f64 {
4718    0.25
4719}
4720fn default_insertion_weight() -> f64 {
4721    0.10
4722}
4723fn default_deletion_weight() -> f64 {
4724    0.15
4725}
4726fn default_ocr_weight() -> f64 {
4727    0.10
4728}
4729fn default_homophone_weight() -> f64 {
4730    0.05
4731}
4732
4733impl Default for TypoTypeWeights {
4734    fn default() -> Self {
4735        Self {
4736            substitution: default_substitution_weight(),
4737            transposition: default_transposition_weight(),
4738            insertion: default_insertion_weight(),
4739            deletion: default_deletion_weight(),
4740            ocr_errors: default_ocr_weight(),
4741            homophones: default_homophone_weight(),
4742        }
4743    }
4744}
4745
4746/// Format variation configuration.
4747#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4748pub struct FormatVariationSchemaConfig {
4749    /// Enable format variations
4750    #[serde(default)]
4751    pub enabled: bool,
4752    /// Date format variation settings
4753    #[serde(default)]
4754    pub dates: DateFormatVariationConfig,
4755    /// Amount format variation settings
4756    #[serde(default)]
4757    pub amounts: AmountFormatVariationConfig,
4758    /// Identifier format variation settings
4759    #[serde(default)]
4760    pub identifiers: IdentifierFormatVariationConfig,
4761}
4762
4763/// Date format variation configuration.
4764#[derive(Debug, Clone, Serialize, Deserialize)]
4765pub struct DateFormatVariationConfig {
4766    /// Enable date format variations
4767    #[serde(default)]
4768    pub enabled: bool,
4769    /// Overall variation rate
4770    #[serde(default = "default_date_variation_rate")]
4771    pub rate: f64,
4772    /// Include ISO format (2024-01-15)
4773    #[serde(default = "default_true")]
4774    pub iso_format: bool,
4775    /// Include US format (01/15/2024)
4776    #[serde(default)]
4777    pub us_format: bool,
4778    /// Include EU format (15.01.2024)
4779    #[serde(default)]
4780    pub eu_format: bool,
4781    /// Include long format (January 15, 2024)
4782    #[serde(default)]
4783    pub long_format: bool,
4784}
4785
4786fn default_date_variation_rate() -> f64 {
4787    0.05
4788}
4789
4790impl Default for DateFormatVariationConfig {
4791    fn default() -> Self {
4792        Self {
4793            enabled: false,
4794            rate: default_date_variation_rate(),
4795            iso_format: true,
4796            us_format: false,
4797            eu_format: false,
4798            long_format: false,
4799        }
4800    }
4801}
4802
4803/// Amount format variation configuration.
4804#[derive(Debug, Clone, Serialize, Deserialize)]
4805pub struct AmountFormatVariationConfig {
4806    /// Enable amount format variations
4807    #[serde(default)]
4808    pub enabled: bool,
4809    /// Overall variation rate
4810    #[serde(default = "default_amount_variation_rate")]
4811    pub rate: f64,
4812    /// Include US comma format (1,234.56)
4813    #[serde(default)]
4814    pub us_comma_format: bool,
4815    /// Include EU format (1.234,56)
4816    #[serde(default)]
4817    pub eu_format: bool,
4818    /// Include currency prefix ($1,234.56)
4819    #[serde(default)]
4820    pub currency_prefix: bool,
4821    /// Include accounting format with parentheses for negatives
4822    #[serde(default)]
4823    pub accounting_format: bool,
4824}
4825
4826fn default_amount_variation_rate() -> f64 {
4827    0.02
4828}
4829
4830impl Default for AmountFormatVariationConfig {
4831    fn default() -> Self {
4832        Self {
4833            enabled: false,
4834            rate: default_amount_variation_rate(),
4835            us_comma_format: false,
4836            eu_format: false,
4837            currency_prefix: false,
4838            accounting_format: false,
4839        }
4840    }
4841}
4842
4843/// Identifier format variation configuration.
4844#[derive(Debug, Clone, Serialize, Deserialize)]
4845pub struct IdentifierFormatVariationConfig {
4846    /// Enable identifier format variations
4847    #[serde(default)]
4848    pub enabled: bool,
4849    /// Overall variation rate
4850    #[serde(default = "default_identifier_variation_rate")]
4851    pub rate: f64,
4852    /// Case variations (uppercase, lowercase, mixed)
4853    #[serde(default)]
4854    pub case_variations: bool,
4855    /// Padding variations (leading zeros)
4856    #[serde(default)]
4857    pub padding_variations: bool,
4858    /// Separator variations (dash vs underscore)
4859    #[serde(default)]
4860    pub separator_variations: bool,
4861}
4862
4863fn default_identifier_variation_rate() -> f64 {
4864    0.02
4865}
4866
4867impl Default for IdentifierFormatVariationConfig {
4868    fn default() -> Self {
4869        Self {
4870            enabled: false,
4871            rate: default_identifier_variation_rate(),
4872            case_variations: false,
4873            padding_variations: false,
4874            separator_variations: false,
4875        }
4876    }
4877}
4878
4879/// Duplicate injection configuration.
4880#[derive(Debug, Clone, Serialize, Deserialize)]
4881pub struct DuplicateSchemaConfig {
4882    /// Enable duplicate injection
4883    #[serde(default)]
4884    pub enabled: bool,
4885    /// Overall duplicate rate
4886    #[serde(default = "default_duplicate_rate")]
4887    pub rate: f64,
4888    /// Exact duplicate proportion (out of duplicates)
4889    #[serde(default = "default_exact_duplicate_ratio")]
4890    pub exact_duplicate_ratio: f64,
4891    /// Near duplicate proportion (slight variations)
4892    #[serde(default = "default_near_duplicate_ratio")]
4893    pub near_duplicate_ratio: f64,
4894    /// Fuzzy duplicate proportion (typos in key fields)
4895    #[serde(default = "default_fuzzy_duplicate_ratio")]
4896    pub fuzzy_duplicate_ratio: f64,
4897    /// Maximum date offset for near/fuzzy duplicates (days)
4898    #[serde(default = "default_max_date_offset")]
4899    pub max_date_offset_days: u32,
4900    /// Maximum amount variance for near duplicates (fraction)
4901    #[serde(default = "default_max_amount_variance")]
4902    pub max_amount_variance: f64,
4903}
4904
4905fn default_duplicate_rate() -> f64 {
4906    0.005
4907}
4908fn default_exact_duplicate_ratio() -> f64 {
4909    0.4
4910}
4911fn default_near_duplicate_ratio() -> f64 {
4912    0.35
4913}
4914fn default_fuzzy_duplicate_ratio() -> f64 {
4915    0.25
4916}
4917fn default_max_date_offset() -> u32 {
4918    3
4919}
4920fn default_max_amount_variance() -> f64 {
4921    0.01
4922}
4923
4924impl Default for DuplicateSchemaConfig {
4925    fn default() -> Self {
4926        Self {
4927            enabled: false,
4928            rate: default_duplicate_rate(),
4929            exact_duplicate_ratio: default_exact_duplicate_ratio(),
4930            near_duplicate_ratio: default_near_duplicate_ratio(),
4931            fuzzy_duplicate_ratio: default_fuzzy_duplicate_ratio(),
4932            max_date_offset_days: default_max_date_offset(),
4933            max_amount_variance: default_max_amount_variance(),
4934        }
4935    }
4936}
4937
4938/// Encoding issue configuration.
4939#[derive(Debug, Clone, Serialize, Deserialize)]
4940pub struct EncodingIssueSchemaConfig {
4941    /// Enable encoding issue injection
4942    #[serde(default)]
4943    pub enabled: bool,
4944    /// Overall encoding issue rate
4945    #[serde(default = "default_encoding_rate")]
4946    pub rate: f64,
4947    /// Include mojibake (UTF-8/Latin-1 confusion)
4948    #[serde(default)]
4949    pub mojibake: bool,
4950    /// Include HTML entity corruption
4951    #[serde(default)]
4952    pub html_entities: bool,
4953    /// Include BOM issues
4954    #[serde(default)]
4955    pub bom_issues: bool,
4956}
4957
4958fn default_encoding_rate() -> f64 {
4959    0.001
4960}
4961
4962impl Default for EncodingIssueSchemaConfig {
4963    fn default() -> Self {
4964        Self {
4965            enabled: false,
4966            rate: default_encoding_rate(),
4967            mojibake: false,
4968            html_entities: false,
4969            bom_issues: false,
4970        }
4971    }
4972}
4973
4974/// Per-sink quality profiles for different output formats.
4975#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4976pub struct SinkQualityProfiles {
4977    /// CSV-specific quality settings
4978    #[serde(default)]
4979    pub csv: Option<SinkQualityOverride>,
4980    /// JSON-specific quality settings
4981    #[serde(default)]
4982    pub json: Option<SinkQualityOverride>,
4983    /// Parquet-specific quality settings
4984    #[serde(default)]
4985    pub parquet: Option<SinkQualityOverride>,
4986}
4987
4988/// Quality setting overrides for a specific sink type.
4989#[derive(Debug, Clone, Serialize, Deserialize)]
4990pub struct SinkQualityOverride {
4991    /// Override enabled state
4992    pub enabled: Option<bool>,
4993    /// Override missing value rate
4994    pub missing_rate: Option<f64>,
4995    /// Override typo rate
4996    pub typo_rate: Option<f64>,
4997    /// Override format variation rate
4998    pub format_variation_rate: Option<f64>,
4999    /// Override duplicate rate
5000    pub duplicate_rate: Option<f64>,
5001}
5002
5003// =============================================================================
5004// Accounting Standards Configuration
5005// =============================================================================
5006
5007/// Accounting standards framework configuration for generating standards-compliant data.
5008///
5009/// Supports US GAAP, IFRS, and French GAAP (PCG) frameworks with specific standards:
5010/// - ASC 606/IFRS 15/PCG: Revenue Recognition
5011/// - ASC 842/IFRS 16/PCG: Leases
5012/// - ASC 820/IFRS 13/PCG: Fair Value Measurement
5013/// - ASC 360/IAS 36/PCG: Impairment
5014#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5015pub struct AccountingStandardsConfig {
5016    /// Enable accounting standards generation
5017    #[serde(default)]
5018    pub enabled: bool,
5019
5020    /// Accounting framework to use.
5021    /// When `None`, the country pack's `accounting.framework` is used as fallback;
5022    /// if that is also absent the orchestrator defaults to US GAAP.
5023    #[serde(default, skip_serializing_if = "Option::is_none")]
5024    pub framework: Option<AccountingFrameworkConfig>,
5025
5026    /// Revenue recognition configuration (ASC 606/IFRS 15)
5027    #[serde(default)]
5028    pub revenue_recognition: RevenueRecognitionConfig,
5029
5030    /// Lease accounting configuration (ASC 842/IFRS 16)
5031    #[serde(default)]
5032    pub leases: LeaseAccountingConfig,
5033
5034    /// Fair value measurement configuration (ASC 820/IFRS 13)
5035    #[serde(default)]
5036    pub fair_value: FairValueConfig,
5037
5038    /// Impairment testing configuration (ASC 360/IAS 36)
5039    #[serde(default)]
5040    pub impairment: ImpairmentConfig,
5041
5042    /// Business combination configuration (IFRS 3 / ASC 805)
5043    #[serde(default)]
5044    pub business_combinations: BusinessCombinationsConfig,
5045
5046    /// Expected Credit Loss configuration (IFRS 9 / ASC 326)
5047    #[serde(default)]
5048    pub expected_credit_loss: EclConfig,
5049
5050    /// Generate framework differences for dual reporting
5051    #[serde(default)]
5052    pub generate_differences: bool,
5053}
5054
5055/// Accounting framework selection.
5056#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5057#[serde(rename_all = "snake_case")]
5058pub enum AccountingFrameworkConfig {
5059    /// US Generally Accepted Accounting Principles
5060    #[default]
5061    UsGaap,
5062    /// International Financial Reporting Standards
5063    Ifrs,
5064    /// Generate data for both frameworks with reconciliation
5065    DualReporting,
5066    /// French GAAP (Plan Comptable Général – PCG)
5067    FrenchGaap,
5068    /// German GAAP (Handelsgesetzbuch – HGB, §238-263)
5069    GermanGaap,
5070}
5071
5072/// Revenue recognition configuration (ASC 606/IFRS 15).
5073#[derive(Debug, Clone, Serialize, Deserialize)]
5074pub struct RevenueRecognitionConfig {
5075    /// Enable revenue recognition generation
5076    #[serde(default)]
5077    pub enabled: bool,
5078
5079    /// Generate customer contracts
5080    #[serde(default = "default_true")]
5081    pub generate_contracts: bool,
5082
5083    /// Average number of performance obligations per contract
5084    #[serde(default = "default_avg_obligations")]
5085    pub avg_obligations_per_contract: f64,
5086
5087    /// Rate of contracts with variable consideration
5088    #[serde(default = "default_variable_consideration_rate")]
5089    pub variable_consideration_rate: f64,
5090
5091    /// Rate of over-time revenue recognition (vs point-in-time)
5092    #[serde(default = "default_over_time_rate")]
5093    pub over_time_recognition_rate: f64,
5094
5095    /// Number of contracts to generate
5096    #[serde(default = "default_contract_count")]
5097    pub contract_count: usize,
5098}
5099
5100fn default_avg_obligations() -> f64 {
5101    2.0
5102}
5103
5104fn default_variable_consideration_rate() -> f64 {
5105    0.15
5106}
5107
5108fn default_over_time_rate() -> f64 {
5109    0.30
5110}
5111
5112fn default_contract_count() -> usize {
5113    100
5114}
5115
5116impl Default for RevenueRecognitionConfig {
5117    fn default() -> Self {
5118        Self {
5119            enabled: false,
5120            generate_contracts: true,
5121            avg_obligations_per_contract: default_avg_obligations(),
5122            variable_consideration_rate: default_variable_consideration_rate(),
5123            over_time_recognition_rate: default_over_time_rate(),
5124            contract_count: default_contract_count(),
5125        }
5126    }
5127}
5128
5129/// Lease accounting configuration (ASC 842/IFRS 16).
5130#[derive(Debug, Clone, Serialize, Deserialize)]
5131pub struct LeaseAccountingConfig {
5132    /// Enable lease accounting generation
5133    #[serde(default)]
5134    pub enabled: bool,
5135
5136    /// Number of leases to generate
5137    #[serde(default = "default_lease_count")]
5138    pub lease_count: usize,
5139
5140    /// Percentage of finance leases (vs operating)
5141    #[serde(default = "default_finance_lease_pct")]
5142    pub finance_lease_percent: f64,
5143
5144    /// Average lease term in months
5145    #[serde(default = "default_avg_lease_term")]
5146    pub avg_lease_term_months: u32,
5147
5148    /// Generate amortization schedules
5149    #[serde(default = "default_true")]
5150    pub generate_amortization: bool,
5151
5152    /// Real estate lease percentage
5153    #[serde(default = "default_real_estate_pct")]
5154    pub real_estate_percent: f64,
5155}
5156
5157fn default_lease_count() -> usize {
5158    50
5159}
5160
5161fn default_finance_lease_pct() -> f64 {
5162    0.30
5163}
5164
5165fn default_avg_lease_term() -> u32 {
5166    60
5167}
5168
5169fn default_real_estate_pct() -> f64 {
5170    0.40
5171}
5172
5173impl Default for LeaseAccountingConfig {
5174    fn default() -> Self {
5175        Self {
5176            enabled: false,
5177            lease_count: default_lease_count(),
5178            finance_lease_percent: default_finance_lease_pct(),
5179            avg_lease_term_months: default_avg_lease_term(),
5180            generate_amortization: true,
5181            real_estate_percent: default_real_estate_pct(),
5182        }
5183    }
5184}
5185
5186/// Fair value measurement configuration (ASC 820/IFRS 13).
5187#[derive(Debug, Clone, Serialize, Deserialize)]
5188pub struct FairValueConfig {
5189    /// Enable fair value measurement generation
5190    #[serde(default)]
5191    pub enabled: bool,
5192
5193    /// Number of fair value measurements to generate
5194    #[serde(default = "default_fv_count")]
5195    pub measurement_count: usize,
5196
5197    /// Level 1 (quoted prices) percentage
5198    #[serde(default = "default_level1_pct")]
5199    pub level1_percent: f64,
5200
5201    /// Level 2 (observable inputs) percentage
5202    #[serde(default = "default_level2_pct")]
5203    pub level2_percent: f64,
5204
5205    /// Level 3 (unobservable inputs) percentage
5206    #[serde(default = "default_level3_pct")]
5207    pub level3_percent: f64,
5208
5209    /// Include sensitivity analysis for Level 3
5210    #[serde(default)]
5211    pub include_sensitivity_analysis: bool,
5212}
5213
5214fn default_fv_count() -> usize {
5215    25
5216}
5217
5218fn default_level1_pct() -> f64 {
5219    0.40
5220}
5221
5222fn default_level2_pct() -> f64 {
5223    0.35
5224}
5225
5226fn default_level3_pct() -> f64 {
5227    0.25
5228}
5229
5230impl Default for FairValueConfig {
5231    fn default() -> Self {
5232        Self {
5233            enabled: false,
5234            measurement_count: default_fv_count(),
5235            level1_percent: default_level1_pct(),
5236            level2_percent: default_level2_pct(),
5237            level3_percent: default_level3_pct(),
5238            include_sensitivity_analysis: false,
5239        }
5240    }
5241}
5242
5243/// Impairment testing configuration (ASC 360/IAS 36).
5244#[derive(Debug, Clone, Serialize, Deserialize)]
5245pub struct ImpairmentConfig {
5246    /// Enable impairment testing generation
5247    #[serde(default)]
5248    pub enabled: bool,
5249
5250    /// Number of impairment tests to generate
5251    #[serde(default = "default_impairment_count")]
5252    pub test_count: usize,
5253
5254    /// Rate of tests resulting in impairment
5255    #[serde(default = "default_impairment_rate")]
5256    pub impairment_rate: f64,
5257
5258    /// Generate cash flow projections
5259    #[serde(default = "default_true")]
5260    pub generate_projections: bool,
5261
5262    /// Include goodwill impairment tests
5263    #[serde(default)]
5264    pub include_goodwill: bool,
5265}
5266
5267fn default_impairment_count() -> usize {
5268    15
5269}
5270
5271fn default_impairment_rate() -> f64 {
5272    0.10
5273}
5274
5275impl Default for ImpairmentConfig {
5276    fn default() -> Self {
5277        Self {
5278            enabled: false,
5279            test_count: default_impairment_count(),
5280            impairment_rate: default_impairment_rate(),
5281            generate_projections: true,
5282            include_goodwill: false,
5283        }
5284    }
5285}
5286
5287// =============================================================================
5288// Business Combinations Configuration (IFRS 3 / ASC 805)
5289// =============================================================================
5290
5291/// Configuration for generating business combination (acquisition) data.
5292#[derive(Debug, Clone, Serialize, Deserialize)]
5293pub struct BusinessCombinationsConfig {
5294    /// Enable business combination generation
5295    #[serde(default)]
5296    pub enabled: bool,
5297
5298    /// Number of acquisitions to generate per company (1-5)
5299    #[serde(default = "default_bc_acquisition_count")]
5300    pub acquisition_count: usize,
5301}
5302
5303fn default_bc_acquisition_count() -> usize {
5304    2
5305}
5306
5307impl Default for BusinessCombinationsConfig {
5308    fn default() -> Self {
5309        Self {
5310            enabled: false,
5311            acquisition_count: default_bc_acquisition_count(),
5312        }
5313    }
5314}
5315
5316// =============================================================================
5317// ECL Configuration (IFRS 9 / ASC 326)
5318// =============================================================================
5319
5320/// Configuration for Expected Credit Loss generation.
5321#[derive(Debug, Clone, Serialize, Deserialize)]
5322pub struct EclConfig {
5323    /// Enable ECL generation.
5324    #[serde(default)]
5325    pub enabled: bool,
5326
5327    /// Weight for base economic scenario (0–1).
5328    #[serde(default = "default_ecl_base_weight")]
5329    pub base_scenario_weight: f64,
5330
5331    /// Multiplier for base scenario (typically 1.0).
5332    #[serde(default = "default_ecl_base_multiplier")]
5333    pub base_scenario_multiplier: f64,
5334
5335    /// Weight for optimistic economic scenario (0–1).
5336    #[serde(default = "default_ecl_optimistic_weight")]
5337    pub optimistic_scenario_weight: f64,
5338
5339    /// Multiplier for optimistic scenario (< 1.0 means lower losses).
5340    #[serde(default = "default_ecl_optimistic_multiplier")]
5341    pub optimistic_scenario_multiplier: f64,
5342
5343    /// Weight for pessimistic economic scenario (0–1).
5344    #[serde(default = "default_ecl_pessimistic_weight")]
5345    pub pessimistic_scenario_weight: f64,
5346
5347    /// Multiplier for pessimistic scenario (> 1.0 means higher losses).
5348    #[serde(default = "default_ecl_pessimistic_multiplier")]
5349    pub pessimistic_scenario_multiplier: f64,
5350}
5351
5352fn default_ecl_base_weight() -> f64 {
5353    0.50
5354}
5355fn default_ecl_base_multiplier() -> f64 {
5356    1.0
5357}
5358fn default_ecl_optimistic_weight() -> f64 {
5359    0.30
5360}
5361fn default_ecl_optimistic_multiplier() -> f64 {
5362    0.8
5363}
5364fn default_ecl_pessimistic_weight() -> f64 {
5365    0.20
5366}
5367fn default_ecl_pessimistic_multiplier() -> f64 {
5368    1.4
5369}
5370
5371impl Default for EclConfig {
5372    fn default() -> Self {
5373        Self {
5374            enabled: false,
5375            base_scenario_weight: default_ecl_base_weight(),
5376            base_scenario_multiplier: default_ecl_base_multiplier(),
5377            optimistic_scenario_weight: default_ecl_optimistic_weight(),
5378            optimistic_scenario_multiplier: default_ecl_optimistic_multiplier(),
5379            pessimistic_scenario_weight: default_ecl_pessimistic_weight(),
5380            pessimistic_scenario_multiplier: default_ecl_pessimistic_multiplier(),
5381        }
5382    }
5383}
5384
5385// =============================================================================
5386// Audit Standards Configuration
5387// =============================================================================
5388
5389/// Audit standards framework configuration for generating standards-compliant audit data.
5390///
5391/// Supports ISA (International Standards on Auditing) and PCAOB standards:
5392/// - ISA 200-720: Complete coverage of audit standards
5393/// - ISA 520: Analytical Procedures
5394/// - ISA 505: External Confirmations
5395/// - ISA 700/705/706/701: Audit Reports
5396/// - PCAOB AS 2201: ICFR Auditing
5397#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5398pub struct AuditStandardsConfig {
5399    /// Enable audit standards generation
5400    #[serde(default)]
5401    pub enabled: bool,
5402
5403    /// ISA compliance configuration
5404    #[serde(default)]
5405    pub isa_compliance: IsaComplianceConfig,
5406
5407    /// Analytical procedures configuration (ISA 520)
5408    #[serde(default)]
5409    pub analytical_procedures: AnalyticalProceduresConfig,
5410
5411    /// External confirmations configuration (ISA 505)
5412    #[serde(default)]
5413    pub confirmations: ConfirmationsConfig,
5414
5415    /// Audit opinion configuration (ISA 700/705/706/701)
5416    #[serde(default)]
5417    pub opinion: AuditOpinionConfig,
5418
5419    /// Generate complete audit trail with traceability
5420    #[serde(default)]
5421    pub generate_audit_trail: bool,
5422
5423    /// SOX 302/404 compliance configuration
5424    #[serde(default)]
5425    pub sox: SoxComplianceConfig,
5426
5427    /// PCAOB-specific configuration
5428    #[serde(default)]
5429    pub pcaob: PcaobConfig,
5430}
5431
5432/// ISA compliance level configuration.
5433#[derive(Debug, Clone, Serialize, Deserialize)]
5434pub struct IsaComplianceConfig {
5435    /// Enable ISA compliance tracking
5436    #[serde(default)]
5437    pub enabled: bool,
5438
5439    /// Compliance level: "basic", "standard", "comprehensive"
5440    #[serde(default = "default_compliance_level")]
5441    pub compliance_level: String,
5442
5443    /// Generate ISA requirement mappings
5444    #[serde(default = "default_true")]
5445    pub generate_isa_mappings: bool,
5446
5447    /// Generate ISA coverage summary
5448    #[serde(default = "default_true")]
5449    pub generate_coverage_summary: bool,
5450
5451    /// Include PCAOB standard mappings (for dual framework)
5452    #[serde(default)]
5453    pub include_pcaob: bool,
5454
5455    /// Framework to use: "isa", "pcaob", "dual"
5456    #[serde(default = "default_audit_framework")]
5457    pub framework: String,
5458}
5459
5460fn default_compliance_level() -> String {
5461    "standard".to_string()
5462}
5463
5464fn default_audit_framework() -> String {
5465    "isa".to_string()
5466}
5467
5468impl Default for IsaComplianceConfig {
5469    fn default() -> Self {
5470        Self {
5471            enabled: false,
5472            compliance_level: default_compliance_level(),
5473            generate_isa_mappings: true,
5474            generate_coverage_summary: true,
5475            include_pcaob: false,
5476            framework: default_audit_framework(),
5477        }
5478    }
5479}
5480
5481/// Analytical procedures configuration (ISA 520).
5482#[derive(Debug, Clone, Serialize, Deserialize)]
5483pub struct AnalyticalProceduresConfig {
5484    /// Enable analytical procedures generation
5485    #[serde(default)]
5486    pub enabled: bool,
5487
5488    /// Number of procedures per account/area
5489    #[serde(default = "default_procedures_per_account")]
5490    pub procedures_per_account: usize,
5491
5492    /// Probability of variance exceeding threshold
5493    #[serde(default = "default_variance_probability")]
5494    pub variance_probability: f64,
5495
5496    /// Include variance investigations
5497    #[serde(default = "default_true")]
5498    pub generate_investigations: bool,
5499
5500    /// Include financial ratio analysis
5501    #[serde(default = "default_true")]
5502    pub include_ratio_analysis: bool,
5503}
5504
5505fn default_procedures_per_account() -> usize {
5506    3
5507}
5508
5509fn default_variance_probability() -> f64 {
5510    0.20
5511}
5512
5513impl Default for AnalyticalProceduresConfig {
5514    fn default() -> Self {
5515        Self {
5516            enabled: false,
5517            procedures_per_account: default_procedures_per_account(),
5518            variance_probability: default_variance_probability(),
5519            generate_investigations: true,
5520            include_ratio_analysis: true,
5521        }
5522    }
5523}
5524
5525/// External confirmations configuration (ISA 505).
5526#[derive(Debug, Clone, Serialize, Deserialize)]
5527pub struct ConfirmationsConfig {
5528    /// Enable confirmation generation
5529    #[serde(default)]
5530    pub enabled: bool,
5531
5532    /// Number of confirmations to generate
5533    #[serde(default = "default_confirmation_count")]
5534    pub confirmation_count: usize,
5535
5536    /// Positive response rate
5537    #[serde(default = "default_positive_response_rate")]
5538    pub positive_response_rate: f64,
5539
5540    /// Exception rate (responses with differences)
5541    #[serde(default = "default_exception_rate_confirm")]
5542    pub exception_rate: f64,
5543
5544    /// Non-response rate
5545    #[serde(default = "default_non_response_rate")]
5546    pub non_response_rate: f64,
5547
5548    /// Generate alternative procedures for non-responses
5549    #[serde(default = "default_true")]
5550    pub generate_alternative_procedures: bool,
5551}
5552
5553fn default_confirmation_count() -> usize {
5554    50
5555}
5556
5557fn default_positive_response_rate() -> f64 {
5558    0.85
5559}
5560
5561fn default_exception_rate_confirm() -> f64 {
5562    0.10
5563}
5564
5565fn default_non_response_rate() -> f64 {
5566    0.05
5567}
5568
5569impl Default for ConfirmationsConfig {
5570    fn default() -> Self {
5571        Self {
5572            enabled: false,
5573            confirmation_count: default_confirmation_count(),
5574            positive_response_rate: default_positive_response_rate(),
5575            exception_rate: default_exception_rate_confirm(),
5576            non_response_rate: default_non_response_rate(),
5577            generate_alternative_procedures: true,
5578        }
5579    }
5580}
5581
5582/// Audit opinion configuration (ISA 700/705/706/701).
5583#[derive(Debug, Clone, Serialize, Deserialize)]
5584pub struct AuditOpinionConfig {
5585    /// Enable audit opinion generation
5586    #[serde(default)]
5587    pub enabled: bool,
5588
5589    /// Generate Key Audit Matters (KAM) / Critical Audit Matters (CAM)
5590    #[serde(default = "default_true")]
5591    pub generate_kam: bool,
5592
5593    /// Average number of KAMs/CAMs per opinion
5594    #[serde(default = "default_kam_count")]
5595    pub average_kam_count: usize,
5596
5597    /// Rate of modified opinions
5598    #[serde(default = "default_modified_opinion_rate")]
5599    pub modified_opinion_rate: f64,
5600
5601    /// Include emphasis of matter paragraphs
5602    #[serde(default)]
5603    pub include_emphasis_of_matter: bool,
5604
5605    /// Include going concern conclusions
5606    #[serde(default = "default_true")]
5607    pub include_going_concern: bool,
5608}
5609
5610fn default_kam_count() -> usize {
5611    3
5612}
5613
5614fn default_modified_opinion_rate() -> f64 {
5615    0.05
5616}
5617
5618impl Default for AuditOpinionConfig {
5619    fn default() -> Self {
5620        Self {
5621            enabled: false,
5622            generate_kam: true,
5623            average_kam_count: default_kam_count(),
5624            modified_opinion_rate: default_modified_opinion_rate(),
5625            include_emphasis_of_matter: false,
5626            include_going_concern: true,
5627        }
5628    }
5629}
5630
5631/// SOX compliance configuration (Sections 302/404).
5632#[derive(Debug, Clone, Serialize, Deserialize)]
5633pub struct SoxComplianceConfig {
5634    /// Enable SOX compliance generation
5635    #[serde(default)]
5636    pub enabled: bool,
5637
5638    /// Generate Section 302 CEO/CFO certifications
5639    #[serde(default = "default_true")]
5640    pub generate_302_certifications: bool,
5641
5642    /// Generate Section 404 ICFR assessments
5643    #[serde(default = "default_true")]
5644    pub generate_404_assessments: bool,
5645
5646    /// Materiality threshold for SOX testing
5647    #[serde(default = "default_sox_materiality_threshold")]
5648    pub materiality_threshold: f64,
5649
5650    /// Rate of material weaknesses
5651    #[serde(default = "default_material_weakness_rate")]
5652    pub material_weakness_rate: f64,
5653
5654    /// Rate of significant deficiencies
5655    #[serde(default = "default_significant_deficiency_rate")]
5656    pub significant_deficiency_rate: f64,
5657}
5658
5659fn default_material_weakness_rate() -> f64 {
5660    0.02
5661}
5662
5663fn default_significant_deficiency_rate() -> f64 {
5664    0.08
5665}
5666
5667impl Default for SoxComplianceConfig {
5668    fn default() -> Self {
5669        Self {
5670            enabled: false,
5671            generate_302_certifications: true,
5672            generate_404_assessments: true,
5673            materiality_threshold: default_sox_materiality_threshold(),
5674            material_weakness_rate: default_material_weakness_rate(),
5675            significant_deficiency_rate: default_significant_deficiency_rate(),
5676        }
5677    }
5678}
5679
5680/// PCAOB-specific configuration.
5681#[derive(Debug, Clone, Serialize, Deserialize)]
5682pub struct PcaobConfig {
5683    /// Enable PCAOB-specific elements
5684    #[serde(default)]
5685    pub enabled: bool,
5686
5687    /// Treat as PCAOB audit (vs ISA-only)
5688    #[serde(default)]
5689    pub is_pcaob_audit: bool,
5690
5691    /// Generate Critical Audit Matters (CAM)
5692    #[serde(default = "default_true")]
5693    pub generate_cam: bool,
5694
5695    /// Include ICFR opinion (for integrated audits)
5696    #[serde(default)]
5697    pub include_icfr_opinion: bool,
5698
5699    /// Generate PCAOB-ISA standard mappings
5700    #[serde(default)]
5701    pub generate_standard_mappings: bool,
5702}
5703
5704impl Default for PcaobConfig {
5705    fn default() -> Self {
5706        Self {
5707            enabled: false,
5708            is_pcaob_audit: false,
5709            generate_cam: true,
5710            include_icfr_opinion: false,
5711            generate_standard_mappings: false,
5712        }
5713    }
5714}
5715
5716// =============================================================================
5717// Advanced Distribution Configuration
5718// =============================================================================
5719
5720/// Advanced distribution configuration for realistic data generation.
5721///
5722/// This section enables sophisticated distribution models including:
5723/// - Mixture models (multi-modal distributions)
5724/// - Cross-field correlations
5725/// - Conditional distributions
5726/// - Regime changes and economic cycles
5727/// - Statistical validation
5728#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5729pub struct AdvancedDistributionConfig {
5730    /// Enable advanced distribution features.
5731    #[serde(default)]
5732    pub enabled: bool,
5733
5734    /// Mixture model configuration for amounts.
5735    #[serde(default)]
5736    pub amounts: MixtureDistributionSchemaConfig,
5737
5738    /// Cross-field correlation configuration.
5739    #[serde(default)]
5740    pub correlations: CorrelationSchemaConfig,
5741
5742    /// Conditional distribution configurations.
5743    #[serde(default)]
5744    pub conditional: Vec<ConditionalDistributionSchemaConfig>,
5745
5746    /// Regime change configuration.
5747    #[serde(default)]
5748    pub regime_changes: RegimeChangeSchemaConfig,
5749
5750    /// Industry-specific distribution profile.
5751    #[serde(default)]
5752    pub industry_profile: Option<IndustryProfileType>,
5753
5754    /// Statistical validation configuration.
5755    #[serde(default)]
5756    pub validation: StatisticalValidationSchemaConfig,
5757}
5758
5759/// Industry profile types for pre-configured distribution settings.
5760#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5761#[serde(rename_all = "snake_case")]
5762pub enum IndustryProfileType {
5763    /// Retail industry profile (POS sales, inventory, seasonal)
5764    Retail,
5765    /// Manufacturing industry profile (raw materials, maintenance, capital)
5766    Manufacturing,
5767    /// Financial services profile (wire transfers, ACH, fee income)
5768    FinancialServices,
5769    /// Healthcare profile (claims, procedures, supplies)
5770    Healthcare,
5771    /// Technology profile (subscriptions, services, R&D)
5772    Technology,
5773}
5774
5775/// Mixture model distribution configuration.
5776#[derive(Debug, Clone, Serialize, Deserialize)]
5777pub struct MixtureDistributionSchemaConfig {
5778    /// Enable mixture model for amount generation.
5779    #[serde(default)]
5780    pub enabled: bool,
5781
5782    /// Distribution type: "gaussian" or "lognormal".
5783    #[serde(default = "default_mixture_type")]
5784    pub distribution_type: MixtureDistributionType,
5785
5786    /// Mixture components with weights.
5787    #[serde(default)]
5788    pub components: Vec<MixtureComponentConfig>,
5789
5790    /// Minimum value constraint.
5791    #[serde(default = "default_min_amount")]
5792    pub min_value: f64,
5793
5794    /// Maximum value constraint (optional).
5795    #[serde(default)]
5796    pub max_value: Option<f64>,
5797
5798    /// Decimal places for rounding.
5799    #[serde(default = "default_decimal_places")]
5800    pub decimal_places: u8,
5801}
5802
5803fn default_mixture_type() -> MixtureDistributionType {
5804    MixtureDistributionType::LogNormal
5805}
5806
5807fn default_min_amount() -> f64 {
5808    0.01
5809}
5810
5811fn default_decimal_places() -> u8 {
5812    2
5813}
5814
5815impl Default for MixtureDistributionSchemaConfig {
5816    fn default() -> Self {
5817        Self {
5818            enabled: false,
5819            distribution_type: MixtureDistributionType::LogNormal,
5820            components: Vec::new(),
5821            min_value: 0.01,
5822            max_value: None,
5823            decimal_places: 2,
5824        }
5825    }
5826}
5827
5828/// Mixture distribution type.
5829#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5830#[serde(rename_all = "snake_case")]
5831pub enum MixtureDistributionType {
5832    /// Gaussian (normal) mixture
5833    Gaussian,
5834    /// Log-normal mixture (for positive amounts)
5835    #[default]
5836    LogNormal,
5837}
5838
5839/// Configuration for a single mixture component.
5840#[derive(Debug, Clone, Serialize, Deserialize)]
5841pub struct MixtureComponentConfig {
5842    /// Weight of this component (must sum to 1.0 across all components).
5843    pub weight: f64,
5844
5845    /// Location parameter (mean for Gaussian, mu for log-normal).
5846    pub mu: f64,
5847
5848    /// Scale parameter (std dev for Gaussian, sigma for log-normal).
5849    pub sigma: f64,
5850
5851    /// Optional label for this component (e.g., "routine", "significant", "major").
5852    #[serde(default)]
5853    pub label: Option<String>,
5854}
5855
5856/// Cross-field correlation configuration.
5857#[derive(Debug, Clone, Serialize, Deserialize)]
5858pub struct CorrelationSchemaConfig {
5859    /// Enable correlation modeling.
5860    #[serde(default)]
5861    pub enabled: bool,
5862
5863    /// Copula type for dependency modeling.
5864    #[serde(default)]
5865    pub copula_type: CopulaSchemaType,
5866
5867    /// Field definitions for correlation.
5868    #[serde(default)]
5869    pub fields: Vec<CorrelatedFieldConfig>,
5870
5871    /// Correlation matrix (upper triangular, row-major).
5872    /// For n fields, this should have n*(n-1)/2 values.
5873    #[serde(default)]
5874    pub matrix: Vec<f64>,
5875
5876    /// Expected correlations for validation.
5877    #[serde(default)]
5878    pub expected_correlations: Vec<ExpectedCorrelationConfig>,
5879}
5880
5881impl Default for CorrelationSchemaConfig {
5882    fn default() -> Self {
5883        Self {
5884            enabled: false,
5885            copula_type: CopulaSchemaType::Gaussian,
5886            fields: Vec::new(),
5887            matrix: Vec::new(),
5888            expected_correlations: Vec::new(),
5889        }
5890    }
5891}
5892
5893/// Copula type for dependency modeling.
5894#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5895#[serde(rename_all = "snake_case")]
5896pub enum CopulaSchemaType {
5897    /// Gaussian copula (symmetric, no tail dependence)
5898    #[default]
5899    Gaussian,
5900    /// Clayton copula (lower tail dependence)
5901    Clayton,
5902    /// Gumbel copula (upper tail dependence)
5903    Gumbel,
5904    /// Frank copula (symmetric, no tail dependence)
5905    Frank,
5906    /// Student-t copula (both tail dependencies)
5907    StudentT,
5908}
5909
5910/// Configuration for a correlated field.
5911#[derive(Debug, Clone, Serialize, Deserialize)]
5912pub struct CorrelatedFieldConfig {
5913    /// Field name.
5914    pub name: String,
5915
5916    /// Marginal distribution type.
5917    #[serde(default)]
5918    pub distribution: MarginalDistributionConfig,
5919}
5920
5921/// Marginal distribution configuration.
5922#[derive(Debug, Clone, Serialize, Deserialize)]
5923#[serde(tag = "type", rename_all = "snake_case")]
5924pub enum MarginalDistributionConfig {
5925    /// Normal distribution.
5926    Normal {
5927        /// Mean
5928        mu: f64,
5929        /// Standard deviation
5930        sigma: f64,
5931    },
5932    /// Log-normal distribution.
5933    LogNormal {
5934        /// Location parameter
5935        mu: f64,
5936        /// Scale parameter
5937        sigma: f64,
5938    },
5939    /// Uniform distribution.
5940    Uniform {
5941        /// Minimum value
5942        min: f64,
5943        /// Maximum value
5944        max: f64,
5945    },
5946    /// Discrete uniform distribution.
5947    DiscreteUniform {
5948        /// Minimum integer value
5949        min: i32,
5950        /// Maximum integer value
5951        max: i32,
5952    },
5953}
5954
5955impl Default for MarginalDistributionConfig {
5956    fn default() -> Self {
5957        Self::Normal {
5958            mu: 0.0,
5959            sigma: 1.0,
5960        }
5961    }
5962}
5963
5964/// Expected correlation for validation.
5965#[derive(Debug, Clone, Serialize, Deserialize)]
5966pub struct ExpectedCorrelationConfig {
5967    /// First field name.
5968    pub field1: String,
5969    /// Second field name.
5970    pub field2: String,
5971    /// Expected correlation coefficient.
5972    pub expected_r: f64,
5973    /// Acceptable tolerance.
5974    #[serde(default = "default_correlation_tolerance")]
5975    pub tolerance: f64,
5976}
5977
5978fn default_correlation_tolerance() -> f64 {
5979    0.10
5980}
5981
5982/// Conditional distribution configuration.
5983#[derive(Debug, Clone, Serialize, Deserialize)]
5984pub struct ConditionalDistributionSchemaConfig {
5985    /// Output field name to generate.
5986    pub output_field: String,
5987
5988    /// Input field name that conditions the distribution.
5989    pub input_field: String,
5990
5991    /// Breakpoints defining distribution changes.
5992    #[serde(default)]
5993    pub breakpoints: Vec<ConditionalBreakpointConfig>,
5994
5995    /// Default distribution when below all breakpoints.
5996    #[serde(default)]
5997    pub default_distribution: ConditionalDistributionParamsConfig,
5998
5999    /// Minimum output value constraint.
6000    #[serde(default)]
6001    pub min_value: Option<f64>,
6002
6003    /// Maximum output value constraint.
6004    #[serde(default)]
6005    pub max_value: Option<f64>,
6006
6007    /// Decimal places for output rounding.
6008    #[serde(default = "default_decimal_places")]
6009    pub decimal_places: u8,
6010}
6011
6012/// Breakpoint for conditional distribution.
6013#[derive(Debug, Clone, Serialize, Deserialize)]
6014pub struct ConditionalBreakpointConfig {
6015    /// Input value threshold.
6016    pub threshold: f64,
6017
6018    /// Distribution to use when input >= threshold.
6019    pub distribution: ConditionalDistributionParamsConfig,
6020}
6021
6022/// Distribution parameters for conditional distributions.
6023#[derive(Debug, Clone, Serialize, Deserialize)]
6024#[serde(tag = "type", rename_all = "snake_case")]
6025pub enum ConditionalDistributionParamsConfig {
6026    /// Fixed value.
6027    Fixed {
6028        /// The fixed value
6029        value: f64,
6030    },
6031    /// Normal distribution.
6032    Normal {
6033        /// Mean
6034        mu: f64,
6035        /// Standard deviation
6036        sigma: f64,
6037    },
6038    /// Log-normal distribution.
6039    LogNormal {
6040        /// Location parameter
6041        mu: f64,
6042        /// Scale parameter
6043        sigma: f64,
6044    },
6045    /// Uniform distribution.
6046    Uniform {
6047        /// Minimum
6048        min: f64,
6049        /// Maximum
6050        max: f64,
6051    },
6052    /// Beta distribution (scaled).
6053    Beta {
6054        /// Alpha parameter
6055        alpha: f64,
6056        /// Beta parameter
6057        beta: f64,
6058        /// Minimum output value
6059        min: f64,
6060        /// Maximum output value
6061        max: f64,
6062    },
6063    /// Discrete values with weights.
6064    Discrete {
6065        /// Possible values
6066        values: Vec<f64>,
6067        /// Weights (should sum to 1.0)
6068        weights: Vec<f64>,
6069    },
6070}
6071
6072impl Default for ConditionalDistributionParamsConfig {
6073    fn default() -> Self {
6074        Self::Normal {
6075            mu: 0.0,
6076            sigma: 1.0,
6077        }
6078    }
6079}
6080
6081/// Regime change configuration.
6082#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6083pub struct RegimeChangeSchemaConfig {
6084    /// Enable regime change modeling.
6085    #[serde(default)]
6086    pub enabled: bool,
6087
6088    /// List of regime changes.
6089    #[serde(default)]
6090    pub changes: Vec<RegimeChangeEventConfig>,
6091
6092    /// Economic cycle configuration.
6093    #[serde(default)]
6094    pub economic_cycle: Option<EconomicCycleSchemaConfig>,
6095
6096    /// Parameter drift configurations.
6097    #[serde(default)]
6098    pub parameter_drifts: Vec<ParameterDriftSchemaConfig>,
6099}
6100
6101/// A single regime change event.
6102#[derive(Debug, Clone, Serialize, Deserialize)]
6103pub struct RegimeChangeEventConfig {
6104    /// Date when the change occurs (ISO 8601 format).
6105    pub date: String,
6106
6107    /// Type of regime change.
6108    pub change_type: RegimeChangeTypeConfig,
6109
6110    /// Description of the change.
6111    #[serde(default)]
6112    pub description: Option<String>,
6113
6114    /// Effects of this regime change.
6115    #[serde(default)]
6116    pub effects: Vec<RegimeEffectConfig>,
6117}
6118
6119/// Type of regime change.
6120#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6121#[serde(rename_all = "snake_case")]
6122pub enum RegimeChangeTypeConfig {
6123    /// Acquisition - sudden volume and amount increase
6124    Acquisition,
6125    /// Divestiture - sudden volume and amount decrease
6126    Divestiture,
6127    /// Price increase - amounts increase
6128    PriceIncrease,
6129    /// Price decrease - amounts decrease
6130    PriceDecrease,
6131    /// New product launch - volume ramp-up
6132    ProductLaunch,
6133    /// Product discontinuation - volume ramp-down
6134    ProductDiscontinuation,
6135    /// Policy change - affects patterns
6136    PolicyChange,
6137    /// Competitor entry - market disruption
6138    CompetitorEntry,
6139    /// Custom effect
6140    Custom,
6141}
6142
6143/// Effect of a regime change on a specific field.
6144#[derive(Debug, Clone, Serialize, Deserialize)]
6145pub struct RegimeEffectConfig {
6146    /// Field being affected.
6147    pub field: String,
6148
6149    /// Multiplier to apply (1.0 = no change, 1.5 = 50% increase).
6150    pub multiplier: f64,
6151}
6152
6153/// Economic cycle configuration.
6154#[derive(Debug, Clone, Serialize, Deserialize)]
6155pub struct EconomicCycleSchemaConfig {
6156    /// Enable economic cycle modeling.
6157    #[serde(default)]
6158    pub enabled: bool,
6159
6160    /// Cycle period in months (e.g., 48 for 4-year business cycle).
6161    #[serde(default = "default_cycle_period")]
6162    pub period_months: u32,
6163
6164    /// Amplitude of cycle effect (0.0-1.0).
6165    #[serde(default = "default_cycle_amplitude")]
6166    pub amplitude: f64,
6167
6168    /// Phase offset in months.
6169    #[serde(default)]
6170    pub phase_offset: u32,
6171
6172    /// Recession periods (start_month, duration_months).
6173    #[serde(default)]
6174    pub recessions: Vec<RecessionPeriodConfig>,
6175}
6176
6177fn default_cycle_period() -> u32 {
6178    48
6179}
6180
6181fn default_cycle_amplitude() -> f64 {
6182    0.15
6183}
6184
6185impl Default for EconomicCycleSchemaConfig {
6186    fn default() -> Self {
6187        Self {
6188            enabled: false,
6189            period_months: 48,
6190            amplitude: 0.15,
6191            phase_offset: 0,
6192            recessions: Vec::new(),
6193        }
6194    }
6195}
6196
6197/// Recession period configuration.
6198#[derive(Debug, Clone, Serialize, Deserialize)]
6199pub struct RecessionPeriodConfig {
6200    /// Start month (0-indexed from generation start).
6201    pub start_month: u32,
6202
6203    /// Duration in months.
6204    pub duration_months: u32,
6205
6206    /// Severity (0.0-1.0, affects volume reduction).
6207    #[serde(default = "default_recession_severity")]
6208    pub severity: f64,
6209}
6210
6211fn default_recession_severity() -> f64 {
6212    0.20
6213}
6214
6215/// Parameter drift configuration.
6216#[derive(Debug, Clone, Serialize, Deserialize)]
6217pub struct ParameterDriftSchemaConfig {
6218    /// Parameter being drifted.
6219    pub parameter: String,
6220
6221    /// Drift type.
6222    pub drift_type: ParameterDriftTypeConfig,
6223
6224    /// Start value.
6225    pub start_value: f64,
6226
6227    /// End value.
6228    pub end_value: f64,
6229
6230    /// Start period (month, 0-indexed).
6231    #[serde(default)]
6232    pub start_period: u32,
6233
6234    /// End period (month, optional - defaults to end of generation).
6235    #[serde(default)]
6236    pub end_period: Option<u32>,
6237}
6238
6239/// Parameter drift type.
6240#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6241#[serde(rename_all = "snake_case")]
6242pub enum ParameterDriftTypeConfig {
6243    /// Linear interpolation
6244    #[default]
6245    Linear,
6246    /// Exponential growth/decay
6247    Exponential,
6248    /// S-curve (logistic)
6249    Logistic,
6250    /// Step function
6251    Step,
6252}
6253
6254/// Statistical validation configuration.
6255#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6256pub struct StatisticalValidationSchemaConfig {
6257    /// Enable statistical validation.
6258    #[serde(default)]
6259    pub enabled: bool,
6260
6261    /// Statistical tests to run.
6262    #[serde(default)]
6263    pub tests: Vec<StatisticalTestConfig>,
6264
6265    /// Validation reporting configuration.
6266    #[serde(default)]
6267    pub reporting: ValidationReportingConfig,
6268}
6269
6270/// Statistical test configuration.
6271#[derive(Debug, Clone, Serialize, Deserialize)]
6272#[serde(tag = "type", rename_all = "snake_case")]
6273pub enum StatisticalTestConfig {
6274    /// Benford's Law first digit test.
6275    BenfordFirstDigit {
6276        /// Threshold MAD for failure.
6277        #[serde(default = "default_benford_threshold")]
6278        threshold_mad: f64,
6279        /// Warning MAD threshold.
6280        #[serde(default = "default_benford_warning")]
6281        warning_mad: f64,
6282    },
6283    /// Distribution fit test.
6284    DistributionFit {
6285        /// Target distribution to test.
6286        target: TargetDistributionConfig,
6287        /// K-S test significance level.
6288        #[serde(default = "default_ks_significance")]
6289        ks_significance: f64,
6290        /// Test method (ks, anderson_darling, chi_squared).
6291        #[serde(default)]
6292        method: DistributionFitMethod,
6293    },
6294    /// Correlation check.
6295    CorrelationCheck {
6296        /// Expected correlations to validate.
6297        expected_correlations: Vec<ExpectedCorrelationConfig>,
6298    },
6299    /// Chi-squared test.
6300    ChiSquared {
6301        /// Number of bins.
6302        #[serde(default = "default_chi_squared_bins")]
6303        bins: usize,
6304        /// Significance level.
6305        #[serde(default = "default_chi_squared_significance")]
6306        significance: f64,
6307    },
6308    /// Anderson-Darling test.
6309    AndersonDarling {
6310        /// Target distribution.
6311        target: TargetDistributionConfig,
6312        /// Significance level.
6313        #[serde(default = "default_ad_significance")]
6314        significance: f64,
6315    },
6316}
6317
6318fn default_benford_threshold() -> f64 {
6319    0.015
6320}
6321
6322fn default_benford_warning() -> f64 {
6323    0.010
6324}
6325
6326fn default_ks_significance() -> f64 {
6327    0.05
6328}
6329
6330fn default_chi_squared_bins() -> usize {
6331    10
6332}
6333
6334fn default_chi_squared_significance() -> f64 {
6335    0.05
6336}
6337
6338fn default_ad_significance() -> f64 {
6339    0.05
6340}
6341
6342/// Target distribution for fit tests.
6343#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6344#[serde(rename_all = "snake_case")]
6345pub enum TargetDistributionConfig {
6346    /// Normal distribution
6347    Normal,
6348    /// Log-normal distribution
6349    #[default]
6350    LogNormal,
6351    /// Exponential distribution
6352    Exponential,
6353    /// Uniform distribution
6354    Uniform,
6355}
6356
6357/// Distribution fit test method.
6358#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6359#[serde(rename_all = "snake_case")]
6360pub enum DistributionFitMethod {
6361    /// Kolmogorov-Smirnov test
6362    #[default]
6363    KolmogorovSmirnov,
6364    /// Anderson-Darling test
6365    AndersonDarling,
6366    /// Chi-squared test
6367    ChiSquared,
6368}
6369
6370/// Validation reporting configuration.
6371#[derive(Debug, Clone, Serialize, Deserialize)]
6372pub struct ValidationReportingConfig {
6373    /// Output validation report to file.
6374    #[serde(default)]
6375    pub output_report: bool,
6376
6377    /// Report format.
6378    #[serde(default)]
6379    pub format: ValidationReportFormat,
6380
6381    /// Fail generation if validation fails.
6382    #[serde(default)]
6383    pub fail_on_error: bool,
6384
6385    /// Include detailed statistics in report.
6386    #[serde(default = "default_true")]
6387    pub include_details: bool,
6388}
6389
6390impl Default for ValidationReportingConfig {
6391    fn default() -> Self {
6392        Self {
6393            output_report: false,
6394            format: ValidationReportFormat::Json,
6395            fail_on_error: false,
6396            include_details: true,
6397        }
6398    }
6399}
6400
6401/// Validation report format.
6402#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6403#[serde(rename_all = "snake_case")]
6404pub enum ValidationReportFormat {
6405    /// JSON format
6406    #[default]
6407    Json,
6408    /// YAML format
6409    Yaml,
6410    /// HTML report
6411    Html,
6412}
6413
6414// =============================================================================
6415// Temporal Patterns Configuration
6416// =============================================================================
6417
6418/// Temporal patterns configuration for business days, period-end dynamics, and processing lags.
6419///
6420/// This section enables sophisticated temporal modeling including:
6421/// - Business day calculations and settlement dates
6422/// - Regional holiday calendars
6423/// - Period-end decay curves (non-flat volume spikes)
6424/// - Processing lag modeling (event-to-posting delays)
6425#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6426pub struct TemporalPatternsConfig {
6427    /// Enable temporal patterns features.
6428    #[serde(default)]
6429    pub enabled: bool,
6430
6431    /// Business day calculation configuration.
6432    #[serde(default)]
6433    pub business_days: BusinessDaySchemaConfig,
6434
6435    /// Regional calendar configuration.
6436    #[serde(default)]
6437    pub calendars: CalendarSchemaConfig,
6438
6439    /// Period-end dynamics configuration.
6440    #[serde(default)]
6441    pub period_end: PeriodEndSchemaConfig,
6442
6443    /// Processing lag configuration.
6444    #[serde(default)]
6445    pub processing_lags: ProcessingLagSchemaConfig,
6446
6447    /// Fiscal calendar configuration (custom year start, 4-4-5, 13-period).
6448    #[serde(default)]
6449    pub fiscal_calendar: FiscalCalendarSchemaConfig,
6450
6451    /// Intra-day patterns configuration (morning spike, lunch dip, EOD rush).
6452    #[serde(default)]
6453    pub intraday: IntraDaySchemaConfig,
6454
6455    /// Timezone handling configuration.
6456    #[serde(default)]
6457    pub timezones: TimezoneSchemaConfig,
6458}
6459
6460/// Business day calculation configuration.
6461#[derive(Debug, Clone, Serialize, Deserialize)]
6462pub struct BusinessDaySchemaConfig {
6463    /// Enable business day calculations.
6464    #[serde(default = "default_true")]
6465    pub enabled: bool,
6466
6467    /// Half-day policy: "full_day", "half_day", "non_business_day".
6468    #[serde(default = "default_half_day_policy")]
6469    pub half_day_policy: String,
6470
6471    /// Settlement rules configuration.
6472    #[serde(default)]
6473    pub settlement_rules: SettlementRulesSchemaConfig,
6474
6475    /// Month-end convention: "modified_following", "preceding", "following", "end_of_month".
6476    #[serde(default = "default_month_end_convention")]
6477    pub month_end_convention: String,
6478
6479    /// Weekend days (e.g., ["saturday", "sunday"] or ["friday", "saturday"] for Middle East).
6480    #[serde(default)]
6481    pub weekend_days: Option<Vec<String>>,
6482}
6483
6484fn default_half_day_policy() -> String {
6485    "half_day".to_string()
6486}
6487
6488fn default_month_end_convention() -> String {
6489    "modified_following".to_string()
6490}
6491
6492impl Default for BusinessDaySchemaConfig {
6493    fn default() -> Self {
6494        Self {
6495            enabled: true,
6496            half_day_policy: "half_day".to_string(),
6497            settlement_rules: SettlementRulesSchemaConfig::default(),
6498            month_end_convention: "modified_following".to_string(),
6499            weekend_days: None,
6500        }
6501    }
6502}
6503
6504/// Settlement rules configuration.
6505#[derive(Debug, Clone, Serialize, Deserialize)]
6506pub struct SettlementRulesSchemaConfig {
6507    /// Equity settlement days (T+N).
6508    #[serde(default = "default_settlement_2")]
6509    pub equity_days: i32,
6510
6511    /// Government bonds settlement days.
6512    #[serde(default = "default_settlement_1")]
6513    pub government_bonds_days: i32,
6514
6515    /// FX spot settlement days.
6516    #[serde(default = "default_settlement_2")]
6517    pub fx_spot_days: i32,
6518
6519    /// Corporate bonds settlement days.
6520    #[serde(default = "default_settlement_2")]
6521    pub corporate_bonds_days: i32,
6522
6523    /// Wire transfer cutoff time (HH:MM format).
6524    #[serde(default = "default_wire_cutoff")]
6525    pub wire_cutoff_time: String,
6526
6527    /// International wire settlement days.
6528    #[serde(default = "default_settlement_1")]
6529    pub wire_international_days: i32,
6530
6531    /// ACH settlement days.
6532    #[serde(default = "default_settlement_1")]
6533    pub ach_days: i32,
6534}
6535
6536fn default_settlement_1() -> i32 {
6537    1
6538}
6539
6540fn default_settlement_2() -> i32 {
6541    2
6542}
6543
6544fn default_wire_cutoff() -> String {
6545    "14:00".to_string()
6546}
6547
6548impl Default for SettlementRulesSchemaConfig {
6549    fn default() -> Self {
6550        Self {
6551            equity_days: 2,
6552            government_bonds_days: 1,
6553            fx_spot_days: 2,
6554            corporate_bonds_days: 2,
6555            wire_cutoff_time: "14:00".to_string(),
6556            wire_international_days: 1,
6557            ach_days: 1,
6558        }
6559    }
6560}
6561
6562/// Regional calendar configuration.
6563#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6564pub struct CalendarSchemaConfig {
6565    /// List of regions to include (e.g., ["US", "DE", "BR", "SG", "KR"]).
6566    #[serde(default)]
6567    pub regions: Vec<String>,
6568
6569    /// Custom holidays (in addition to regional calendars).
6570    #[serde(default)]
6571    pub custom_holidays: Vec<CustomHolidaySchemaConfig>,
6572}
6573
6574/// Custom holiday configuration.
6575#[derive(Debug, Clone, Serialize, Deserialize)]
6576pub struct CustomHolidaySchemaConfig {
6577    /// Holiday name.
6578    pub name: String,
6579    /// Month (1-12).
6580    pub month: u8,
6581    /// Day of month.
6582    pub day: u8,
6583    /// Activity multiplier (0.0-1.0, default 0.05).
6584    #[serde(default = "default_holiday_multiplier")]
6585    pub activity_multiplier: f64,
6586}
6587
6588fn default_holiday_multiplier() -> f64 {
6589    0.05
6590}
6591
6592/// Period-end dynamics configuration.
6593#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6594pub struct PeriodEndSchemaConfig {
6595    /// Model type: "flat", "exponential", "extended_crunch", "daily_profile".
6596    #[serde(default)]
6597    pub model: Option<String>,
6598
6599    /// Month-end configuration.
6600    #[serde(default)]
6601    pub month_end: Option<PeriodEndModelSchemaConfig>,
6602
6603    /// Quarter-end configuration.
6604    #[serde(default)]
6605    pub quarter_end: Option<PeriodEndModelSchemaConfig>,
6606
6607    /// Year-end configuration.
6608    #[serde(default)]
6609    pub year_end: Option<PeriodEndModelSchemaConfig>,
6610}
6611
6612/// Period-end model configuration.
6613#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6614pub struct PeriodEndModelSchemaConfig {
6615    /// Inherit configuration from another period (e.g., "month_end").
6616    #[serde(default)]
6617    pub inherit_from: Option<String>,
6618
6619    /// Additional multiplier on top of inherited/base model.
6620    #[serde(default)]
6621    pub additional_multiplier: Option<f64>,
6622
6623    /// Days before period end to start acceleration (negative, e.g., -10).
6624    #[serde(default)]
6625    pub start_day: Option<i32>,
6626
6627    /// Base multiplier at start of acceleration.
6628    #[serde(default)]
6629    pub base_multiplier: Option<f64>,
6630
6631    /// Peak multiplier on last day.
6632    #[serde(default)]
6633    pub peak_multiplier: Option<f64>,
6634
6635    /// Decay rate for exponential model (0.1-0.5 typical).
6636    #[serde(default)]
6637    pub decay_rate: Option<f64>,
6638
6639    /// Sustained high days for crunch model.
6640    #[serde(default)]
6641    pub sustained_high_days: Option<i32>,
6642}
6643
6644/// Processing lag configuration.
6645#[derive(Debug, Clone, Serialize, Deserialize)]
6646pub struct ProcessingLagSchemaConfig {
6647    /// Enable processing lag calculations.
6648    #[serde(default = "default_true")]
6649    pub enabled: bool,
6650
6651    /// Sales order lag configuration (log-normal mu, sigma).
6652    #[serde(default)]
6653    pub sales_order_lag: Option<LagDistributionSchemaConfig>,
6654
6655    /// Purchase order lag configuration.
6656    #[serde(default)]
6657    pub purchase_order_lag: Option<LagDistributionSchemaConfig>,
6658
6659    /// Goods receipt lag configuration.
6660    #[serde(default)]
6661    pub goods_receipt_lag: Option<LagDistributionSchemaConfig>,
6662
6663    /// Invoice receipt lag configuration.
6664    #[serde(default)]
6665    pub invoice_receipt_lag: Option<LagDistributionSchemaConfig>,
6666
6667    /// Invoice issue lag configuration.
6668    #[serde(default)]
6669    pub invoice_issue_lag: Option<LagDistributionSchemaConfig>,
6670
6671    /// Payment lag configuration.
6672    #[serde(default)]
6673    pub payment_lag: Option<LagDistributionSchemaConfig>,
6674
6675    /// Journal entry lag configuration.
6676    #[serde(default)]
6677    pub journal_entry_lag: Option<LagDistributionSchemaConfig>,
6678
6679    /// Cross-day posting configuration.
6680    #[serde(default)]
6681    pub cross_day_posting: Option<CrossDayPostingSchemaConfig>,
6682}
6683
6684impl Default for ProcessingLagSchemaConfig {
6685    fn default() -> Self {
6686        Self {
6687            enabled: true,
6688            sales_order_lag: None,
6689            purchase_order_lag: None,
6690            goods_receipt_lag: None,
6691            invoice_receipt_lag: None,
6692            invoice_issue_lag: None,
6693            payment_lag: None,
6694            journal_entry_lag: None,
6695            cross_day_posting: None,
6696        }
6697    }
6698}
6699
6700/// Lag distribution configuration (log-normal parameters).
6701#[derive(Debug, Clone, Serialize, Deserialize)]
6702pub struct LagDistributionSchemaConfig {
6703    /// Log-scale mean (mu for log-normal).
6704    pub mu: f64,
6705    /// Log-scale standard deviation (sigma for log-normal).
6706    pub sigma: f64,
6707    /// Minimum lag in hours.
6708    #[serde(default)]
6709    pub min_hours: Option<f64>,
6710    /// Maximum lag in hours.
6711    #[serde(default)]
6712    pub max_hours: Option<f64>,
6713}
6714
6715/// Cross-day posting configuration.
6716#[derive(Debug, Clone, Serialize, Deserialize)]
6717pub struct CrossDayPostingSchemaConfig {
6718    /// Enable cross-day posting logic.
6719    #[serde(default = "default_true")]
6720    pub enabled: bool,
6721
6722    /// Probability of next-day posting by hour (map of hour -> probability).
6723    /// E.g., { 17: 0.7, 19: 0.9, 21: 0.99 }
6724    #[serde(default)]
6725    pub probability_by_hour: std::collections::HashMap<u8, f64>,
6726}
6727
6728impl Default for CrossDayPostingSchemaConfig {
6729    fn default() -> Self {
6730        let mut probability_by_hour = std::collections::HashMap::new();
6731        probability_by_hour.insert(17, 0.3);
6732        probability_by_hour.insert(18, 0.6);
6733        probability_by_hour.insert(19, 0.8);
6734        probability_by_hour.insert(20, 0.9);
6735        probability_by_hour.insert(21, 0.95);
6736        probability_by_hour.insert(22, 0.99);
6737
6738        Self {
6739            enabled: true,
6740            probability_by_hour,
6741        }
6742    }
6743}
6744
6745// =============================================================================
6746// Fiscal Calendar Configuration (P2)
6747// =============================================================================
6748
6749/// Fiscal calendar configuration.
6750///
6751/// Supports calendar year, custom year start, 4-4-5 retail calendar,
6752/// and 13-period calendars.
6753#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6754pub struct FiscalCalendarSchemaConfig {
6755    /// Enable non-standard fiscal calendar.
6756    #[serde(default)]
6757    pub enabled: bool,
6758
6759    /// Fiscal calendar type: "calendar_year", "custom", "four_four_five", "thirteen_period".
6760    #[serde(default = "default_fiscal_calendar_type")]
6761    pub calendar_type: String,
6762
6763    /// Month the fiscal year starts (1-12). Used for custom year start.
6764    #[serde(default)]
6765    pub year_start_month: Option<u8>,
6766
6767    /// Day the fiscal year starts (1-31). Used for custom year start.
6768    #[serde(default)]
6769    pub year_start_day: Option<u8>,
6770
6771    /// 4-4-5 calendar configuration (if calendar_type is "four_four_five").
6772    #[serde(default)]
6773    pub four_four_five: Option<FourFourFiveSchemaConfig>,
6774}
6775
6776fn default_fiscal_calendar_type() -> String {
6777    "calendar_year".to_string()
6778}
6779
6780/// 4-4-5 retail calendar configuration.
6781#[derive(Debug, Clone, Serialize, Deserialize)]
6782pub struct FourFourFiveSchemaConfig {
6783    /// Week pattern: "four_four_five", "four_five_four", "five_four_four".
6784    #[serde(default = "default_week_pattern")]
6785    pub pattern: String,
6786
6787    /// Anchor type: "first_sunday", "last_saturday", "nearest_saturday".
6788    #[serde(default = "default_anchor_type")]
6789    pub anchor_type: String,
6790
6791    /// Anchor month (1-12).
6792    #[serde(default = "default_anchor_month")]
6793    pub anchor_month: u8,
6794
6795    /// Where to place leap week: "q4_period3" or "q1_period1".
6796    #[serde(default = "default_leap_week_placement")]
6797    pub leap_week_placement: String,
6798}
6799
6800fn default_week_pattern() -> String {
6801    "four_four_five".to_string()
6802}
6803
6804fn default_anchor_type() -> String {
6805    "last_saturday".to_string()
6806}
6807
6808fn default_anchor_month() -> u8 {
6809    1 // January
6810}
6811
6812fn default_leap_week_placement() -> String {
6813    "q4_period3".to_string()
6814}
6815
6816impl Default for FourFourFiveSchemaConfig {
6817    fn default() -> Self {
6818        Self {
6819            pattern: "four_four_five".to_string(),
6820            anchor_type: "last_saturday".to_string(),
6821            anchor_month: 1,
6822            leap_week_placement: "q4_period3".to_string(),
6823        }
6824    }
6825}
6826
6827// =============================================================================
6828// Intra-Day Patterns Configuration (P2)
6829// =============================================================================
6830
6831/// Intra-day patterns configuration.
6832///
6833/// Defines time-of-day segments with different activity multipliers
6834/// for realistic modeling of morning spikes, lunch dips, and end-of-day rushes.
6835#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6836pub struct IntraDaySchemaConfig {
6837    /// Enable intra-day patterns.
6838    #[serde(default)]
6839    pub enabled: bool,
6840
6841    /// Custom intra-day segments.
6842    #[serde(default)]
6843    pub segments: Vec<IntraDaySegmentSchemaConfig>,
6844}
6845
6846/// Intra-day segment configuration.
6847#[derive(Debug, Clone, Serialize, Deserialize)]
6848pub struct IntraDaySegmentSchemaConfig {
6849    /// Name of the segment (e.g., "morning_spike", "lunch_dip").
6850    pub name: String,
6851
6852    /// Start time (HH:MM format).
6853    pub start: String,
6854
6855    /// End time (HH:MM format).
6856    pub end: String,
6857
6858    /// Activity multiplier (1.0 = normal).
6859    #[serde(default = "default_multiplier")]
6860    pub multiplier: f64,
6861
6862    /// Posting type: "human", "system", "both".
6863    #[serde(default = "default_posting_type")]
6864    pub posting_type: String,
6865}
6866
6867fn default_multiplier() -> f64 {
6868    1.0
6869}
6870
6871fn default_posting_type() -> String {
6872    "both".to_string()
6873}
6874
6875// =============================================================================
6876// Timezone Configuration
6877// =============================================================================
6878
6879/// Timezone handling configuration for multi-region entities.
6880#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6881pub struct TimezoneSchemaConfig {
6882    /// Enable timezone handling.
6883    #[serde(default)]
6884    pub enabled: bool,
6885
6886    /// Default timezone (IANA format, e.g., "America/New_York").
6887    #[serde(default = "default_timezone")]
6888    pub default_timezone: String,
6889
6890    /// Consolidation timezone for group reporting (IANA format).
6891    #[serde(default = "default_consolidation_timezone")]
6892    pub consolidation_timezone: String,
6893
6894    /// Entity-to-timezone mappings.
6895    /// Supports patterns like "EU_*" -> "Europe/London".
6896    #[serde(default)]
6897    pub entity_mappings: Vec<EntityTimezoneMapping>,
6898}
6899
6900fn default_timezone() -> String {
6901    "America/New_York".to_string()
6902}
6903
6904fn default_consolidation_timezone() -> String {
6905    "UTC".to_string()
6906}
6907
6908/// Mapping from entity pattern to timezone.
6909#[derive(Debug, Clone, Serialize, Deserialize)]
6910pub struct EntityTimezoneMapping {
6911    /// Entity code pattern (e.g., "EU_*", "*_APAC", "1000").
6912    pub pattern: String,
6913
6914    /// Timezone (IANA format, e.g., "Europe/London").
6915    pub timezone: String,
6916}
6917
6918// =============================================================================
6919// Vendor Network Configuration
6920// =============================================================================
6921
6922/// Configuration for multi-tier vendor network generation.
6923#[derive(Debug, Clone, Serialize, Deserialize)]
6924pub struct VendorNetworkSchemaConfig {
6925    /// Enable vendor network generation.
6926    #[serde(default)]
6927    pub enabled: bool,
6928
6929    /// Maximum depth of supply chain tiers (1-3).
6930    #[serde(default = "default_vendor_tier_depth")]
6931    pub depth: u8,
6932
6933    /// Tier 1 vendor count configuration.
6934    #[serde(default)]
6935    pub tier1: TierCountSchemaConfig,
6936
6937    /// Tier 2 vendors per Tier 1 parent.
6938    #[serde(default)]
6939    pub tier2_per_parent: TierCountSchemaConfig,
6940
6941    /// Tier 3 vendors per Tier 2 parent.
6942    #[serde(default)]
6943    pub tier3_per_parent: TierCountSchemaConfig,
6944
6945    /// Vendor cluster distribution.
6946    #[serde(default)]
6947    pub clusters: VendorClusterSchemaConfig,
6948
6949    /// Concentration limits.
6950    #[serde(default)]
6951    pub dependencies: DependencySchemaConfig,
6952}
6953
6954fn default_vendor_tier_depth() -> u8 {
6955    3
6956}
6957
6958impl Default for VendorNetworkSchemaConfig {
6959    fn default() -> Self {
6960        Self {
6961            enabled: false,
6962            depth: 3,
6963            tier1: TierCountSchemaConfig { min: 50, max: 100 },
6964            tier2_per_parent: TierCountSchemaConfig { min: 4, max: 10 },
6965            tier3_per_parent: TierCountSchemaConfig { min: 2, max: 5 },
6966            clusters: VendorClusterSchemaConfig::default(),
6967            dependencies: DependencySchemaConfig::default(),
6968        }
6969    }
6970}
6971
6972/// Tier count configuration.
6973#[derive(Debug, Clone, Serialize, Deserialize)]
6974pub struct TierCountSchemaConfig {
6975    /// Minimum count.
6976    #[serde(default = "default_tier_min")]
6977    pub min: usize,
6978
6979    /// Maximum count.
6980    #[serde(default = "default_tier_max")]
6981    pub max: usize,
6982}
6983
6984fn default_tier_min() -> usize {
6985    5
6986}
6987
6988fn default_tier_max() -> usize {
6989    20
6990}
6991
6992impl Default for TierCountSchemaConfig {
6993    fn default() -> Self {
6994        Self {
6995            min: default_tier_min(),
6996            max: default_tier_max(),
6997        }
6998    }
6999}
7000
7001/// Vendor cluster distribution configuration.
7002#[derive(Debug, Clone, Serialize, Deserialize)]
7003pub struct VendorClusterSchemaConfig {
7004    /// Reliable strategic vendors percentage (default: 0.20).
7005    #[serde(default = "default_reliable_strategic")]
7006    pub reliable_strategic: f64,
7007
7008    /// Standard operational vendors percentage (default: 0.50).
7009    #[serde(default = "default_standard_operational")]
7010    pub standard_operational: f64,
7011
7012    /// Transactional vendors percentage (default: 0.25).
7013    #[serde(default = "default_transactional")]
7014    pub transactional: f64,
7015
7016    /// Problematic vendors percentage (default: 0.05).
7017    #[serde(default = "default_problematic")]
7018    pub problematic: f64,
7019}
7020
7021fn default_reliable_strategic() -> f64 {
7022    0.20
7023}
7024
7025fn default_standard_operational() -> f64 {
7026    0.50
7027}
7028
7029fn default_transactional() -> f64 {
7030    0.25
7031}
7032
7033fn default_problematic() -> f64 {
7034    0.05
7035}
7036
7037impl Default for VendorClusterSchemaConfig {
7038    fn default() -> Self {
7039        Self {
7040            reliable_strategic: 0.20,
7041            standard_operational: 0.50,
7042            transactional: 0.25,
7043            problematic: 0.05,
7044        }
7045    }
7046}
7047
7048/// Dependency and concentration limits configuration.
7049#[derive(Debug, Clone, Serialize, Deserialize)]
7050pub struct DependencySchemaConfig {
7051    /// Maximum concentration for a single vendor (default: 0.15).
7052    #[serde(default = "default_max_single_vendor")]
7053    pub max_single_vendor_concentration: f64,
7054
7055    /// Maximum concentration for top 5 vendors (default: 0.45).
7056    #[serde(default = "default_max_top5")]
7057    pub top_5_concentration: f64,
7058
7059    /// Percentage of single-source vendors (default: 0.05).
7060    #[serde(default = "default_single_source_percent")]
7061    pub single_source_percent: f64,
7062}
7063
7064fn default_max_single_vendor() -> f64 {
7065    0.15
7066}
7067
7068fn default_max_top5() -> f64 {
7069    0.45
7070}
7071
7072fn default_single_source_percent() -> f64 {
7073    0.05
7074}
7075
7076impl Default for DependencySchemaConfig {
7077    fn default() -> Self {
7078        Self {
7079            max_single_vendor_concentration: 0.15,
7080            top_5_concentration: 0.45,
7081            single_source_percent: 0.05,
7082        }
7083    }
7084}
7085
7086// =============================================================================
7087// Customer Segmentation Configuration
7088// =============================================================================
7089
7090/// Configuration for customer segmentation generation.
7091#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7092pub struct CustomerSegmentationSchemaConfig {
7093    /// Enable customer segmentation generation.
7094    #[serde(default)]
7095    pub enabled: bool,
7096
7097    /// Value segment distribution.
7098    #[serde(default)]
7099    pub value_segments: ValueSegmentsSchemaConfig,
7100
7101    /// Lifecycle stage configuration.
7102    #[serde(default)]
7103    pub lifecycle: LifecycleSchemaConfig,
7104
7105    /// Network (referrals, hierarchies) configuration.
7106    #[serde(default)]
7107    pub networks: CustomerNetworksSchemaConfig,
7108}
7109
7110/// Customer value segments distribution configuration.
7111#[derive(Debug, Clone, Serialize, Deserialize)]
7112pub struct ValueSegmentsSchemaConfig {
7113    /// Enterprise segment configuration.
7114    #[serde(default)]
7115    pub enterprise: SegmentDetailSchemaConfig,
7116
7117    /// Mid-market segment configuration.
7118    #[serde(default)]
7119    pub mid_market: SegmentDetailSchemaConfig,
7120
7121    /// SMB segment configuration.
7122    #[serde(default)]
7123    pub smb: SegmentDetailSchemaConfig,
7124
7125    /// Consumer segment configuration.
7126    #[serde(default)]
7127    pub consumer: SegmentDetailSchemaConfig,
7128}
7129
7130impl Default for ValueSegmentsSchemaConfig {
7131    fn default() -> Self {
7132        Self {
7133            enterprise: SegmentDetailSchemaConfig {
7134                revenue_share: 0.40,
7135                customer_share: 0.05,
7136                avg_order_value_range: "50000+".to_string(),
7137            },
7138            mid_market: SegmentDetailSchemaConfig {
7139                revenue_share: 0.35,
7140                customer_share: 0.20,
7141                avg_order_value_range: "5000-50000".to_string(),
7142            },
7143            smb: SegmentDetailSchemaConfig {
7144                revenue_share: 0.20,
7145                customer_share: 0.50,
7146                avg_order_value_range: "500-5000".to_string(),
7147            },
7148            consumer: SegmentDetailSchemaConfig {
7149                revenue_share: 0.05,
7150                customer_share: 0.25,
7151                avg_order_value_range: "50-500".to_string(),
7152            },
7153        }
7154    }
7155}
7156
7157/// Individual segment detail configuration.
7158#[derive(Debug, Clone, Serialize, Deserialize)]
7159pub struct SegmentDetailSchemaConfig {
7160    /// Revenue share for this segment.
7161    #[serde(default)]
7162    pub revenue_share: f64,
7163
7164    /// Customer share for this segment.
7165    #[serde(default)]
7166    pub customer_share: f64,
7167
7168    /// Average order value range (e.g., "5000-50000" or "50000+").
7169    #[serde(default)]
7170    pub avg_order_value_range: String,
7171}
7172
7173impl Default for SegmentDetailSchemaConfig {
7174    fn default() -> Self {
7175        Self {
7176            revenue_share: 0.25,
7177            customer_share: 0.25,
7178            avg_order_value_range: "1000-10000".to_string(),
7179        }
7180    }
7181}
7182
7183/// Customer lifecycle stage configuration.
7184#[derive(Debug, Clone, Serialize, Deserialize)]
7185pub struct LifecycleSchemaConfig {
7186    /// Prospect stage rate.
7187    #[serde(default)]
7188    pub prospect_rate: f64,
7189
7190    /// New customer stage rate.
7191    #[serde(default = "default_new_rate")]
7192    pub new_rate: f64,
7193
7194    /// Growth stage rate.
7195    #[serde(default = "default_growth_rate")]
7196    pub growth_rate: f64,
7197
7198    /// Mature stage rate.
7199    #[serde(default = "default_mature_rate")]
7200    pub mature_rate: f64,
7201
7202    /// At-risk stage rate.
7203    #[serde(default = "default_at_risk_rate")]
7204    pub at_risk_rate: f64,
7205
7206    /// Churned stage rate.
7207    #[serde(default = "default_churned_rate")]
7208    pub churned_rate: f64,
7209
7210    /// Won-back stage rate (churned customers reacquired).
7211    #[serde(default)]
7212    pub won_back_rate: f64,
7213}
7214
7215fn default_new_rate() -> f64 {
7216    0.10
7217}
7218
7219fn default_growth_rate() -> f64 {
7220    0.15
7221}
7222
7223fn default_mature_rate() -> f64 {
7224    0.60
7225}
7226
7227fn default_at_risk_rate() -> f64 {
7228    0.10
7229}
7230
7231fn default_churned_rate() -> f64 {
7232    0.05
7233}
7234
7235impl Default for LifecycleSchemaConfig {
7236    fn default() -> Self {
7237        Self {
7238            prospect_rate: 0.0,
7239            new_rate: 0.10,
7240            growth_rate: 0.15,
7241            mature_rate: 0.60,
7242            at_risk_rate: 0.10,
7243            churned_rate: 0.05,
7244            won_back_rate: 0.0,
7245        }
7246    }
7247}
7248
7249/// Customer networks configuration (referrals, hierarchies).
7250#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7251pub struct CustomerNetworksSchemaConfig {
7252    /// Referral network configuration.
7253    #[serde(default)]
7254    pub referrals: ReferralSchemaConfig,
7255
7256    /// Corporate hierarchy configuration.
7257    #[serde(default)]
7258    pub corporate_hierarchies: HierarchySchemaConfig,
7259}
7260
7261/// Referral network configuration.
7262#[derive(Debug, Clone, Serialize, Deserialize)]
7263pub struct ReferralSchemaConfig {
7264    /// Enable referral generation.
7265    #[serde(default = "default_true")]
7266    pub enabled: bool,
7267
7268    /// Rate of customers acquired via referral.
7269    #[serde(default = "default_referral_rate")]
7270    pub referral_rate: f64,
7271}
7272
7273fn default_referral_rate() -> f64 {
7274    0.15
7275}
7276
7277impl Default for ReferralSchemaConfig {
7278    fn default() -> Self {
7279        Self {
7280            enabled: true,
7281            referral_rate: 0.15,
7282        }
7283    }
7284}
7285
7286/// Corporate hierarchy configuration.
7287#[derive(Debug, Clone, Serialize, Deserialize)]
7288pub struct HierarchySchemaConfig {
7289    /// Enable corporate hierarchy generation.
7290    #[serde(default = "default_true")]
7291    pub enabled: bool,
7292
7293    /// Rate of customers in hierarchies.
7294    #[serde(default = "default_hierarchy_rate")]
7295    pub probability: f64,
7296}
7297
7298fn default_hierarchy_rate() -> f64 {
7299    0.30
7300}
7301
7302impl Default for HierarchySchemaConfig {
7303    fn default() -> Self {
7304        Self {
7305            enabled: true,
7306            probability: 0.30,
7307        }
7308    }
7309}
7310
7311// =============================================================================
7312// Relationship Strength Configuration
7313// =============================================================================
7314
7315/// Configuration for relationship strength calculation.
7316#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7317pub struct RelationshipStrengthSchemaConfig {
7318    /// Enable relationship strength calculation.
7319    #[serde(default)]
7320    pub enabled: bool,
7321
7322    /// Calculation weights.
7323    #[serde(default)]
7324    pub calculation: StrengthCalculationSchemaConfig,
7325
7326    /// Strength thresholds for classification.
7327    #[serde(default)]
7328    pub thresholds: StrengthThresholdsSchemaConfig,
7329}
7330
7331/// Strength calculation weights configuration.
7332#[derive(Debug, Clone, Serialize, Deserialize)]
7333pub struct StrengthCalculationSchemaConfig {
7334    /// Weight for transaction volume (default: 0.30).
7335    #[serde(default = "default_volume_weight")]
7336    pub transaction_volume_weight: f64,
7337
7338    /// Weight for transaction count (default: 0.25).
7339    #[serde(default = "default_count_weight")]
7340    pub transaction_count_weight: f64,
7341
7342    /// Weight for relationship duration (default: 0.20).
7343    #[serde(default = "default_duration_weight")]
7344    pub relationship_duration_weight: f64,
7345
7346    /// Weight for recency (default: 0.15).
7347    #[serde(default = "default_recency_weight")]
7348    pub recency_weight: f64,
7349
7350    /// Weight for mutual connections (default: 0.10).
7351    #[serde(default = "default_mutual_weight")]
7352    pub mutual_connections_weight: f64,
7353
7354    /// Recency half-life in days (default: 90).
7355    #[serde(default = "default_recency_half_life")]
7356    pub recency_half_life_days: u32,
7357}
7358
7359fn default_volume_weight() -> f64 {
7360    0.30
7361}
7362
7363fn default_count_weight() -> f64 {
7364    0.25
7365}
7366
7367fn default_duration_weight() -> f64 {
7368    0.20
7369}
7370
7371fn default_recency_weight() -> f64 {
7372    0.15
7373}
7374
7375fn default_mutual_weight() -> f64 {
7376    0.10
7377}
7378
7379fn default_recency_half_life() -> u32 {
7380    90
7381}
7382
7383impl Default for StrengthCalculationSchemaConfig {
7384    fn default() -> Self {
7385        Self {
7386            transaction_volume_weight: 0.30,
7387            transaction_count_weight: 0.25,
7388            relationship_duration_weight: 0.20,
7389            recency_weight: 0.15,
7390            mutual_connections_weight: 0.10,
7391            recency_half_life_days: 90,
7392        }
7393    }
7394}
7395
7396/// Strength thresholds for relationship classification.
7397#[derive(Debug, Clone, Serialize, Deserialize)]
7398pub struct StrengthThresholdsSchemaConfig {
7399    /// Threshold for strong relationships (default: 0.7).
7400    #[serde(default = "default_strong_threshold")]
7401    pub strong: f64,
7402
7403    /// Threshold for moderate relationships (default: 0.4).
7404    #[serde(default = "default_moderate_threshold")]
7405    pub moderate: f64,
7406
7407    /// Threshold for weak relationships (default: 0.1).
7408    #[serde(default = "default_weak_threshold")]
7409    pub weak: f64,
7410}
7411
7412fn default_strong_threshold() -> f64 {
7413    0.7
7414}
7415
7416fn default_moderate_threshold() -> f64 {
7417    0.4
7418}
7419
7420fn default_weak_threshold() -> f64 {
7421    0.1
7422}
7423
7424impl Default for StrengthThresholdsSchemaConfig {
7425    fn default() -> Self {
7426        Self {
7427            strong: 0.7,
7428            moderate: 0.4,
7429            weak: 0.1,
7430        }
7431    }
7432}
7433
7434// =============================================================================
7435// Cross-Process Links Configuration
7436// =============================================================================
7437
7438/// Configuration for cross-process linkages.
7439#[derive(Debug, Clone, Serialize, Deserialize)]
7440pub struct CrossProcessLinksSchemaConfig {
7441    /// Enable cross-process link generation.
7442    #[serde(default)]
7443    pub enabled: bool,
7444
7445    /// Enable inventory links between P2P and O2C.
7446    #[serde(default = "default_true")]
7447    pub inventory_p2p_o2c: bool,
7448
7449    /// Enable payment to bank reconciliation links.
7450    #[serde(default = "default_true")]
7451    pub payment_bank_reconciliation: bool,
7452
7453    /// Enable intercompany bilateral matching.
7454    #[serde(default = "default_true")]
7455    pub intercompany_bilateral: bool,
7456
7457    /// Percentage of GR/Deliveries to link via inventory (0.0 - 1.0).
7458    #[serde(default = "default_inventory_link_rate")]
7459    pub inventory_link_rate: f64,
7460}
7461
7462fn default_inventory_link_rate() -> f64 {
7463    0.30
7464}
7465
7466impl Default for CrossProcessLinksSchemaConfig {
7467    fn default() -> Self {
7468        Self {
7469            enabled: false,
7470            inventory_p2p_o2c: true,
7471            payment_bank_reconciliation: true,
7472            intercompany_bilateral: true,
7473            inventory_link_rate: 0.30,
7474        }
7475    }
7476}
7477
7478// =============================================================================
7479// Organizational Events Configuration
7480// =============================================================================
7481
7482/// Configuration for organizational events (acquisitions, divestitures, etc.).
7483#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7484pub struct OrganizationalEventsSchemaConfig {
7485    /// Enable organizational events.
7486    #[serde(default)]
7487    pub enabled: bool,
7488
7489    /// Effect blending mode (multiplicative, additive, maximum, minimum).
7490    #[serde(default)]
7491    pub effect_blending: EffectBlendingModeConfig,
7492
7493    /// Organizational events (acquisitions, divestitures, reorganizations, etc.).
7494    #[serde(default)]
7495    pub events: Vec<OrganizationalEventSchemaConfig>,
7496
7497    /// Process evolution events.
7498    #[serde(default)]
7499    pub process_evolution: Vec<ProcessEvolutionSchemaConfig>,
7500
7501    /// Technology transition events.
7502    #[serde(default)]
7503    pub technology_transitions: Vec<TechnologyTransitionSchemaConfig>,
7504}
7505
7506/// Effect blending mode for combining multiple event effects.
7507#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7508#[serde(rename_all = "snake_case")]
7509pub enum EffectBlendingModeConfig {
7510    /// Multiply effects together.
7511    #[default]
7512    Multiplicative,
7513    /// Add effects together.
7514    Additive,
7515    /// Take the maximum effect.
7516    Maximum,
7517    /// Take the minimum effect.
7518    Minimum,
7519}
7520
7521/// Configuration for a single organizational event.
7522#[derive(Debug, Clone, Serialize, Deserialize)]
7523pub struct OrganizationalEventSchemaConfig {
7524    /// Event ID.
7525    pub id: String,
7526
7527    /// Event type and configuration.
7528    pub event_type: OrganizationalEventTypeSchemaConfig,
7529
7530    /// Effective date.
7531    pub effective_date: String,
7532
7533    /// Transition duration in months.
7534    #[serde(default = "default_org_transition_months")]
7535    pub transition_months: u32,
7536
7537    /// Description.
7538    #[serde(default)]
7539    pub description: Option<String>,
7540}
7541
7542fn default_org_transition_months() -> u32 {
7543    6
7544}
7545
7546/// Organizational event type configuration.
7547#[derive(Debug, Clone, Serialize, Deserialize)]
7548#[serde(tag = "type", rename_all = "snake_case")]
7549pub enum OrganizationalEventTypeSchemaConfig {
7550    /// Acquisition event.
7551    Acquisition {
7552        /// Acquired entity code.
7553        acquired_entity: String,
7554        /// Volume increase multiplier.
7555        #[serde(default = "default_acquisition_volume")]
7556        volume_increase: f64,
7557        /// Integration error rate.
7558        #[serde(default = "default_acquisition_error")]
7559        integration_error_rate: f64,
7560        /// Parallel posting days.
7561        #[serde(default = "default_parallel_days")]
7562        parallel_posting_days: u32,
7563    },
7564    /// Divestiture event.
7565    Divestiture {
7566        /// Divested entity code.
7567        divested_entity: String,
7568        /// Volume reduction factor.
7569        #[serde(default = "default_divestiture_volume")]
7570        volume_reduction: f64,
7571        /// Remove entity from generation.
7572        #[serde(default = "default_true_val")]
7573        remove_entity: bool,
7574    },
7575    /// Reorganization event.
7576    Reorganization {
7577        /// Cost center remapping.
7578        #[serde(default)]
7579        cost_center_remapping: std::collections::HashMap<String, String>,
7580        /// Transition error rate.
7581        #[serde(default = "default_reorg_error")]
7582        transition_error_rate: f64,
7583    },
7584    /// Leadership change event.
7585    LeadershipChange {
7586        /// Role that changed.
7587        role: String,
7588        /// Policy changes.
7589        #[serde(default)]
7590        policy_changes: Vec<String>,
7591    },
7592    /// Workforce reduction event.
7593    WorkforceReduction {
7594        /// Reduction percentage.
7595        #[serde(default = "default_workforce_reduction")]
7596        reduction_percent: f64,
7597        /// Error rate increase.
7598        #[serde(default = "default_workforce_error")]
7599        error_rate_increase: f64,
7600    },
7601    /// Merger event.
7602    Merger {
7603        /// Merged entity code.
7604        merged_entity: String,
7605        /// Volume increase multiplier.
7606        #[serde(default = "default_merger_volume")]
7607        volume_increase: f64,
7608    },
7609}
7610
7611fn default_acquisition_volume() -> f64 {
7612    1.35
7613}
7614
7615fn default_acquisition_error() -> f64 {
7616    0.05
7617}
7618
7619fn default_parallel_days() -> u32 {
7620    30
7621}
7622
7623fn default_divestiture_volume() -> f64 {
7624    0.70
7625}
7626
7627fn default_true_val() -> bool {
7628    true
7629}
7630
7631fn default_reorg_error() -> f64 {
7632    0.04
7633}
7634
7635fn default_workforce_reduction() -> f64 {
7636    0.10
7637}
7638
7639fn default_workforce_error() -> f64 {
7640    0.05
7641}
7642
7643fn default_merger_volume() -> f64 {
7644    1.80
7645}
7646
7647/// Configuration for a process evolution event.
7648#[derive(Debug, Clone, Serialize, Deserialize)]
7649pub struct ProcessEvolutionSchemaConfig {
7650    /// Event ID.
7651    pub id: String,
7652
7653    /// Event type.
7654    pub event_type: ProcessEvolutionTypeSchemaConfig,
7655
7656    /// Effective date.
7657    pub effective_date: String,
7658
7659    /// Description.
7660    #[serde(default)]
7661    pub description: Option<String>,
7662}
7663
7664/// Process evolution type configuration.
7665#[derive(Debug, Clone, Serialize, Deserialize)]
7666#[serde(tag = "type", rename_all = "snake_case")]
7667pub enum ProcessEvolutionTypeSchemaConfig {
7668    /// Process automation.
7669    ProcessAutomation {
7670        /// Process name.
7671        process_name: String,
7672        /// Manual rate before.
7673        #[serde(default = "default_manual_before")]
7674        manual_rate_before: f64,
7675        /// Manual rate after.
7676        #[serde(default = "default_manual_after")]
7677        manual_rate_after: f64,
7678    },
7679    /// Approval workflow change.
7680    ApprovalWorkflowChange {
7681        /// Description.
7682        description: String,
7683    },
7684    /// Control enhancement.
7685    ControlEnhancement {
7686        /// Control ID.
7687        control_id: String,
7688        /// Error reduction.
7689        #[serde(default = "default_error_reduction")]
7690        error_reduction: f64,
7691    },
7692}
7693
7694fn default_manual_before() -> f64 {
7695    0.80
7696}
7697
7698fn default_manual_after() -> f64 {
7699    0.15
7700}
7701
7702fn default_error_reduction() -> f64 {
7703    0.02
7704}
7705
7706/// Configuration for a technology transition event.
7707#[derive(Debug, Clone, Serialize, Deserialize)]
7708pub struct TechnologyTransitionSchemaConfig {
7709    /// Event ID.
7710    pub id: String,
7711
7712    /// Event type.
7713    pub event_type: TechnologyTransitionTypeSchemaConfig,
7714
7715    /// Description.
7716    #[serde(default)]
7717    pub description: Option<String>,
7718}
7719
7720/// Technology transition type configuration.
7721#[derive(Debug, Clone, Serialize, Deserialize)]
7722#[serde(tag = "type", rename_all = "snake_case")]
7723pub enum TechnologyTransitionTypeSchemaConfig {
7724    /// ERP migration.
7725    ErpMigration {
7726        /// Source system.
7727        source_system: String,
7728        /// Target system.
7729        target_system: String,
7730        /// Cutover date.
7731        cutover_date: String,
7732        /// Stabilization end date.
7733        stabilization_end: String,
7734        /// Duplicate rate during migration.
7735        #[serde(default = "default_erp_duplicate_rate")]
7736        duplicate_rate: f64,
7737        /// Format mismatch rate.
7738        #[serde(default = "default_format_mismatch")]
7739        format_mismatch_rate: f64,
7740    },
7741    /// Module implementation.
7742    ModuleImplementation {
7743        /// Module name.
7744        module_name: String,
7745        /// Go-live date.
7746        go_live_date: String,
7747    },
7748}
7749
7750fn default_erp_duplicate_rate() -> f64 {
7751    0.02
7752}
7753
7754fn default_format_mismatch() -> f64 {
7755    0.03
7756}
7757
7758// =============================================================================
7759// Behavioral Drift Configuration
7760// =============================================================================
7761
7762/// Configuration for behavioral drift (vendor, customer, employee behavior).
7763#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7764pub struct BehavioralDriftSchemaConfig {
7765    /// Enable behavioral drift.
7766    #[serde(default)]
7767    pub enabled: bool,
7768
7769    /// Vendor behavior drift.
7770    #[serde(default)]
7771    pub vendor_behavior: VendorBehaviorSchemaConfig,
7772
7773    /// Customer behavior drift.
7774    #[serde(default)]
7775    pub customer_behavior: CustomerBehaviorSchemaConfig,
7776
7777    /// Employee behavior drift.
7778    #[serde(default)]
7779    pub employee_behavior: EmployeeBehaviorSchemaConfig,
7780
7781    /// Collective behavior drift.
7782    #[serde(default)]
7783    pub collective: CollectiveBehaviorSchemaConfig,
7784}
7785
7786/// Vendor behavior drift configuration.
7787#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7788pub struct VendorBehaviorSchemaConfig {
7789    /// Payment terms drift.
7790    #[serde(default)]
7791    pub payment_terms_drift: PaymentTermsDriftSchemaConfig,
7792
7793    /// Quality drift.
7794    #[serde(default)]
7795    pub quality_drift: QualityDriftSchemaConfig,
7796}
7797
7798/// Payment terms drift configuration.
7799#[derive(Debug, Clone, Serialize, Deserialize)]
7800pub struct PaymentTermsDriftSchemaConfig {
7801    /// Extension rate per year (days).
7802    #[serde(default = "default_extension_rate")]
7803    pub extension_rate_per_year: f64,
7804
7805    /// Economic sensitivity.
7806    #[serde(default = "default_economic_sensitivity")]
7807    pub economic_sensitivity: f64,
7808}
7809
7810fn default_extension_rate() -> f64 {
7811    2.5
7812}
7813
7814fn default_economic_sensitivity() -> f64 {
7815    1.0
7816}
7817
7818impl Default for PaymentTermsDriftSchemaConfig {
7819    fn default() -> Self {
7820        Self {
7821            extension_rate_per_year: 2.5,
7822            economic_sensitivity: 1.0,
7823        }
7824    }
7825}
7826
7827/// Quality drift configuration.
7828#[derive(Debug, Clone, Serialize, Deserialize)]
7829pub struct QualityDriftSchemaConfig {
7830    /// New vendor improvement rate (per year).
7831    #[serde(default = "default_improvement_rate")]
7832    pub new_vendor_improvement_rate: f64,
7833
7834    /// Complacency decline rate (per year after first year).
7835    #[serde(default = "default_decline_rate")]
7836    pub complacency_decline_rate: f64,
7837}
7838
7839fn default_improvement_rate() -> f64 {
7840    0.02
7841}
7842
7843fn default_decline_rate() -> f64 {
7844    0.01
7845}
7846
7847impl Default for QualityDriftSchemaConfig {
7848    fn default() -> Self {
7849        Self {
7850            new_vendor_improvement_rate: 0.02,
7851            complacency_decline_rate: 0.01,
7852        }
7853    }
7854}
7855
7856/// Customer behavior drift configuration.
7857#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7858pub struct CustomerBehaviorSchemaConfig {
7859    /// Payment drift.
7860    #[serde(default)]
7861    pub payment_drift: CustomerPaymentDriftSchemaConfig,
7862
7863    /// Order drift.
7864    #[serde(default)]
7865    pub order_drift: OrderDriftSchemaConfig,
7866}
7867
7868/// Customer payment drift configuration.
7869#[derive(Debug, Clone, Serialize, Deserialize)]
7870pub struct CustomerPaymentDriftSchemaConfig {
7871    /// Days extension during downturn (min, max).
7872    #[serde(default = "default_downturn_extension")]
7873    pub downturn_days_extension: (u32, u32),
7874
7875    /// Bad debt increase during downturn.
7876    #[serde(default = "default_bad_debt_increase")]
7877    pub downturn_bad_debt_increase: f64,
7878}
7879
7880fn default_downturn_extension() -> (u32, u32) {
7881    (5, 15)
7882}
7883
7884fn default_bad_debt_increase() -> f64 {
7885    0.02
7886}
7887
7888impl Default for CustomerPaymentDriftSchemaConfig {
7889    fn default() -> Self {
7890        Self {
7891            downturn_days_extension: (5, 15),
7892            downturn_bad_debt_increase: 0.02,
7893        }
7894    }
7895}
7896
7897/// Order drift configuration.
7898#[derive(Debug, Clone, Serialize, Deserialize)]
7899pub struct OrderDriftSchemaConfig {
7900    /// Digital shift rate (per year).
7901    #[serde(default = "default_digital_shift")]
7902    pub digital_shift_rate: f64,
7903}
7904
7905fn default_digital_shift() -> f64 {
7906    0.05
7907}
7908
7909impl Default for OrderDriftSchemaConfig {
7910    fn default() -> Self {
7911        Self {
7912            digital_shift_rate: 0.05,
7913        }
7914    }
7915}
7916
7917/// Employee behavior drift configuration.
7918#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7919pub struct EmployeeBehaviorSchemaConfig {
7920    /// Approval drift.
7921    #[serde(default)]
7922    pub approval_drift: ApprovalDriftSchemaConfig,
7923
7924    /// Error drift.
7925    #[serde(default)]
7926    pub error_drift: ErrorDriftSchemaConfig,
7927}
7928
7929/// Approval drift configuration.
7930#[derive(Debug, Clone, Serialize, Deserialize)]
7931pub struct ApprovalDriftSchemaConfig {
7932    /// EOM intensity increase per year.
7933    #[serde(default = "default_eom_intensity")]
7934    pub eom_intensity_increase_per_year: f64,
7935
7936    /// Rubber stamp volume threshold.
7937    #[serde(default = "default_rubber_stamp")]
7938    pub rubber_stamp_volume_threshold: u32,
7939}
7940
7941fn default_eom_intensity() -> f64 {
7942    0.05
7943}
7944
7945fn default_rubber_stamp() -> u32 {
7946    50
7947}
7948
7949impl Default for ApprovalDriftSchemaConfig {
7950    fn default() -> Self {
7951        Self {
7952            eom_intensity_increase_per_year: 0.05,
7953            rubber_stamp_volume_threshold: 50,
7954        }
7955    }
7956}
7957
7958/// Error drift configuration.
7959#[derive(Debug, Clone, Serialize, Deserialize)]
7960pub struct ErrorDriftSchemaConfig {
7961    /// New employee error rate.
7962    #[serde(default = "default_new_error")]
7963    pub new_employee_error_rate: f64,
7964
7965    /// Learning curve months.
7966    #[serde(default = "default_learning_months")]
7967    pub learning_curve_months: u32,
7968}
7969
7970fn default_new_error() -> f64 {
7971    0.08
7972}
7973
7974fn default_learning_months() -> u32 {
7975    6
7976}
7977
7978impl Default for ErrorDriftSchemaConfig {
7979    fn default() -> Self {
7980        Self {
7981            new_employee_error_rate: 0.08,
7982            learning_curve_months: 6,
7983        }
7984    }
7985}
7986
7987/// Collective behavior drift configuration.
7988#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7989pub struct CollectiveBehaviorSchemaConfig {
7990    /// Automation adoption configuration.
7991    #[serde(default)]
7992    pub automation_adoption: AutomationAdoptionSchemaConfig,
7993}
7994
7995/// Automation adoption configuration.
7996#[derive(Debug, Clone, Serialize, Deserialize)]
7997pub struct AutomationAdoptionSchemaConfig {
7998    /// Enable S-curve adoption model.
7999    #[serde(default)]
8000    pub s_curve_enabled: bool,
8001
8002    /// Adoption midpoint in months.
8003    #[serde(default = "default_midpoint")]
8004    pub adoption_midpoint_months: u32,
8005
8006    /// Steepness of adoption curve.
8007    #[serde(default = "default_steepness")]
8008    pub steepness: f64,
8009}
8010
8011fn default_midpoint() -> u32 {
8012    24
8013}
8014
8015fn default_steepness() -> f64 {
8016    0.15
8017}
8018
8019impl Default for AutomationAdoptionSchemaConfig {
8020    fn default() -> Self {
8021        Self {
8022            s_curve_enabled: false,
8023            adoption_midpoint_months: 24,
8024            steepness: 0.15,
8025        }
8026    }
8027}
8028
8029// =============================================================================
8030// Market Drift Configuration
8031// =============================================================================
8032
8033/// Configuration for market drift (economic cycles, commodities, price shocks).
8034#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8035pub struct MarketDriftSchemaConfig {
8036    /// Enable market drift.
8037    #[serde(default)]
8038    pub enabled: bool,
8039
8040    /// Economic cycle configuration.
8041    #[serde(default)]
8042    pub economic_cycle: MarketEconomicCycleSchemaConfig,
8043
8044    /// Industry-specific cycles.
8045    #[serde(default)]
8046    pub industry_cycles: std::collections::HashMap<String, IndustryCycleSchemaConfig>,
8047
8048    /// Commodity drift configuration.
8049    #[serde(default)]
8050    pub commodities: CommoditiesSchemaConfig,
8051}
8052
8053/// Market economic cycle configuration.
8054#[derive(Debug, Clone, Serialize, Deserialize)]
8055pub struct MarketEconomicCycleSchemaConfig {
8056    /// Enable economic cycle.
8057    #[serde(default)]
8058    pub enabled: bool,
8059
8060    /// Cycle type.
8061    #[serde(default)]
8062    pub cycle_type: CycleTypeSchemaConfig,
8063
8064    /// Cycle period in months.
8065    #[serde(default = "default_market_cycle_period")]
8066    pub period_months: u32,
8067
8068    /// Amplitude.
8069    #[serde(default = "default_market_amplitude")]
8070    pub amplitude: f64,
8071
8072    /// Recession configuration.
8073    #[serde(default)]
8074    pub recession: RecessionSchemaConfig,
8075}
8076
8077fn default_market_cycle_period() -> u32 {
8078    48
8079}
8080
8081fn default_market_amplitude() -> f64 {
8082    0.15
8083}
8084
8085impl Default for MarketEconomicCycleSchemaConfig {
8086    fn default() -> Self {
8087        Self {
8088            enabled: false,
8089            cycle_type: CycleTypeSchemaConfig::Sinusoidal,
8090            period_months: 48,
8091            amplitude: 0.15,
8092            recession: RecessionSchemaConfig::default(),
8093        }
8094    }
8095}
8096
8097/// Cycle type configuration.
8098#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
8099#[serde(rename_all = "snake_case")]
8100pub enum CycleTypeSchemaConfig {
8101    /// Sinusoidal cycle.
8102    #[default]
8103    Sinusoidal,
8104    /// Asymmetric cycle.
8105    Asymmetric,
8106    /// Mean-reverting cycle.
8107    MeanReverting,
8108}
8109
8110/// Recession configuration.
8111#[derive(Debug, Clone, Serialize, Deserialize)]
8112pub struct RecessionSchemaConfig {
8113    /// Enable recession simulation.
8114    #[serde(default)]
8115    pub enabled: bool,
8116
8117    /// Probability per year.
8118    #[serde(default = "default_recession_prob")]
8119    pub probability_per_year: f64,
8120
8121    /// Severity.
8122    #[serde(default)]
8123    pub severity: RecessionSeveritySchemaConfig,
8124
8125    /// Specific recession periods.
8126    #[serde(default)]
8127    pub recession_periods: Vec<RecessionPeriodSchemaConfig>,
8128}
8129
8130fn default_recession_prob() -> f64 {
8131    0.10
8132}
8133
8134impl Default for RecessionSchemaConfig {
8135    fn default() -> Self {
8136        Self {
8137            enabled: false,
8138            probability_per_year: 0.10,
8139            severity: RecessionSeveritySchemaConfig::Moderate,
8140            recession_periods: Vec::new(),
8141        }
8142    }
8143}
8144
8145/// Recession severity configuration.
8146#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
8147#[serde(rename_all = "snake_case")]
8148pub enum RecessionSeveritySchemaConfig {
8149    /// Mild recession.
8150    Mild,
8151    /// Moderate recession.
8152    #[default]
8153    Moderate,
8154    /// Severe recession.
8155    Severe,
8156}
8157
8158/// Recession period configuration.
8159#[derive(Debug, Clone, Serialize, Deserialize)]
8160pub struct RecessionPeriodSchemaConfig {
8161    /// Start month.
8162    pub start_month: u32,
8163    /// Duration in months.
8164    pub duration_months: u32,
8165}
8166
8167/// Industry cycle configuration.
8168#[derive(Debug, Clone, Serialize, Deserialize)]
8169pub struct IndustryCycleSchemaConfig {
8170    /// Period in months.
8171    #[serde(default = "default_industry_period")]
8172    pub period_months: u32,
8173
8174    /// Amplitude.
8175    #[serde(default = "default_industry_amp")]
8176    pub amplitude: f64,
8177}
8178
8179fn default_industry_period() -> u32 {
8180    36
8181}
8182
8183fn default_industry_amp() -> f64 {
8184    0.20
8185}
8186
8187/// Commodities drift configuration.
8188#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8189pub struct CommoditiesSchemaConfig {
8190    /// Enable commodity drift.
8191    #[serde(default)]
8192    pub enabled: bool,
8193
8194    /// Commodity items.
8195    #[serde(default)]
8196    pub items: Vec<CommodityItemSchemaConfig>,
8197}
8198
8199/// Commodity item configuration.
8200#[derive(Debug, Clone, Serialize, Deserialize)]
8201pub struct CommodityItemSchemaConfig {
8202    /// Commodity name.
8203    pub name: String,
8204
8205    /// Volatility.
8206    #[serde(default = "default_volatility")]
8207    pub volatility: f64,
8208
8209    /// COGS pass-through.
8210    #[serde(default)]
8211    pub cogs_pass_through: f64,
8212
8213    /// Overhead pass-through.
8214    #[serde(default)]
8215    pub overhead_pass_through: f64,
8216}
8217
8218fn default_volatility() -> f64 {
8219    0.20
8220}
8221
8222// =============================================================================
8223// Drift Labeling Configuration
8224// =============================================================================
8225
8226/// Configuration for drift ground truth labeling.
8227#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8228pub struct DriftLabelingSchemaConfig {
8229    /// Enable drift labeling.
8230    #[serde(default)]
8231    pub enabled: bool,
8232
8233    /// Statistical drift labeling.
8234    #[serde(default)]
8235    pub statistical: StatisticalDriftLabelingSchemaConfig,
8236
8237    /// Categorical drift labeling.
8238    #[serde(default)]
8239    pub categorical: CategoricalDriftLabelingSchemaConfig,
8240
8241    /// Temporal drift labeling.
8242    #[serde(default)]
8243    pub temporal: TemporalDriftLabelingSchemaConfig,
8244
8245    /// Regulatory calendar preset.
8246    #[serde(default)]
8247    pub regulatory_calendar_preset: Option<String>,
8248}
8249
8250/// Statistical drift labeling configuration.
8251#[derive(Debug, Clone, Serialize, Deserialize)]
8252pub struct StatisticalDriftLabelingSchemaConfig {
8253    /// Enable statistical drift labeling.
8254    #[serde(default = "default_true_val")]
8255    pub enabled: bool,
8256
8257    /// Minimum magnitude threshold.
8258    #[serde(default = "default_min_magnitude")]
8259    pub min_magnitude_threshold: f64,
8260}
8261
8262fn default_min_magnitude() -> f64 {
8263    0.05
8264}
8265
8266impl Default for StatisticalDriftLabelingSchemaConfig {
8267    fn default() -> Self {
8268        Self {
8269            enabled: true,
8270            min_magnitude_threshold: 0.05,
8271        }
8272    }
8273}
8274
8275/// Categorical drift labeling configuration.
8276#[derive(Debug, Clone, Serialize, Deserialize)]
8277pub struct CategoricalDriftLabelingSchemaConfig {
8278    /// Enable categorical drift labeling.
8279    #[serde(default = "default_true_val")]
8280    pub enabled: bool,
8281}
8282
8283impl Default for CategoricalDriftLabelingSchemaConfig {
8284    fn default() -> Self {
8285        Self { enabled: true }
8286    }
8287}
8288
8289/// Temporal drift labeling configuration.
8290#[derive(Debug, Clone, Serialize, Deserialize)]
8291pub struct TemporalDriftLabelingSchemaConfig {
8292    /// Enable temporal drift labeling.
8293    #[serde(default = "default_true_val")]
8294    pub enabled: bool,
8295}
8296
8297impl Default for TemporalDriftLabelingSchemaConfig {
8298    fn default() -> Self {
8299        Self { enabled: true }
8300    }
8301}
8302
8303// =============================================================================
8304// Enhanced Anomaly Injection Configuration
8305// =============================================================================
8306
8307/// Enhanced anomaly injection configuration.
8308///
8309/// Provides comprehensive anomaly injection capabilities including:
8310/// - Multi-stage fraud schemes (embezzlement, revenue manipulation, kickbacks)
8311/// - Correlated anomaly injection (co-occurrence patterns, error cascades)
8312/// - Near-miss generation for false positive reduction
8313/// - Detection difficulty classification
8314/// - Context-aware injection based on entity behavior
8315#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8316pub struct EnhancedAnomalyConfig {
8317    /// Enable enhanced anomaly injection.
8318    #[serde(default)]
8319    pub enabled: bool,
8320
8321    /// Base anomaly rates.
8322    #[serde(default)]
8323    pub rates: AnomalyRateConfig,
8324
8325    /// Multi-stage fraud scheme configuration.
8326    #[serde(default)]
8327    pub multi_stage_schemes: MultiStageSchemeConfig,
8328
8329    /// Correlated anomaly injection configuration.
8330    #[serde(default)]
8331    pub correlated_injection: CorrelatedInjectionConfig,
8332
8333    /// Near-miss generation configuration.
8334    #[serde(default)]
8335    pub near_miss: NearMissConfig,
8336
8337    /// Detection difficulty classification configuration.
8338    #[serde(default)]
8339    pub difficulty_classification: DifficultyClassificationConfig,
8340
8341    /// Context-aware injection configuration.
8342    #[serde(default)]
8343    pub context_aware: ContextAwareConfig,
8344
8345    /// Enhanced labeling configuration.
8346    #[serde(default)]
8347    pub labeling: EnhancedLabelingConfig,
8348}
8349
8350/// Base anomaly rate configuration.
8351#[derive(Debug, Clone, Serialize, Deserialize)]
8352pub struct AnomalyRateConfig {
8353    /// Total anomaly rate (0.0 to 1.0).
8354    #[serde(default = "default_total_anomaly_rate")]
8355    pub total_rate: f64,
8356
8357    /// Fraud anomaly rate.
8358    #[serde(default = "default_fraud_anomaly_rate")]
8359    pub fraud_rate: f64,
8360
8361    /// Error anomaly rate.
8362    #[serde(default = "default_error_anomaly_rate")]
8363    pub error_rate: f64,
8364
8365    /// Process issue rate.
8366    #[serde(default = "default_process_anomaly_rate")]
8367    pub process_rate: f64,
8368}
8369
8370fn default_total_anomaly_rate() -> f64 {
8371    0.03
8372}
8373fn default_fraud_anomaly_rate() -> f64 {
8374    0.01
8375}
8376fn default_error_anomaly_rate() -> f64 {
8377    0.015
8378}
8379fn default_process_anomaly_rate() -> f64 {
8380    0.005
8381}
8382
8383impl Default for AnomalyRateConfig {
8384    fn default() -> Self {
8385        Self {
8386            total_rate: default_total_anomaly_rate(),
8387            fraud_rate: default_fraud_anomaly_rate(),
8388            error_rate: default_error_anomaly_rate(),
8389            process_rate: default_process_anomaly_rate(),
8390        }
8391    }
8392}
8393
8394/// Multi-stage fraud scheme configuration.
8395#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8396pub struct MultiStageSchemeConfig {
8397    /// Enable multi-stage fraud schemes.
8398    #[serde(default)]
8399    pub enabled: bool,
8400
8401    /// Embezzlement scheme configuration.
8402    #[serde(default)]
8403    pub embezzlement: EmbezzlementSchemeConfig,
8404
8405    /// Revenue manipulation scheme configuration.
8406    #[serde(default)]
8407    pub revenue_manipulation: RevenueManipulationSchemeConfig,
8408
8409    /// Vendor kickback scheme configuration.
8410    #[serde(default)]
8411    pub kickback: KickbackSchemeConfig,
8412}
8413
8414/// Embezzlement scheme configuration.
8415#[derive(Debug, Clone, Serialize, Deserialize)]
8416pub struct EmbezzlementSchemeConfig {
8417    /// Probability of starting an embezzlement scheme per perpetrator per year.
8418    #[serde(default = "default_embezzlement_probability")]
8419    pub probability: f64,
8420
8421    /// Testing stage configuration.
8422    #[serde(default)]
8423    pub testing_stage: SchemeStageConfig,
8424
8425    /// Escalation stage configuration.
8426    #[serde(default)]
8427    pub escalation_stage: SchemeStageConfig,
8428
8429    /// Acceleration stage configuration.
8430    #[serde(default)]
8431    pub acceleration_stage: SchemeStageConfig,
8432
8433    /// Desperation stage configuration.
8434    #[serde(default)]
8435    pub desperation_stage: SchemeStageConfig,
8436}
8437
8438fn default_embezzlement_probability() -> f64 {
8439    0.02
8440}
8441
8442impl Default for EmbezzlementSchemeConfig {
8443    fn default() -> Self {
8444        Self {
8445            probability: default_embezzlement_probability(),
8446            testing_stage: SchemeStageConfig {
8447                duration_months: 2,
8448                amount_min: 100.0,
8449                amount_max: 500.0,
8450                transaction_count_min: 2,
8451                transaction_count_max: 5,
8452                difficulty: "hard".to_string(),
8453            },
8454            escalation_stage: SchemeStageConfig {
8455                duration_months: 6,
8456                amount_min: 500.0,
8457                amount_max: 2000.0,
8458                transaction_count_min: 3,
8459                transaction_count_max: 8,
8460                difficulty: "moderate".to_string(),
8461            },
8462            acceleration_stage: SchemeStageConfig {
8463                duration_months: 3,
8464                amount_min: 2000.0,
8465                amount_max: 10000.0,
8466                transaction_count_min: 5,
8467                transaction_count_max: 12,
8468                difficulty: "easy".to_string(),
8469            },
8470            desperation_stage: SchemeStageConfig {
8471                duration_months: 1,
8472                amount_min: 10000.0,
8473                amount_max: 50000.0,
8474                transaction_count_min: 3,
8475                transaction_count_max: 6,
8476                difficulty: "trivial".to_string(),
8477            },
8478        }
8479    }
8480}
8481
8482/// Revenue manipulation scheme configuration.
8483#[derive(Debug, Clone, Serialize, Deserialize)]
8484pub struct RevenueManipulationSchemeConfig {
8485    /// Probability of starting a revenue manipulation scheme per period.
8486    #[serde(default = "default_revenue_manipulation_probability")]
8487    pub probability: f64,
8488
8489    /// Early revenue recognition inflation target (Q4).
8490    #[serde(default = "default_early_recognition_target")]
8491    pub early_recognition_target: f64,
8492
8493    /// Expense deferral inflation target (Q1).
8494    #[serde(default = "default_expense_deferral_target")]
8495    pub expense_deferral_target: f64,
8496
8497    /// Reserve release inflation target (Q2).
8498    #[serde(default = "default_reserve_release_target")]
8499    pub reserve_release_target: f64,
8500
8501    /// Channel stuffing inflation target (Q4).
8502    #[serde(default = "default_channel_stuffing_target")]
8503    pub channel_stuffing_target: f64,
8504}
8505
8506fn default_revenue_manipulation_probability() -> f64 {
8507    0.01
8508}
8509fn default_early_recognition_target() -> f64 {
8510    0.02
8511}
8512fn default_expense_deferral_target() -> f64 {
8513    0.03
8514}
8515fn default_reserve_release_target() -> f64 {
8516    0.02
8517}
8518fn default_channel_stuffing_target() -> f64 {
8519    0.05
8520}
8521
8522impl Default for RevenueManipulationSchemeConfig {
8523    fn default() -> Self {
8524        Self {
8525            probability: default_revenue_manipulation_probability(),
8526            early_recognition_target: default_early_recognition_target(),
8527            expense_deferral_target: default_expense_deferral_target(),
8528            reserve_release_target: default_reserve_release_target(),
8529            channel_stuffing_target: default_channel_stuffing_target(),
8530        }
8531    }
8532}
8533
8534/// Vendor kickback scheme configuration.
8535#[derive(Debug, Clone, Serialize, Deserialize)]
8536pub struct KickbackSchemeConfig {
8537    /// Probability of starting a kickback scheme.
8538    #[serde(default = "default_kickback_probability")]
8539    pub probability: f64,
8540
8541    /// Minimum price inflation percentage.
8542    #[serde(default = "default_kickback_inflation_min")]
8543    pub inflation_min: f64,
8544
8545    /// Maximum price inflation percentage.
8546    #[serde(default = "default_kickback_inflation_max")]
8547    pub inflation_max: f64,
8548
8549    /// Kickback percentage (of inflation).
8550    #[serde(default = "default_kickback_percent")]
8551    pub kickback_percent: f64,
8552
8553    /// Setup duration in months.
8554    #[serde(default = "default_kickback_setup_months")]
8555    pub setup_months: u32,
8556
8557    /// Main operation duration in months.
8558    #[serde(default = "default_kickback_operation_months")]
8559    pub operation_months: u32,
8560}
8561
8562fn default_kickback_probability() -> f64 {
8563    0.01
8564}
8565fn default_kickback_inflation_min() -> f64 {
8566    0.10
8567}
8568fn default_kickback_inflation_max() -> f64 {
8569    0.25
8570}
8571fn default_kickback_percent() -> f64 {
8572    0.50
8573}
8574fn default_kickback_setup_months() -> u32 {
8575    3
8576}
8577fn default_kickback_operation_months() -> u32 {
8578    12
8579}
8580
8581impl Default for KickbackSchemeConfig {
8582    fn default() -> Self {
8583        Self {
8584            probability: default_kickback_probability(),
8585            inflation_min: default_kickback_inflation_min(),
8586            inflation_max: default_kickback_inflation_max(),
8587            kickback_percent: default_kickback_percent(),
8588            setup_months: default_kickback_setup_months(),
8589            operation_months: default_kickback_operation_months(),
8590        }
8591    }
8592}
8593
8594/// Individual scheme stage configuration.
8595#[derive(Debug, Clone, Serialize, Deserialize)]
8596pub struct SchemeStageConfig {
8597    /// Duration in months.
8598    pub duration_months: u32,
8599
8600    /// Minimum transaction amount.
8601    pub amount_min: f64,
8602
8603    /// Maximum transaction amount.
8604    pub amount_max: f64,
8605
8606    /// Minimum number of transactions.
8607    pub transaction_count_min: u32,
8608
8609    /// Maximum number of transactions.
8610    pub transaction_count_max: u32,
8611
8612    /// Detection difficulty level (trivial, easy, moderate, hard, expert).
8613    pub difficulty: String,
8614}
8615
8616impl Default for SchemeStageConfig {
8617    fn default() -> Self {
8618        Self {
8619            duration_months: 3,
8620            amount_min: 100.0,
8621            amount_max: 1000.0,
8622            transaction_count_min: 2,
8623            transaction_count_max: 10,
8624            difficulty: "moderate".to_string(),
8625        }
8626    }
8627}
8628
8629/// Correlated anomaly injection configuration.
8630#[derive(Debug, Clone, Serialize, Deserialize)]
8631pub struct CorrelatedInjectionConfig {
8632    /// Enable correlated anomaly injection.
8633    #[serde(default)]
8634    pub enabled: bool,
8635
8636    /// Enable fraud concealment co-occurrence patterns.
8637    #[serde(default = "default_true_val")]
8638    pub fraud_concealment: bool,
8639
8640    /// Enable error cascade patterns.
8641    #[serde(default = "default_true_val")]
8642    pub error_cascade: bool,
8643
8644    /// Enable temporal clustering (period-end spikes).
8645    #[serde(default = "default_true_val")]
8646    pub temporal_clustering: bool,
8647
8648    /// Temporal clustering configuration.
8649    #[serde(default)]
8650    pub temporal_clustering_config: TemporalClusteringConfig,
8651
8652    /// Co-occurrence patterns.
8653    #[serde(default)]
8654    pub co_occurrence_patterns: Vec<CoOccurrencePatternConfig>,
8655}
8656
8657impl Default for CorrelatedInjectionConfig {
8658    fn default() -> Self {
8659        Self {
8660            enabled: false,
8661            fraud_concealment: true,
8662            error_cascade: true,
8663            temporal_clustering: true,
8664            temporal_clustering_config: TemporalClusteringConfig::default(),
8665            co_occurrence_patterns: Vec::new(),
8666        }
8667    }
8668}
8669
8670/// Temporal clustering configuration.
8671#[derive(Debug, Clone, Serialize, Deserialize)]
8672pub struct TemporalClusteringConfig {
8673    /// Period-end error multiplier.
8674    #[serde(default = "default_period_end_multiplier")]
8675    pub period_end_multiplier: f64,
8676
8677    /// Number of business days before period end to apply multiplier.
8678    #[serde(default = "default_period_end_days")]
8679    pub period_end_days: u32,
8680
8681    /// Quarter-end additional multiplier.
8682    #[serde(default = "default_quarter_end_multiplier")]
8683    pub quarter_end_multiplier: f64,
8684
8685    /// Year-end additional multiplier.
8686    #[serde(default = "default_year_end_multiplier")]
8687    pub year_end_multiplier: f64,
8688}
8689
8690fn default_period_end_multiplier() -> f64 {
8691    2.5
8692}
8693fn default_period_end_days() -> u32 {
8694    5
8695}
8696fn default_quarter_end_multiplier() -> f64 {
8697    1.5
8698}
8699fn default_year_end_multiplier() -> f64 {
8700    2.0
8701}
8702
8703impl Default for TemporalClusteringConfig {
8704    fn default() -> Self {
8705        Self {
8706            period_end_multiplier: default_period_end_multiplier(),
8707            period_end_days: default_period_end_days(),
8708            quarter_end_multiplier: default_quarter_end_multiplier(),
8709            year_end_multiplier: default_year_end_multiplier(),
8710        }
8711    }
8712}
8713
8714/// Co-occurrence pattern configuration.
8715#[derive(Debug, Clone, Serialize, Deserialize)]
8716pub struct CoOccurrencePatternConfig {
8717    /// Pattern name.
8718    pub name: String,
8719
8720    /// Primary anomaly type that triggers the pattern.
8721    pub primary_type: String,
8722
8723    /// Correlated anomalies.
8724    pub correlated: Vec<CorrelatedAnomalyConfig>,
8725}
8726
8727/// Correlated anomaly configuration.
8728#[derive(Debug, Clone, Serialize, Deserialize)]
8729pub struct CorrelatedAnomalyConfig {
8730    /// Anomaly type.
8731    pub anomaly_type: String,
8732
8733    /// Probability of occurrence (0.0 to 1.0).
8734    pub probability: f64,
8735
8736    /// Minimum lag in days.
8737    pub lag_days_min: i32,
8738
8739    /// Maximum lag in days.
8740    pub lag_days_max: i32,
8741}
8742
8743/// Near-miss generation configuration.
8744#[derive(Debug, Clone, Serialize, Deserialize)]
8745pub struct NearMissConfig {
8746    /// Enable near-miss generation.
8747    #[serde(default)]
8748    pub enabled: bool,
8749
8750    /// Proportion of "anomalies" that are actually near-misses (0.0 to 1.0).
8751    #[serde(default = "default_near_miss_proportion")]
8752    pub proportion: f64,
8753
8754    /// Enable near-duplicate pattern.
8755    #[serde(default = "default_true_val")]
8756    pub near_duplicate: bool,
8757
8758    /// Near-duplicate date difference range in days.
8759    #[serde(default)]
8760    pub near_duplicate_days: NearDuplicateDaysConfig,
8761
8762    /// Enable threshold proximity pattern.
8763    #[serde(default = "default_true_val")]
8764    pub threshold_proximity: bool,
8765
8766    /// Threshold proximity range (e.g., 0.90-0.99 of threshold).
8767    #[serde(default)]
8768    pub threshold_proximity_range: ThresholdProximityRangeConfig,
8769
8770    /// Enable unusual but legitimate patterns.
8771    #[serde(default = "default_true_val")]
8772    pub unusual_legitimate: bool,
8773
8774    /// Types of unusual legitimate patterns to generate.
8775    #[serde(default = "default_unusual_legitimate_types")]
8776    pub unusual_legitimate_types: Vec<String>,
8777
8778    /// Enable corrected error patterns.
8779    #[serde(default = "default_true_val")]
8780    pub corrected_errors: bool,
8781
8782    /// Corrected error correction lag range in days.
8783    #[serde(default)]
8784    pub corrected_error_lag: CorrectedErrorLagConfig,
8785}
8786
8787fn default_near_miss_proportion() -> f64 {
8788    0.30
8789}
8790
8791fn default_unusual_legitimate_types() -> Vec<String> {
8792    vec![
8793        "year_end_bonus".to_string(),
8794        "contract_prepayment".to_string(),
8795        "insurance_claim".to_string(),
8796        "settlement_payment".to_string(),
8797    ]
8798}
8799
8800impl Default for NearMissConfig {
8801    fn default() -> Self {
8802        Self {
8803            enabled: false,
8804            proportion: default_near_miss_proportion(),
8805            near_duplicate: true,
8806            near_duplicate_days: NearDuplicateDaysConfig::default(),
8807            threshold_proximity: true,
8808            threshold_proximity_range: ThresholdProximityRangeConfig::default(),
8809            unusual_legitimate: true,
8810            unusual_legitimate_types: default_unusual_legitimate_types(),
8811            corrected_errors: true,
8812            corrected_error_lag: CorrectedErrorLagConfig::default(),
8813        }
8814    }
8815}
8816
8817/// Near-duplicate days configuration.
8818#[derive(Debug, Clone, Serialize, Deserialize)]
8819pub struct NearDuplicateDaysConfig {
8820    /// Minimum days apart.
8821    #[serde(default = "default_near_duplicate_min")]
8822    pub min: u32,
8823
8824    /// Maximum days apart.
8825    #[serde(default = "default_near_duplicate_max")]
8826    pub max: u32,
8827}
8828
8829fn default_near_duplicate_min() -> u32 {
8830    1
8831}
8832fn default_near_duplicate_max() -> u32 {
8833    3
8834}
8835
8836impl Default for NearDuplicateDaysConfig {
8837    fn default() -> Self {
8838        Self {
8839            min: default_near_duplicate_min(),
8840            max: default_near_duplicate_max(),
8841        }
8842    }
8843}
8844
8845/// Threshold proximity range configuration.
8846#[derive(Debug, Clone, Serialize, Deserialize)]
8847pub struct ThresholdProximityRangeConfig {
8848    /// Minimum proximity (e.g., 0.90 = 90% of threshold).
8849    #[serde(default = "default_threshold_proximity_min")]
8850    pub min: f64,
8851
8852    /// Maximum proximity (e.g., 0.99 = 99% of threshold).
8853    #[serde(default = "default_threshold_proximity_max")]
8854    pub max: f64,
8855}
8856
8857fn default_threshold_proximity_min() -> f64 {
8858    0.90
8859}
8860fn default_threshold_proximity_max() -> f64 {
8861    0.99
8862}
8863
8864impl Default for ThresholdProximityRangeConfig {
8865    fn default() -> Self {
8866        Self {
8867            min: default_threshold_proximity_min(),
8868            max: default_threshold_proximity_max(),
8869        }
8870    }
8871}
8872
8873/// Corrected error lag configuration.
8874#[derive(Debug, Clone, Serialize, Deserialize)]
8875pub struct CorrectedErrorLagConfig {
8876    /// Minimum correction lag in days.
8877    #[serde(default = "default_corrected_error_lag_min")]
8878    pub min: u32,
8879
8880    /// Maximum correction lag in days.
8881    #[serde(default = "default_corrected_error_lag_max")]
8882    pub max: u32,
8883}
8884
8885fn default_corrected_error_lag_min() -> u32 {
8886    1
8887}
8888fn default_corrected_error_lag_max() -> u32 {
8889    5
8890}
8891
8892impl Default for CorrectedErrorLagConfig {
8893    fn default() -> Self {
8894        Self {
8895            min: default_corrected_error_lag_min(),
8896            max: default_corrected_error_lag_max(),
8897        }
8898    }
8899}
8900
8901/// Detection difficulty classification configuration.
8902#[derive(Debug, Clone, Serialize, Deserialize)]
8903pub struct DifficultyClassificationConfig {
8904    /// Enable detection difficulty classification.
8905    #[serde(default)]
8906    pub enabled: bool,
8907
8908    /// Target distribution of difficulty levels.
8909    #[serde(default)]
8910    pub target_distribution: DifficultyDistributionConfig,
8911}
8912
8913impl Default for DifficultyClassificationConfig {
8914    fn default() -> Self {
8915        Self {
8916            enabled: true,
8917            target_distribution: DifficultyDistributionConfig::default(),
8918        }
8919    }
8920}
8921
8922/// Target distribution of detection difficulty levels.
8923#[derive(Debug, Clone, Serialize, Deserialize)]
8924pub struct DifficultyDistributionConfig {
8925    /// Proportion of trivial anomalies (expected 99% detection).
8926    #[serde(default = "default_difficulty_trivial")]
8927    pub trivial: f64,
8928
8929    /// Proportion of easy anomalies (expected 90% detection).
8930    #[serde(default = "default_difficulty_easy")]
8931    pub easy: f64,
8932
8933    /// Proportion of moderate anomalies (expected 70% detection).
8934    #[serde(default = "default_difficulty_moderate")]
8935    pub moderate: f64,
8936
8937    /// Proportion of hard anomalies (expected 40% detection).
8938    #[serde(default = "default_difficulty_hard")]
8939    pub hard: f64,
8940
8941    /// Proportion of expert anomalies (expected 15% detection).
8942    #[serde(default = "default_difficulty_expert")]
8943    pub expert: f64,
8944}
8945
8946fn default_difficulty_trivial() -> f64 {
8947    0.15
8948}
8949fn default_difficulty_easy() -> f64 {
8950    0.25
8951}
8952fn default_difficulty_moderate() -> f64 {
8953    0.30
8954}
8955fn default_difficulty_hard() -> f64 {
8956    0.20
8957}
8958fn default_difficulty_expert() -> f64 {
8959    0.10
8960}
8961
8962impl Default for DifficultyDistributionConfig {
8963    fn default() -> Self {
8964        Self {
8965            trivial: default_difficulty_trivial(),
8966            easy: default_difficulty_easy(),
8967            moderate: default_difficulty_moderate(),
8968            hard: default_difficulty_hard(),
8969            expert: default_difficulty_expert(),
8970        }
8971    }
8972}
8973
8974/// Context-aware injection configuration.
8975#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8976pub struct ContextAwareConfig {
8977    /// Enable context-aware injection.
8978    #[serde(default)]
8979    pub enabled: bool,
8980
8981    /// Vendor-specific anomaly rules.
8982    #[serde(default)]
8983    pub vendor_rules: VendorAnomalyRulesConfig,
8984
8985    /// Employee-specific anomaly rules.
8986    #[serde(default)]
8987    pub employee_rules: EmployeeAnomalyRulesConfig,
8988
8989    /// Account-specific anomaly rules.
8990    #[serde(default)]
8991    pub account_rules: AccountAnomalyRulesConfig,
8992
8993    /// Behavioral baseline configuration.
8994    #[serde(default)]
8995    pub behavioral_baseline: BehavioralBaselineConfig,
8996}
8997
8998/// Vendor-specific anomaly rules configuration.
8999#[derive(Debug, Clone, Serialize, Deserialize)]
9000pub struct VendorAnomalyRulesConfig {
9001    /// Error rate multiplier for new vendors (< threshold days).
9002    #[serde(default = "default_new_vendor_multiplier")]
9003    pub new_vendor_error_multiplier: f64,
9004
9005    /// Days threshold for "new" vendor classification.
9006    #[serde(default = "default_new_vendor_threshold")]
9007    pub new_vendor_threshold_days: u32,
9008
9009    /// Error rate multiplier for international vendors.
9010    #[serde(default = "default_international_multiplier")]
9011    pub international_error_multiplier: f64,
9012
9013    /// Strategic vendor anomaly types (may differ from general vendors).
9014    #[serde(default = "default_strategic_vendor_types")]
9015    pub strategic_vendor_anomaly_types: Vec<String>,
9016}
9017
9018fn default_new_vendor_multiplier() -> f64 {
9019    2.5
9020}
9021fn default_new_vendor_threshold() -> u32 {
9022    90
9023}
9024fn default_international_multiplier() -> f64 {
9025    1.5
9026}
9027fn default_strategic_vendor_types() -> Vec<String> {
9028    vec![
9029        "pricing_dispute".to_string(),
9030        "contract_violation".to_string(),
9031    ]
9032}
9033
9034impl Default for VendorAnomalyRulesConfig {
9035    fn default() -> Self {
9036        Self {
9037            new_vendor_error_multiplier: default_new_vendor_multiplier(),
9038            new_vendor_threshold_days: default_new_vendor_threshold(),
9039            international_error_multiplier: default_international_multiplier(),
9040            strategic_vendor_anomaly_types: default_strategic_vendor_types(),
9041        }
9042    }
9043}
9044
9045/// Employee-specific anomaly rules configuration.
9046#[derive(Debug, Clone, Serialize, Deserialize)]
9047pub struct EmployeeAnomalyRulesConfig {
9048    /// Error rate for new employees (< threshold days).
9049    #[serde(default = "default_new_employee_rate")]
9050    pub new_employee_error_rate: f64,
9051
9052    /// Days threshold for "new" employee classification.
9053    #[serde(default = "default_new_employee_threshold")]
9054    pub new_employee_threshold_days: u32,
9055
9056    /// Transaction volume threshold for fatigue errors.
9057    #[serde(default = "default_volume_fatigue_threshold")]
9058    pub volume_fatigue_threshold: u32,
9059
9060    /// Error rate multiplier when primary approver is absent.
9061    #[serde(default = "default_coverage_multiplier")]
9062    pub coverage_error_multiplier: f64,
9063}
9064
9065fn default_new_employee_rate() -> f64 {
9066    0.05
9067}
9068fn default_new_employee_threshold() -> u32 {
9069    180
9070}
9071fn default_volume_fatigue_threshold() -> u32 {
9072    50
9073}
9074fn default_coverage_multiplier() -> f64 {
9075    1.8
9076}
9077
9078impl Default for EmployeeAnomalyRulesConfig {
9079    fn default() -> Self {
9080        Self {
9081            new_employee_error_rate: default_new_employee_rate(),
9082            new_employee_threshold_days: default_new_employee_threshold(),
9083            volume_fatigue_threshold: default_volume_fatigue_threshold(),
9084            coverage_error_multiplier: default_coverage_multiplier(),
9085        }
9086    }
9087}
9088
9089/// Account-specific anomaly rules configuration.
9090#[derive(Debug, Clone, Serialize, Deserialize)]
9091pub struct AccountAnomalyRulesConfig {
9092    /// Error rate multiplier for high-risk accounts.
9093    #[serde(default = "default_high_risk_multiplier")]
9094    pub high_risk_account_multiplier: f64,
9095
9096    /// Account codes considered high-risk.
9097    #[serde(default = "default_high_risk_accounts")]
9098    pub high_risk_accounts: Vec<String>,
9099
9100    /// Error rate multiplier for suspense accounts.
9101    #[serde(default = "default_suspense_multiplier")]
9102    pub suspense_account_multiplier: f64,
9103
9104    /// Account codes considered suspense accounts.
9105    #[serde(default = "default_suspense_accounts")]
9106    pub suspense_accounts: Vec<String>,
9107
9108    /// Error rate multiplier for intercompany accounts.
9109    #[serde(default = "default_intercompany_multiplier")]
9110    pub intercompany_account_multiplier: f64,
9111}
9112
9113fn default_high_risk_multiplier() -> f64 {
9114    2.0
9115}
9116fn default_high_risk_accounts() -> Vec<String> {
9117    vec![
9118        "1100".to_string(), // AR Control
9119        "2000".to_string(), // AP Control
9120        "3000".to_string(), // Cash
9121    ]
9122}
9123fn default_suspense_multiplier() -> f64 {
9124    3.0
9125}
9126fn default_suspense_accounts() -> Vec<String> {
9127    vec!["9999".to_string(), "9998".to_string()]
9128}
9129fn default_intercompany_multiplier() -> f64 {
9130    1.5
9131}
9132
9133impl Default for AccountAnomalyRulesConfig {
9134    fn default() -> Self {
9135        Self {
9136            high_risk_account_multiplier: default_high_risk_multiplier(),
9137            high_risk_accounts: default_high_risk_accounts(),
9138            suspense_account_multiplier: default_suspense_multiplier(),
9139            suspense_accounts: default_suspense_accounts(),
9140            intercompany_account_multiplier: default_intercompany_multiplier(),
9141        }
9142    }
9143}
9144
9145/// Behavioral baseline configuration.
9146#[derive(Debug, Clone, Serialize, Deserialize)]
9147pub struct BehavioralBaselineConfig {
9148    /// Enable behavioral baseline tracking.
9149    #[serde(default)]
9150    pub enabled: bool,
9151
9152    /// Number of days to build baseline from.
9153    #[serde(default = "default_baseline_period")]
9154    pub baseline_period_days: u32,
9155
9156    /// Standard deviation threshold for amount anomalies.
9157    #[serde(default = "default_deviation_threshold")]
9158    pub deviation_threshold_std: f64,
9159
9160    /// Standard deviation threshold for frequency anomalies.
9161    #[serde(default = "default_frequency_deviation")]
9162    pub frequency_deviation_threshold: f64,
9163}
9164
9165fn default_baseline_period() -> u32 {
9166    90
9167}
9168fn default_deviation_threshold() -> f64 {
9169    3.0
9170}
9171fn default_frequency_deviation() -> f64 {
9172    2.0
9173}
9174
9175impl Default for BehavioralBaselineConfig {
9176    fn default() -> Self {
9177        Self {
9178            enabled: false,
9179            baseline_period_days: default_baseline_period(),
9180            deviation_threshold_std: default_deviation_threshold(),
9181            frequency_deviation_threshold: default_frequency_deviation(),
9182        }
9183    }
9184}
9185
9186/// Enhanced labeling configuration.
9187#[derive(Debug, Clone, Serialize, Deserialize)]
9188pub struct EnhancedLabelingConfig {
9189    /// Enable severity scoring.
9190    #[serde(default = "default_true_val")]
9191    pub severity_scoring: bool,
9192
9193    /// Enable difficulty classification.
9194    #[serde(default = "default_true_val")]
9195    pub difficulty_classification: bool,
9196
9197    /// Materiality thresholds for severity classification.
9198    #[serde(default)]
9199    pub materiality_thresholds: MaterialityThresholdsConfig,
9200}
9201
9202impl Default for EnhancedLabelingConfig {
9203    fn default() -> Self {
9204        Self {
9205            severity_scoring: true,
9206            difficulty_classification: true,
9207            materiality_thresholds: MaterialityThresholdsConfig::default(),
9208        }
9209    }
9210}
9211
9212/// Materiality thresholds configuration.
9213#[derive(Debug, Clone, Serialize, Deserialize)]
9214pub struct MaterialityThresholdsConfig {
9215    /// Threshold for trivial impact (as percentage of total).
9216    #[serde(default = "default_materiality_trivial")]
9217    pub trivial: f64,
9218
9219    /// Threshold for immaterial impact.
9220    #[serde(default = "default_materiality_immaterial")]
9221    pub immaterial: f64,
9222
9223    /// Threshold for material impact.
9224    #[serde(default = "default_materiality_material")]
9225    pub material: f64,
9226
9227    /// Threshold for highly material impact.
9228    #[serde(default = "default_materiality_highly_material")]
9229    pub highly_material: f64,
9230}
9231
9232fn default_materiality_trivial() -> f64 {
9233    0.001
9234}
9235fn default_materiality_immaterial() -> f64 {
9236    0.01
9237}
9238fn default_materiality_material() -> f64 {
9239    0.05
9240}
9241fn default_materiality_highly_material() -> f64 {
9242    0.10
9243}
9244
9245impl Default for MaterialityThresholdsConfig {
9246    fn default() -> Self {
9247        Self {
9248            trivial: default_materiality_trivial(),
9249            immaterial: default_materiality_immaterial(),
9250            material: default_materiality_material(),
9251            highly_material: default_materiality_highly_material(),
9252        }
9253    }
9254}
9255
9256// =============================================================================
9257// Industry-Specific Configuration
9258// =============================================================================
9259
9260/// Industry-specific transaction and anomaly generation configuration.
9261///
9262/// This configuration enables generation of industry-authentic:
9263/// - Transaction types with appropriate terminology
9264/// - Master data (BOM, routings, clinical codes, etc.)
9265/// - Industry-specific anomaly patterns
9266/// - Regulatory framework compliance
9267#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9268pub struct IndustrySpecificConfig {
9269    /// Enable industry-specific generation.
9270    #[serde(default)]
9271    pub enabled: bool,
9272
9273    /// Manufacturing industry settings.
9274    #[serde(default)]
9275    pub manufacturing: ManufacturingConfig,
9276
9277    /// Retail industry settings.
9278    #[serde(default)]
9279    pub retail: RetailConfig,
9280
9281    /// Healthcare industry settings.
9282    #[serde(default)]
9283    pub healthcare: HealthcareConfig,
9284
9285    /// Technology industry settings.
9286    #[serde(default)]
9287    pub technology: TechnologyConfig,
9288
9289    /// Financial services industry settings.
9290    #[serde(default)]
9291    pub financial_services: FinancialServicesConfig,
9292
9293    /// Professional services industry settings.
9294    #[serde(default)]
9295    pub professional_services: ProfessionalServicesConfig,
9296}
9297
9298/// Manufacturing industry configuration.
9299#[derive(Debug, Clone, Serialize, Deserialize)]
9300pub struct ManufacturingConfig {
9301    /// Enable manufacturing-specific generation.
9302    #[serde(default)]
9303    pub enabled: bool,
9304
9305    /// Bill of Materials depth (typical: 3-7).
9306    #[serde(default = "default_bom_depth")]
9307    pub bom_depth: u32,
9308
9309    /// Whether to use just-in-time inventory.
9310    #[serde(default)]
9311    pub just_in_time: bool,
9312
9313    /// Production order types to generate.
9314    #[serde(default = "default_production_order_types")]
9315    pub production_order_types: Vec<String>,
9316
9317    /// Quality framework (ISO_9001, Six_Sigma, etc.).
9318    #[serde(default)]
9319    pub quality_framework: Option<String>,
9320
9321    /// Number of supplier tiers to model (1-3).
9322    #[serde(default = "default_supplier_tiers")]
9323    pub supplier_tiers: u32,
9324
9325    /// Standard cost update frequency.
9326    #[serde(default = "default_cost_frequency")]
9327    pub standard_cost_frequency: String,
9328
9329    /// Target yield rate (0.95-0.99 typical).
9330    #[serde(default = "default_yield_rate")]
9331    pub target_yield_rate: f64,
9332
9333    /// Scrap percentage threshold for alerts.
9334    #[serde(default = "default_scrap_threshold")]
9335    pub scrap_alert_threshold: f64,
9336
9337    /// Manufacturing anomaly injection rates.
9338    #[serde(default)]
9339    pub anomaly_rates: ManufacturingAnomalyRates,
9340
9341    /// Cost accounting configuration (WIP → FG → COGS pipeline).
9342    #[serde(default)]
9343    pub cost_accounting: ManufacturingCostAccountingConfig,
9344}
9345
9346/// Configuration for manufacturing cost accounting JE generation.
9347#[derive(Debug, Clone, Serialize, Deserialize)]
9348pub struct ManufacturingCostAccountingConfig {
9349    /// Enable multi-stage cost flow (WIP → FG → COGS) instead of flat JEs.
9350    #[serde(default = "default_true")]
9351    pub enabled: bool,
9352
9353    /// Generate standard cost variance JEs.
9354    #[serde(default = "default_true")]
9355    pub variance_accounts_enabled: bool,
9356
9357    /// Generate warranty provisions from quality inspection failures.
9358    #[serde(default = "default_true")]
9359    pub warranty_provisions_enabled: bool,
9360
9361    /// Minimum defect rate (0.0-1.0) to trigger warranty provision generation.
9362    #[serde(default = "default_warranty_defect_threshold")]
9363    pub warranty_defect_threshold: f64,
9364}
9365
9366fn default_warranty_defect_threshold() -> f64 {
9367    0.01
9368}
9369
9370impl Default for ManufacturingCostAccountingConfig {
9371    fn default() -> Self {
9372        Self {
9373            enabled: true,
9374            variance_accounts_enabled: true,
9375            warranty_provisions_enabled: true,
9376            warranty_defect_threshold: 0.01,
9377        }
9378    }
9379}
9380
9381fn default_bom_depth() -> u32 {
9382    4
9383}
9384
9385fn default_production_order_types() -> Vec<String> {
9386    vec![
9387        "standard".to_string(),
9388        "rework".to_string(),
9389        "prototype".to_string(),
9390    ]
9391}
9392
9393fn default_supplier_tiers() -> u32 {
9394    2
9395}
9396
9397fn default_cost_frequency() -> String {
9398    "quarterly".to_string()
9399}
9400
9401fn default_yield_rate() -> f64 {
9402    0.97
9403}
9404
9405fn default_scrap_threshold() -> f64 {
9406    0.03
9407}
9408
9409impl Default for ManufacturingConfig {
9410    fn default() -> Self {
9411        Self {
9412            enabled: false,
9413            bom_depth: default_bom_depth(),
9414            just_in_time: false,
9415            production_order_types: default_production_order_types(),
9416            quality_framework: Some("ISO_9001".to_string()),
9417            supplier_tiers: default_supplier_tiers(),
9418            standard_cost_frequency: default_cost_frequency(),
9419            target_yield_rate: default_yield_rate(),
9420            scrap_alert_threshold: default_scrap_threshold(),
9421            anomaly_rates: ManufacturingAnomalyRates::default(),
9422            cost_accounting: ManufacturingCostAccountingConfig::default(),
9423        }
9424    }
9425}
9426
9427/// Manufacturing anomaly injection rates.
9428#[derive(Debug, Clone, Serialize, Deserialize)]
9429pub struct ManufacturingAnomalyRates {
9430    /// Yield manipulation rate.
9431    #[serde(default = "default_mfg_yield_rate")]
9432    pub yield_manipulation: f64,
9433
9434    /// Labor misallocation rate.
9435    #[serde(default = "default_mfg_labor_rate")]
9436    pub labor_misallocation: f64,
9437
9438    /// Phantom production rate.
9439    #[serde(default = "default_mfg_phantom_rate")]
9440    pub phantom_production: f64,
9441
9442    /// Standard cost manipulation rate.
9443    #[serde(default = "default_mfg_cost_rate")]
9444    pub standard_cost_manipulation: f64,
9445
9446    /// Inventory fraud rate.
9447    #[serde(default = "default_mfg_inventory_rate")]
9448    pub inventory_fraud: f64,
9449}
9450
9451fn default_mfg_yield_rate() -> f64 {
9452    0.015
9453}
9454
9455fn default_mfg_labor_rate() -> f64 {
9456    0.02
9457}
9458
9459fn default_mfg_phantom_rate() -> f64 {
9460    0.005
9461}
9462
9463fn default_mfg_cost_rate() -> f64 {
9464    0.01
9465}
9466
9467fn default_mfg_inventory_rate() -> f64 {
9468    0.008
9469}
9470
9471impl Default for ManufacturingAnomalyRates {
9472    fn default() -> Self {
9473        Self {
9474            yield_manipulation: default_mfg_yield_rate(),
9475            labor_misallocation: default_mfg_labor_rate(),
9476            phantom_production: default_mfg_phantom_rate(),
9477            standard_cost_manipulation: default_mfg_cost_rate(),
9478            inventory_fraud: default_mfg_inventory_rate(),
9479        }
9480    }
9481}
9482
9483/// Retail industry configuration.
9484#[derive(Debug, Clone, Serialize, Deserialize)]
9485pub struct RetailConfig {
9486    /// Enable retail-specific generation.
9487    #[serde(default)]
9488    pub enabled: bool,
9489
9490    /// Store type distribution.
9491    #[serde(default)]
9492    pub store_types: RetailStoreTypeConfig,
9493
9494    /// Average daily transactions per store.
9495    #[serde(default = "default_retail_daily_txns")]
9496    pub avg_daily_transactions: u32,
9497
9498    /// Enable loss prevention tracking.
9499    #[serde(default = "default_true")]
9500    pub loss_prevention: bool,
9501
9502    /// Shrinkage rate (0.01-0.03 typical).
9503    #[serde(default = "default_shrinkage_rate")]
9504    pub shrinkage_rate: f64,
9505
9506    /// Retail anomaly injection rates.
9507    #[serde(default)]
9508    pub anomaly_rates: RetailAnomalyRates,
9509}
9510
9511fn default_retail_daily_txns() -> u32 {
9512    500
9513}
9514
9515fn default_shrinkage_rate() -> f64 {
9516    0.015
9517}
9518
9519impl Default for RetailConfig {
9520    fn default() -> Self {
9521        Self {
9522            enabled: false,
9523            store_types: RetailStoreTypeConfig::default(),
9524            avg_daily_transactions: default_retail_daily_txns(),
9525            loss_prevention: true,
9526            shrinkage_rate: default_shrinkage_rate(),
9527            anomaly_rates: RetailAnomalyRates::default(),
9528        }
9529    }
9530}
9531
9532/// Retail store type distribution.
9533#[derive(Debug, Clone, Serialize, Deserialize)]
9534pub struct RetailStoreTypeConfig {
9535    /// Percentage of flagship stores.
9536    #[serde(default = "default_flagship_pct")]
9537    pub flagship: f64,
9538
9539    /// Percentage of regional stores.
9540    #[serde(default = "default_regional_pct")]
9541    pub regional: f64,
9542
9543    /// Percentage of outlet stores.
9544    #[serde(default = "default_outlet_pct")]
9545    pub outlet: f64,
9546
9547    /// Percentage of e-commerce.
9548    #[serde(default = "default_ecommerce_pct")]
9549    pub ecommerce: f64,
9550}
9551
9552fn default_flagship_pct() -> f64 {
9553    0.10
9554}
9555
9556fn default_regional_pct() -> f64 {
9557    0.50
9558}
9559
9560fn default_outlet_pct() -> f64 {
9561    0.25
9562}
9563
9564fn default_ecommerce_pct() -> f64 {
9565    0.15
9566}
9567
9568impl Default for RetailStoreTypeConfig {
9569    fn default() -> Self {
9570        Self {
9571            flagship: default_flagship_pct(),
9572            regional: default_regional_pct(),
9573            outlet: default_outlet_pct(),
9574            ecommerce: default_ecommerce_pct(),
9575        }
9576    }
9577}
9578
9579/// Retail anomaly injection rates.
9580#[derive(Debug, Clone, Serialize, Deserialize)]
9581pub struct RetailAnomalyRates {
9582    /// Sweethearting rate.
9583    #[serde(default = "default_sweethearting_rate")]
9584    pub sweethearting: f64,
9585
9586    /// Skimming rate.
9587    #[serde(default = "default_skimming_rate")]
9588    pub skimming: f64,
9589
9590    /// Refund fraud rate.
9591    #[serde(default = "default_refund_fraud_rate")]
9592    pub refund_fraud: f64,
9593
9594    /// Void abuse rate.
9595    #[serde(default = "default_void_abuse_rate")]
9596    pub void_abuse: f64,
9597
9598    /// Gift card fraud rate.
9599    #[serde(default = "default_gift_card_rate")]
9600    pub gift_card_fraud: f64,
9601
9602    /// Vendor kickback rate.
9603    #[serde(default = "default_retail_kickback_rate")]
9604    pub vendor_kickback: f64,
9605}
9606
9607fn default_sweethearting_rate() -> f64 {
9608    0.02
9609}
9610
9611fn default_skimming_rate() -> f64 {
9612    0.005
9613}
9614
9615fn default_refund_fraud_rate() -> f64 {
9616    0.015
9617}
9618
9619fn default_void_abuse_rate() -> f64 {
9620    0.01
9621}
9622
9623fn default_gift_card_rate() -> f64 {
9624    0.008
9625}
9626
9627fn default_retail_kickback_rate() -> f64 {
9628    0.003
9629}
9630
9631impl Default for RetailAnomalyRates {
9632    fn default() -> Self {
9633        Self {
9634            sweethearting: default_sweethearting_rate(),
9635            skimming: default_skimming_rate(),
9636            refund_fraud: default_refund_fraud_rate(),
9637            void_abuse: default_void_abuse_rate(),
9638            gift_card_fraud: default_gift_card_rate(),
9639            vendor_kickback: default_retail_kickback_rate(),
9640        }
9641    }
9642}
9643
9644/// Healthcare industry configuration.
9645#[derive(Debug, Clone, Serialize, Deserialize)]
9646pub struct HealthcareConfig {
9647    /// Enable healthcare-specific generation.
9648    #[serde(default)]
9649    pub enabled: bool,
9650
9651    /// Healthcare facility type.
9652    #[serde(default = "default_facility_type")]
9653    pub facility_type: String,
9654
9655    /// Payer mix distribution.
9656    #[serde(default)]
9657    pub payer_mix: HealthcarePayerMix,
9658
9659    /// Coding systems enabled.
9660    #[serde(default)]
9661    pub coding_systems: HealthcareCodingSystems,
9662
9663    /// Healthcare compliance settings.
9664    #[serde(default)]
9665    pub compliance: HealthcareComplianceConfig,
9666
9667    /// Average daily encounters.
9668    #[serde(default = "default_daily_encounters")]
9669    pub avg_daily_encounters: u32,
9670
9671    /// Average charges per encounter.
9672    #[serde(default = "default_charges_per_encounter")]
9673    pub avg_charges_per_encounter: u32,
9674
9675    /// Denial rate (0.0-1.0).
9676    #[serde(default = "default_hc_denial_rate")]
9677    pub denial_rate: f64,
9678
9679    /// Bad debt rate (0.0-1.0).
9680    #[serde(default = "default_hc_bad_debt_rate")]
9681    pub bad_debt_rate: f64,
9682
9683    /// Charity care rate (0.0-1.0).
9684    #[serde(default = "default_hc_charity_care_rate")]
9685    pub charity_care_rate: f64,
9686
9687    /// Healthcare anomaly injection rates.
9688    #[serde(default)]
9689    pub anomaly_rates: HealthcareAnomalyRates,
9690}
9691
9692fn default_facility_type() -> String {
9693    "hospital".to_string()
9694}
9695
9696fn default_daily_encounters() -> u32 {
9697    150
9698}
9699
9700fn default_charges_per_encounter() -> u32 {
9701    8
9702}
9703
9704fn default_hc_denial_rate() -> f64 {
9705    0.05
9706}
9707
9708fn default_hc_bad_debt_rate() -> f64 {
9709    0.03
9710}
9711
9712fn default_hc_charity_care_rate() -> f64 {
9713    0.02
9714}
9715
9716impl Default for HealthcareConfig {
9717    fn default() -> Self {
9718        Self {
9719            enabled: false,
9720            facility_type: default_facility_type(),
9721            payer_mix: HealthcarePayerMix::default(),
9722            coding_systems: HealthcareCodingSystems::default(),
9723            compliance: HealthcareComplianceConfig::default(),
9724            avg_daily_encounters: default_daily_encounters(),
9725            avg_charges_per_encounter: default_charges_per_encounter(),
9726            denial_rate: default_hc_denial_rate(),
9727            bad_debt_rate: default_hc_bad_debt_rate(),
9728            charity_care_rate: default_hc_charity_care_rate(),
9729            anomaly_rates: HealthcareAnomalyRates::default(),
9730        }
9731    }
9732}
9733
9734/// Healthcare payer mix distribution.
9735#[derive(Debug, Clone, Serialize, Deserialize)]
9736pub struct HealthcarePayerMix {
9737    /// Medicare percentage.
9738    #[serde(default = "default_medicare_pct")]
9739    pub medicare: f64,
9740
9741    /// Medicaid percentage.
9742    #[serde(default = "default_medicaid_pct")]
9743    pub medicaid: f64,
9744
9745    /// Commercial insurance percentage.
9746    #[serde(default = "default_commercial_pct")]
9747    pub commercial: f64,
9748
9749    /// Self-pay percentage.
9750    #[serde(default = "default_self_pay_pct")]
9751    pub self_pay: f64,
9752}
9753
9754fn default_medicare_pct() -> f64 {
9755    0.40
9756}
9757
9758fn default_medicaid_pct() -> f64 {
9759    0.20
9760}
9761
9762fn default_commercial_pct() -> f64 {
9763    0.30
9764}
9765
9766fn default_self_pay_pct() -> f64 {
9767    0.10
9768}
9769
9770impl Default for HealthcarePayerMix {
9771    fn default() -> Self {
9772        Self {
9773            medicare: default_medicare_pct(),
9774            medicaid: default_medicaid_pct(),
9775            commercial: default_commercial_pct(),
9776            self_pay: default_self_pay_pct(),
9777        }
9778    }
9779}
9780
9781/// Healthcare coding systems configuration.
9782#[derive(Debug, Clone, Serialize, Deserialize)]
9783pub struct HealthcareCodingSystems {
9784    /// Enable ICD-10 diagnosis coding.
9785    #[serde(default = "default_true")]
9786    pub icd10: bool,
9787
9788    /// Enable CPT procedure coding.
9789    #[serde(default = "default_true")]
9790    pub cpt: bool,
9791
9792    /// Enable DRG grouping.
9793    #[serde(default = "default_true")]
9794    pub drg: bool,
9795
9796    /// Enable HCPCS Level II coding.
9797    #[serde(default = "default_true")]
9798    pub hcpcs: bool,
9799
9800    /// Enable revenue codes.
9801    #[serde(default = "default_true")]
9802    pub revenue_codes: bool,
9803}
9804
9805impl Default for HealthcareCodingSystems {
9806    fn default() -> Self {
9807        Self {
9808            icd10: true,
9809            cpt: true,
9810            drg: true,
9811            hcpcs: true,
9812            revenue_codes: true,
9813        }
9814    }
9815}
9816
9817/// Healthcare compliance configuration.
9818#[derive(Debug, Clone, Serialize, Deserialize)]
9819pub struct HealthcareComplianceConfig {
9820    /// Enable HIPAA compliance.
9821    #[serde(default = "default_true")]
9822    pub hipaa: bool,
9823
9824    /// Enable Stark Law compliance.
9825    #[serde(default = "default_true")]
9826    pub stark_law: bool,
9827
9828    /// Enable Anti-Kickback Statute compliance.
9829    #[serde(default = "default_true")]
9830    pub anti_kickback: bool,
9831
9832    /// Enable False Claims Act compliance.
9833    #[serde(default = "default_true")]
9834    pub false_claims_act: bool,
9835
9836    /// Enable EMTALA compliance (for hospitals).
9837    #[serde(default = "default_true")]
9838    pub emtala: bool,
9839}
9840
9841impl Default for HealthcareComplianceConfig {
9842    fn default() -> Self {
9843        Self {
9844            hipaa: true,
9845            stark_law: true,
9846            anti_kickback: true,
9847            false_claims_act: true,
9848            emtala: true,
9849        }
9850    }
9851}
9852
9853/// Healthcare anomaly injection rates.
9854#[derive(Debug, Clone, Serialize, Deserialize)]
9855pub struct HealthcareAnomalyRates {
9856    /// Upcoding rate.
9857    #[serde(default = "default_upcoding_rate")]
9858    pub upcoding: f64,
9859
9860    /// Unbundling rate.
9861    #[serde(default = "default_unbundling_rate")]
9862    pub unbundling: f64,
9863
9864    /// Phantom billing rate.
9865    #[serde(default = "default_phantom_billing_rate")]
9866    pub phantom_billing: f64,
9867
9868    /// Kickback rate.
9869    #[serde(default = "default_healthcare_kickback_rate")]
9870    pub kickbacks: f64,
9871
9872    /// Duplicate billing rate.
9873    #[serde(default = "default_duplicate_billing_rate")]
9874    pub duplicate_billing: f64,
9875
9876    /// Medical necessity abuse rate.
9877    #[serde(default = "default_med_necessity_rate")]
9878    pub medical_necessity_abuse: f64,
9879}
9880
9881fn default_upcoding_rate() -> f64 {
9882    0.02
9883}
9884
9885fn default_unbundling_rate() -> f64 {
9886    0.015
9887}
9888
9889fn default_phantom_billing_rate() -> f64 {
9890    0.005
9891}
9892
9893fn default_healthcare_kickback_rate() -> f64 {
9894    0.003
9895}
9896
9897fn default_duplicate_billing_rate() -> f64 {
9898    0.008
9899}
9900
9901fn default_med_necessity_rate() -> f64 {
9902    0.01
9903}
9904
9905impl Default for HealthcareAnomalyRates {
9906    fn default() -> Self {
9907        Self {
9908            upcoding: default_upcoding_rate(),
9909            unbundling: default_unbundling_rate(),
9910            phantom_billing: default_phantom_billing_rate(),
9911            kickbacks: default_healthcare_kickback_rate(),
9912            duplicate_billing: default_duplicate_billing_rate(),
9913            medical_necessity_abuse: default_med_necessity_rate(),
9914        }
9915    }
9916}
9917
9918/// Technology industry configuration.
9919#[derive(Debug, Clone, Serialize, Deserialize)]
9920pub struct TechnologyConfig {
9921    /// Enable technology-specific generation.
9922    #[serde(default)]
9923    pub enabled: bool,
9924
9925    /// Revenue model type.
9926    #[serde(default = "default_revenue_model")]
9927    pub revenue_model: String,
9928
9929    /// Subscription revenue percentage (for SaaS).
9930    #[serde(default = "default_subscription_pct")]
9931    pub subscription_revenue_pct: f64,
9932
9933    /// License revenue percentage.
9934    #[serde(default = "default_license_pct")]
9935    pub license_revenue_pct: f64,
9936
9937    /// Services revenue percentage.
9938    #[serde(default = "default_services_pct")]
9939    pub services_revenue_pct: f64,
9940
9941    /// R&D capitalization settings.
9942    #[serde(default)]
9943    pub rd_capitalization: RdCapitalizationConfig,
9944
9945    /// Technology anomaly injection rates.
9946    #[serde(default)]
9947    pub anomaly_rates: TechnologyAnomalyRates,
9948}
9949
9950fn default_revenue_model() -> String {
9951    "saas".to_string()
9952}
9953
9954fn default_subscription_pct() -> f64 {
9955    0.60
9956}
9957
9958fn default_license_pct() -> f64 {
9959    0.25
9960}
9961
9962fn default_services_pct() -> f64 {
9963    0.15
9964}
9965
9966impl Default for TechnologyConfig {
9967    fn default() -> Self {
9968        Self {
9969            enabled: false,
9970            revenue_model: default_revenue_model(),
9971            subscription_revenue_pct: default_subscription_pct(),
9972            license_revenue_pct: default_license_pct(),
9973            services_revenue_pct: default_services_pct(),
9974            rd_capitalization: RdCapitalizationConfig::default(),
9975            anomaly_rates: TechnologyAnomalyRates::default(),
9976        }
9977    }
9978}
9979
9980/// R&D capitalization configuration.
9981#[derive(Debug, Clone, Serialize, Deserialize)]
9982pub struct RdCapitalizationConfig {
9983    /// Enable R&D capitalization.
9984    #[serde(default = "default_true")]
9985    pub enabled: bool,
9986
9987    /// Capitalization rate (0.0-1.0).
9988    #[serde(default = "default_cap_rate")]
9989    pub capitalization_rate: f64,
9990
9991    /// Useful life in years.
9992    #[serde(default = "default_useful_life")]
9993    pub useful_life_years: u32,
9994}
9995
9996fn default_cap_rate() -> f64 {
9997    0.30
9998}
9999
10000fn default_useful_life() -> u32 {
10001    3
10002}
10003
10004impl Default for RdCapitalizationConfig {
10005    fn default() -> Self {
10006        Self {
10007            enabled: true,
10008            capitalization_rate: default_cap_rate(),
10009            useful_life_years: default_useful_life(),
10010        }
10011    }
10012}
10013
10014/// Technology anomaly injection rates.
10015#[derive(Debug, Clone, Serialize, Deserialize)]
10016pub struct TechnologyAnomalyRates {
10017    /// Premature revenue recognition rate.
10018    #[serde(default = "default_premature_rev_rate")]
10019    pub premature_revenue: f64,
10020
10021    /// Side letter abuse rate.
10022    #[serde(default = "default_side_letter_rate")]
10023    pub side_letter_abuse: f64,
10024
10025    /// Channel stuffing rate.
10026    #[serde(default = "default_channel_stuffing_rate")]
10027    pub channel_stuffing: f64,
10028
10029    /// Improper capitalization rate.
10030    #[serde(default = "default_improper_cap_rate")]
10031    pub improper_capitalization: f64,
10032}
10033
10034fn default_premature_rev_rate() -> f64 {
10035    0.015
10036}
10037
10038fn default_side_letter_rate() -> f64 {
10039    0.008
10040}
10041
10042fn default_channel_stuffing_rate() -> f64 {
10043    0.01
10044}
10045
10046fn default_improper_cap_rate() -> f64 {
10047    0.012
10048}
10049
10050impl Default for TechnologyAnomalyRates {
10051    fn default() -> Self {
10052        Self {
10053            premature_revenue: default_premature_rev_rate(),
10054            side_letter_abuse: default_side_letter_rate(),
10055            channel_stuffing: default_channel_stuffing_rate(),
10056            improper_capitalization: default_improper_cap_rate(),
10057        }
10058    }
10059}
10060
10061/// Financial services industry configuration.
10062#[derive(Debug, Clone, Serialize, Deserialize)]
10063pub struct FinancialServicesConfig {
10064    /// Enable financial services-specific generation.
10065    #[serde(default)]
10066    pub enabled: bool,
10067
10068    /// Financial institution type.
10069    #[serde(default = "default_fi_type")]
10070    pub institution_type: String,
10071
10072    /// Regulatory framework.
10073    #[serde(default = "default_fi_regulatory")]
10074    pub regulatory_framework: String,
10075
10076    /// Financial services anomaly injection rates.
10077    #[serde(default)]
10078    pub anomaly_rates: FinancialServicesAnomalyRates,
10079}
10080
10081fn default_fi_type() -> String {
10082    "commercial_bank".to_string()
10083}
10084
10085fn default_fi_regulatory() -> String {
10086    "us_banking".to_string()
10087}
10088
10089impl Default for FinancialServicesConfig {
10090    fn default() -> Self {
10091        Self {
10092            enabled: false,
10093            institution_type: default_fi_type(),
10094            regulatory_framework: default_fi_regulatory(),
10095            anomaly_rates: FinancialServicesAnomalyRates::default(),
10096        }
10097    }
10098}
10099
10100/// Financial services anomaly injection rates.
10101#[derive(Debug, Clone, Serialize, Deserialize)]
10102pub struct FinancialServicesAnomalyRates {
10103    /// Loan fraud rate.
10104    #[serde(default = "default_loan_fraud_rate")]
10105    pub loan_fraud: f64,
10106
10107    /// Trading fraud rate.
10108    #[serde(default = "default_trading_fraud_rate")]
10109    pub trading_fraud: f64,
10110
10111    /// Insurance fraud rate.
10112    #[serde(default = "default_insurance_fraud_rate")]
10113    pub insurance_fraud: f64,
10114
10115    /// Account manipulation rate.
10116    #[serde(default = "default_account_manip_rate")]
10117    pub account_manipulation: f64,
10118}
10119
10120fn default_loan_fraud_rate() -> f64 {
10121    0.01
10122}
10123
10124fn default_trading_fraud_rate() -> f64 {
10125    0.008
10126}
10127
10128fn default_insurance_fraud_rate() -> f64 {
10129    0.012
10130}
10131
10132fn default_account_manip_rate() -> f64 {
10133    0.005
10134}
10135
10136impl Default for FinancialServicesAnomalyRates {
10137    fn default() -> Self {
10138        Self {
10139            loan_fraud: default_loan_fraud_rate(),
10140            trading_fraud: default_trading_fraud_rate(),
10141            insurance_fraud: default_insurance_fraud_rate(),
10142            account_manipulation: default_account_manip_rate(),
10143        }
10144    }
10145}
10146
10147/// Professional services industry configuration.
10148#[derive(Debug, Clone, Serialize, Deserialize)]
10149pub struct ProfessionalServicesConfig {
10150    /// Enable professional services-specific generation.
10151    #[serde(default)]
10152    pub enabled: bool,
10153
10154    /// Firm type.
10155    #[serde(default = "default_firm_type")]
10156    pub firm_type: String,
10157
10158    /// Billing model.
10159    #[serde(default = "default_billing_model")]
10160    pub billing_model: String,
10161
10162    /// Average hourly rate.
10163    #[serde(default = "default_hourly_rate")]
10164    pub avg_hourly_rate: f64,
10165
10166    /// Trust account settings (for law firms).
10167    #[serde(default)]
10168    pub trust_accounting: TrustAccountingConfig,
10169
10170    /// Professional services anomaly injection rates.
10171    #[serde(default)]
10172    pub anomaly_rates: ProfessionalServicesAnomalyRates,
10173}
10174
10175fn default_firm_type() -> String {
10176    "consulting".to_string()
10177}
10178
10179fn default_billing_model() -> String {
10180    "time_and_materials".to_string()
10181}
10182
10183fn default_hourly_rate() -> f64 {
10184    250.0
10185}
10186
10187impl Default for ProfessionalServicesConfig {
10188    fn default() -> Self {
10189        Self {
10190            enabled: false,
10191            firm_type: default_firm_type(),
10192            billing_model: default_billing_model(),
10193            avg_hourly_rate: default_hourly_rate(),
10194            trust_accounting: TrustAccountingConfig::default(),
10195            anomaly_rates: ProfessionalServicesAnomalyRates::default(),
10196        }
10197    }
10198}
10199
10200/// Trust accounting configuration for law firms.
10201#[derive(Debug, Clone, Serialize, Deserialize)]
10202pub struct TrustAccountingConfig {
10203    /// Enable trust accounting.
10204    #[serde(default)]
10205    pub enabled: bool,
10206
10207    /// Require three-way reconciliation.
10208    #[serde(default = "default_true")]
10209    pub require_three_way_reconciliation: bool,
10210}
10211
10212impl Default for TrustAccountingConfig {
10213    fn default() -> Self {
10214        Self {
10215            enabled: false,
10216            require_three_way_reconciliation: true,
10217        }
10218    }
10219}
10220
10221/// Professional services anomaly injection rates.
10222#[derive(Debug, Clone, Serialize, Deserialize)]
10223pub struct ProfessionalServicesAnomalyRates {
10224    /// Time billing fraud rate.
10225    #[serde(default = "default_time_fraud_rate")]
10226    pub time_billing_fraud: f64,
10227
10228    /// Expense report fraud rate.
10229    #[serde(default = "default_expense_fraud_rate")]
10230    pub expense_fraud: f64,
10231
10232    /// Trust misappropriation rate.
10233    #[serde(default = "default_trust_misappropriation_rate")]
10234    pub trust_misappropriation: f64,
10235}
10236
10237fn default_time_fraud_rate() -> f64 {
10238    0.02
10239}
10240
10241fn default_expense_fraud_rate() -> f64 {
10242    0.015
10243}
10244
10245fn default_trust_misappropriation_rate() -> f64 {
10246    0.003
10247}
10248
10249impl Default for ProfessionalServicesAnomalyRates {
10250    fn default() -> Self {
10251        Self {
10252            time_billing_fraud: default_time_fraud_rate(),
10253            expense_fraud: default_expense_fraud_rate(),
10254            trust_misappropriation: default_trust_misappropriation_rate(),
10255        }
10256    }
10257}
10258
10259/// Fingerprint privacy configuration for extraction and synthesis.
10260///
10261/// Controls the privacy parameters used when extracting fingerprints
10262/// from sensitive data. Supports predefined levels or custom (epsilon, delta) tuples.
10263///
10264/// ```yaml
10265/// fingerprint_privacy:
10266///   level: custom
10267///   epsilon: 0.5
10268///   delta: 1.0e-5
10269///   k_anonymity: 10
10270///   composition_method: renyi_dp
10271/// ```
10272#[derive(Debug, Clone, Serialize, Deserialize)]
10273pub struct FingerprintPrivacyConfig {
10274    /// Privacy level preset. Use "custom" for user-specified epsilon/delta.
10275    #[serde(default)]
10276    pub level: String,
10277    /// Custom epsilon value (only used when level = "custom").
10278    #[serde(default = "default_epsilon")]
10279    pub epsilon: f64,
10280    /// Custom delta value for (epsilon, delta)-DP (only used with RDP/zCDP).
10281    #[serde(default = "default_delta")]
10282    pub delta: f64,
10283    /// K-anonymity threshold.
10284    #[serde(default = "default_k_anonymity")]
10285    pub k_anonymity: u32,
10286    /// Composition method: "naive", "advanced", "renyi_dp", "zcdp".
10287    #[serde(default)]
10288    pub composition_method: String,
10289}
10290
10291fn default_epsilon() -> f64 {
10292    1.0
10293}
10294
10295fn default_delta() -> f64 {
10296    1e-5
10297}
10298
10299fn default_k_anonymity() -> u32 {
10300    5
10301}
10302
10303impl Default for FingerprintPrivacyConfig {
10304    fn default() -> Self {
10305        Self {
10306            level: "standard".to_string(),
10307            epsilon: default_epsilon(),
10308            delta: default_delta(),
10309            k_anonymity: default_k_anonymity(),
10310            composition_method: "naive".to_string(),
10311        }
10312    }
10313}
10314
10315/// Quality gates configuration for pass/fail thresholds on generation runs.
10316///
10317/// ```yaml
10318/// quality_gates:
10319///   enabled: true
10320///   profile: strict  # strict, default, lenient, custom
10321///   fail_on_violation: true
10322///   custom_gates:
10323///     - name: benford_compliance
10324///       metric: benford_mad
10325///       threshold: 0.015
10326///       comparison: lte
10327/// ```
10328#[derive(Debug, Clone, Serialize, Deserialize)]
10329pub struct QualityGatesSchemaConfig {
10330    /// Enable quality gate evaluation.
10331    #[serde(default)]
10332    pub enabled: bool,
10333    /// Gate profile: "strict", "default", "lenient", or "custom".
10334    #[serde(default = "default_gate_profile_name")]
10335    pub profile: String,
10336    /// Whether to fail the generation on gate violations.
10337    #[serde(default)]
10338    pub fail_on_violation: bool,
10339    /// Custom gate definitions (used when profile = "custom").
10340    #[serde(default)]
10341    pub custom_gates: Vec<QualityGateEntry>,
10342}
10343
10344fn default_gate_profile_name() -> String {
10345    "default".to_string()
10346}
10347
10348impl Default for QualityGatesSchemaConfig {
10349    fn default() -> Self {
10350        Self {
10351            enabled: false,
10352            profile: default_gate_profile_name(),
10353            fail_on_violation: false,
10354            custom_gates: Vec::new(),
10355        }
10356    }
10357}
10358
10359/// A single quality gate entry in configuration.
10360#[derive(Debug, Clone, Serialize, Deserialize)]
10361pub struct QualityGateEntry {
10362    /// Gate name.
10363    pub name: String,
10364    /// Metric to check: benford_mad, balance_coherence, document_chain_integrity,
10365    /// correlation_preservation, temporal_consistency, privacy_mia_auc,
10366    /// completion_rate, duplicate_rate, referential_integrity, ic_match_rate.
10367    pub metric: String,
10368    /// Threshold value.
10369    pub threshold: f64,
10370    /// Upper threshold for "between" comparison.
10371    #[serde(default)]
10372    pub upper_threshold: Option<f64>,
10373    /// Comparison operator: "gte", "lte", "eq", "between".
10374    #[serde(default = "default_gate_comparison")]
10375    pub comparison: String,
10376}
10377
10378fn default_gate_comparison() -> String {
10379    "gte".to_string()
10380}
10381
10382/// Compliance configuration for regulatory requirements.
10383///
10384/// ```yaml
10385/// compliance:
10386///   content_marking:
10387///     enabled: true
10388///     format: embedded  # embedded, sidecar, both
10389///   article10_report: true
10390/// ```
10391#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10392pub struct ComplianceSchemaConfig {
10393    /// Synthetic content marking configuration (EU AI Act Article 50).
10394    #[serde(default)]
10395    pub content_marking: ContentMarkingSchemaConfig,
10396    /// Generate Article 10 data governance report.
10397    #[serde(default)]
10398    pub article10_report: bool,
10399    /// Certificate configuration for proving DP guarantees.
10400    #[serde(default)]
10401    pub certificates: CertificateSchemaConfig,
10402}
10403
10404/// Configuration for synthetic data certificates.
10405#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10406pub struct CertificateSchemaConfig {
10407    /// Whether certificate generation is enabled.
10408    #[serde(default)]
10409    pub enabled: bool,
10410    /// Environment variable name for the signing key.
10411    #[serde(default)]
10412    pub signing_key_env: Option<String>,
10413    /// Whether to include quality metrics in the certificate.
10414    #[serde(default)]
10415    pub include_quality_metrics: bool,
10416}
10417
10418/// Content marking configuration for synthetic data output.
10419#[derive(Debug, Clone, Serialize, Deserialize)]
10420pub struct ContentMarkingSchemaConfig {
10421    /// Whether content marking is enabled.
10422    #[serde(default = "default_true")]
10423    pub enabled: bool,
10424    /// Marking format: "embedded", "sidecar", or "both".
10425    #[serde(default = "default_marking_format")]
10426    pub format: String,
10427}
10428
10429fn default_marking_format() -> String {
10430    "embedded".to_string()
10431}
10432
10433impl Default for ContentMarkingSchemaConfig {
10434    fn default() -> Self {
10435        Self {
10436            enabled: true,
10437            format: default_marking_format(),
10438        }
10439    }
10440}
10441
10442/// Webhook notification configuration.
10443#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10444pub struct WebhookSchemaConfig {
10445    /// Whether webhooks are enabled.
10446    #[serde(default)]
10447    pub enabled: bool,
10448    /// Webhook endpoint configurations.
10449    #[serde(default)]
10450    pub endpoints: Vec<WebhookEndpointConfig>,
10451}
10452
10453/// Configuration for a single webhook endpoint.
10454#[derive(Debug, Clone, Serialize, Deserialize)]
10455pub struct WebhookEndpointConfig {
10456    /// Target URL for the webhook.
10457    pub url: String,
10458    /// Event types this endpoint subscribes to.
10459    #[serde(default)]
10460    pub events: Vec<String>,
10461    /// Optional secret for HMAC-SHA256 signature.
10462    #[serde(default)]
10463    pub secret: Option<String>,
10464    /// Maximum retry attempts (default: 3).
10465    #[serde(default = "default_webhook_retries")]
10466    pub max_retries: u32,
10467    /// Timeout in seconds (default: 10).
10468    #[serde(default = "default_webhook_timeout")]
10469    pub timeout_secs: u64,
10470}
10471
10472fn default_webhook_retries() -> u32 {
10473    3
10474}
10475fn default_webhook_timeout() -> u64 {
10476    10
10477}
10478
10479// ===== Enterprise Process Chain Config Structs =====
10480
10481// ----- Source-to-Pay (S2C/S2P) -----
10482
10483/// Source-to-Pay configuration covering the entire sourcing lifecycle.
10484#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10485pub struct SourceToPayConfig {
10486    /// Enable source-to-pay generation
10487    #[serde(default)]
10488    pub enabled: bool,
10489    /// Spend analysis configuration
10490    #[serde(default)]
10491    pub spend_analysis: SpendAnalysisConfig,
10492    /// Sourcing project configuration
10493    #[serde(default)]
10494    pub sourcing: SourcingConfig,
10495    /// Supplier qualification configuration
10496    #[serde(default)]
10497    pub qualification: QualificationConfig,
10498    /// RFx event configuration
10499    #[serde(default)]
10500    pub rfx: RfxConfig,
10501    /// Contract configuration
10502    #[serde(default)]
10503    pub contracts: ContractConfig,
10504    /// Catalog configuration
10505    #[serde(default)]
10506    pub catalog: CatalogConfig,
10507    /// Scorecard configuration
10508    #[serde(default)]
10509    pub scorecards: ScorecardConfig,
10510    /// P2P integration settings
10511    #[serde(default)]
10512    pub p2p_integration: P2PIntegrationConfig,
10513}
10514
10515/// Spend analysis configuration.
10516#[derive(Debug, Clone, Serialize, Deserialize)]
10517pub struct SpendAnalysisConfig {
10518    /// HHI threshold for triggering sourcing project
10519    #[serde(default = "default_hhi_threshold")]
10520    pub hhi_threshold: f64,
10521    /// Target spend coverage under contracts
10522    #[serde(default = "default_contract_coverage_target")]
10523    pub contract_coverage_target: f64,
10524}
10525
10526impl Default for SpendAnalysisConfig {
10527    fn default() -> Self {
10528        Self {
10529            hhi_threshold: default_hhi_threshold(),
10530            contract_coverage_target: default_contract_coverage_target(),
10531        }
10532    }
10533}
10534
10535fn default_hhi_threshold() -> f64 {
10536    2500.0
10537}
10538fn default_contract_coverage_target() -> f64 {
10539    0.80
10540}
10541
10542/// Sourcing project configuration.
10543#[derive(Debug, Clone, Serialize, Deserialize)]
10544pub struct SourcingConfig {
10545    /// Number of sourcing projects per year
10546    #[serde(default = "default_sourcing_projects_per_year")]
10547    pub projects_per_year: u32,
10548    /// Months before expiry to trigger renewal project
10549    #[serde(default = "default_renewal_horizon_months")]
10550    pub renewal_horizon_months: u32,
10551    /// Average project duration in months
10552    #[serde(default = "default_project_duration_months")]
10553    pub project_duration_months: u32,
10554}
10555
10556impl Default for SourcingConfig {
10557    fn default() -> Self {
10558        Self {
10559            projects_per_year: default_sourcing_projects_per_year(),
10560            renewal_horizon_months: default_renewal_horizon_months(),
10561            project_duration_months: default_project_duration_months(),
10562        }
10563    }
10564}
10565
10566fn default_sourcing_projects_per_year() -> u32 {
10567    10
10568}
10569fn default_renewal_horizon_months() -> u32 {
10570    3
10571}
10572fn default_project_duration_months() -> u32 {
10573    4
10574}
10575
10576/// Supplier qualification configuration.
10577#[derive(Debug, Clone, Serialize, Deserialize)]
10578pub struct QualificationConfig {
10579    /// Pass rate for qualification
10580    #[serde(default = "default_qualification_pass_rate")]
10581    pub pass_rate: f64,
10582    /// Qualification validity in days
10583    #[serde(default = "default_qualification_validity_days")]
10584    pub validity_days: u32,
10585    /// Financial stability weight
10586    #[serde(default = "default_financial_weight")]
10587    pub financial_weight: f64,
10588    /// Quality management weight
10589    #[serde(default = "default_quality_weight")]
10590    pub quality_weight: f64,
10591    /// Delivery performance weight
10592    #[serde(default = "default_delivery_weight")]
10593    pub delivery_weight: f64,
10594    /// Compliance weight
10595    #[serde(default = "default_compliance_weight")]
10596    pub compliance_weight: f64,
10597}
10598
10599impl Default for QualificationConfig {
10600    fn default() -> Self {
10601        Self {
10602            pass_rate: default_qualification_pass_rate(),
10603            validity_days: default_qualification_validity_days(),
10604            financial_weight: default_financial_weight(),
10605            quality_weight: default_quality_weight(),
10606            delivery_weight: default_delivery_weight(),
10607            compliance_weight: default_compliance_weight(),
10608        }
10609    }
10610}
10611
10612fn default_qualification_pass_rate() -> f64 {
10613    0.75
10614}
10615fn default_qualification_validity_days() -> u32 {
10616    365
10617}
10618fn default_financial_weight() -> f64 {
10619    0.25
10620}
10621fn default_quality_weight() -> f64 {
10622    0.30
10623}
10624fn default_delivery_weight() -> f64 {
10625    0.25
10626}
10627fn default_compliance_weight() -> f64 {
10628    0.20
10629}
10630
10631/// RFx event configuration.
10632#[derive(Debug, Clone, Serialize, Deserialize)]
10633pub struct RfxConfig {
10634    /// Spend threshold above which RFI is required before RFP
10635    #[serde(default = "default_rfi_threshold")]
10636    pub rfi_threshold: f64,
10637    /// Minimum vendors invited per RFx
10638    #[serde(default = "default_min_invited_vendors")]
10639    pub min_invited_vendors: u32,
10640    /// Maximum vendors invited per RFx
10641    #[serde(default = "default_max_invited_vendors")]
10642    pub max_invited_vendors: u32,
10643    /// Response rate (% of invited vendors that submit bids)
10644    #[serde(default = "default_response_rate")]
10645    pub response_rate: f64,
10646    /// Default price weight in evaluation
10647    #[serde(default = "default_price_weight")]
10648    pub default_price_weight: f64,
10649    /// Default quality weight in evaluation
10650    #[serde(default = "default_rfx_quality_weight")]
10651    pub default_quality_weight: f64,
10652    /// Default delivery weight in evaluation
10653    #[serde(default = "default_rfx_delivery_weight")]
10654    pub default_delivery_weight: f64,
10655}
10656
10657impl Default for RfxConfig {
10658    fn default() -> Self {
10659        Self {
10660            rfi_threshold: default_rfi_threshold(),
10661            min_invited_vendors: default_min_invited_vendors(),
10662            max_invited_vendors: default_max_invited_vendors(),
10663            response_rate: default_response_rate(),
10664            default_price_weight: default_price_weight(),
10665            default_quality_weight: default_rfx_quality_weight(),
10666            default_delivery_weight: default_rfx_delivery_weight(),
10667        }
10668    }
10669}
10670
10671fn default_rfi_threshold() -> f64 {
10672    100_000.0
10673}
10674fn default_min_invited_vendors() -> u32 {
10675    3
10676}
10677fn default_max_invited_vendors() -> u32 {
10678    8
10679}
10680fn default_response_rate() -> f64 {
10681    0.70
10682}
10683fn default_price_weight() -> f64 {
10684    0.40
10685}
10686fn default_rfx_quality_weight() -> f64 {
10687    0.35
10688}
10689fn default_rfx_delivery_weight() -> f64 {
10690    0.25
10691}
10692
10693/// Contract configuration.
10694#[derive(Debug, Clone, Serialize, Deserialize)]
10695pub struct ContractConfig {
10696    /// Minimum contract duration in months
10697    #[serde(default = "default_min_contract_months")]
10698    pub min_duration_months: u32,
10699    /// Maximum contract duration in months
10700    #[serde(default = "default_max_contract_months")]
10701    pub max_duration_months: u32,
10702    /// Auto-renewal rate
10703    #[serde(default = "default_auto_renewal_rate")]
10704    pub auto_renewal_rate: f64,
10705    /// Amendment rate (% of contracts with at least one amendment)
10706    #[serde(default = "default_amendment_rate")]
10707    pub amendment_rate: f64,
10708    /// Distribution of contract types
10709    #[serde(default)]
10710    pub type_distribution: ContractTypeDistribution,
10711}
10712
10713impl Default for ContractConfig {
10714    fn default() -> Self {
10715        Self {
10716            min_duration_months: default_min_contract_months(),
10717            max_duration_months: default_max_contract_months(),
10718            auto_renewal_rate: default_auto_renewal_rate(),
10719            amendment_rate: default_amendment_rate(),
10720            type_distribution: ContractTypeDistribution::default(),
10721        }
10722    }
10723}
10724
10725fn default_min_contract_months() -> u32 {
10726    12
10727}
10728fn default_max_contract_months() -> u32 {
10729    36
10730}
10731fn default_auto_renewal_rate() -> f64 {
10732    0.40
10733}
10734fn default_amendment_rate() -> f64 {
10735    0.20
10736}
10737
10738/// Distribution of contract types.
10739#[derive(Debug, Clone, Serialize, Deserialize)]
10740pub struct ContractTypeDistribution {
10741    /// Fixed price percentage
10742    #[serde(default = "default_fixed_price_pct")]
10743    pub fixed_price: f64,
10744    /// Blanket/framework percentage
10745    #[serde(default = "default_blanket_pct")]
10746    pub blanket: f64,
10747    /// Time and materials percentage
10748    #[serde(default = "default_time_materials_pct")]
10749    pub time_and_materials: f64,
10750    /// Service agreement percentage
10751    #[serde(default = "default_service_agreement_pct")]
10752    pub service_agreement: f64,
10753}
10754
10755impl Default for ContractTypeDistribution {
10756    fn default() -> Self {
10757        Self {
10758            fixed_price: default_fixed_price_pct(),
10759            blanket: default_blanket_pct(),
10760            time_and_materials: default_time_materials_pct(),
10761            service_agreement: default_service_agreement_pct(),
10762        }
10763    }
10764}
10765
10766fn default_fixed_price_pct() -> f64 {
10767    0.40
10768}
10769fn default_blanket_pct() -> f64 {
10770    0.30
10771}
10772fn default_time_materials_pct() -> f64 {
10773    0.15
10774}
10775fn default_service_agreement_pct() -> f64 {
10776    0.15
10777}
10778
10779/// Catalog configuration.
10780#[derive(Debug, Clone, Serialize, Deserialize)]
10781pub struct CatalogConfig {
10782    /// Percentage of catalog items marked as preferred
10783    #[serde(default = "default_preferred_vendor_flag_rate")]
10784    pub preferred_vendor_flag_rate: f64,
10785    /// Rate of materials with multiple sources in catalog
10786    #[serde(default = "default_multi_source_rate")]
10787    pub multi_source_rate: f64,
10788}
10789
10790impl Default for CatalogConfig {
10791    fn default() -> Self {
10792        Self {
10793            preferred_vendor_flag_rate: default_preferred_vendor_flag_rate(),
10794            multi_source_rate: default_multi_source_rate(),
10795        }
10796    }
10797}
10798
10799fn default_preferred_vendor_flag_rate() -> f64 {
10800    0.70
10801}
10802fn default_multi_source_rate() -> f64 {
10803    0.25
10804}
10805
10806/// Scorecard configuration.
10807#[derive(Debug, Clone, Serialize, Deserialize)]
10808pub struct ScorecardConfig {
10809    /// Scorecard review frequency (quarterly, monthly)
10810    #[serde(default = "default_scorecard_frequency")]
10811    pub frequency: String,
10812    /// On-time delivery weight in overall score
10813    #[serde(default = "default_otd_weight")]
10814    pub on_time_delivery_weight: f64,
10815    /// Quality weight in overall score
10816    #[serde(default = "default_quality_score_weight")]
10817    pub quality_weight: f64,
10818    /// Price competitiveness weight
10819    #[serde(default = "default_price_score_weight")]
10820    pub price_weight: f64,
10821    /// Responsiveness weight
10822    #[serde(default = "default_responsiveness_weight")]
10823    pub responsiveness_weight: f64,
10824    /// Grade A threshold (score >= this)
10825    #[serde(default = "default_grade_a_threshold")]
10826    pub grade_a_threshold: f64,
10827    /// Grade B threshold
10828    #[serde(default = "default_grade_b_threshold")]
10829    pub grade_b_threshold: f64,
10830    /// Grade C threshold
10831    #[serde(default = "default_grade_c_threshold")]
10832    pub grade_c_threshold: f64,
10833}
10834
10835impl Default for ScorecardConfig {
10836    fn default() -> Self {
10837        Self {
10838            frequency: default_scorecard_frequency(),
10839            on_time_delivery_weight: default_otd_weight(),
10840            quality_weight: default_quality_score_weight(),
10841            price_weight: default_price_score_weight(),
10842            responsiveness_weight: default_responsiveness_weight(),
10843            grade_a_threshold: default_grade_a_threshold(),
10844            grade_b_threshold: default_grade_b_threshold(),
10845            grade_c_threshold: default_grade_c_threshold(),
10846        }
10847    }
10848}
10849
10850fn default_scorecard_frequency() -> String {
10851    "quarterly".to_string()
10852}
10853fn default_otd_weight() -> f64 {
10854    0.30
10855}
10856fn default_quality_score_weight() -> f64 {
10857    0.30
10858}
10859fn default_price_score_weight() -> f64 {
10860    0.25
10861}
10862fn default_responsiveness_weight() -> f64 {
10863    0.15
10864}
10865fn default_grade_a_threshold() -> f64 {
10866    90.0
10867}
10868fn default_grade_b_threshold() -> f64 {
10869    75.0
10870}
10871fn default_grade_c_threshold() -> f64 {
10872    60.0
10873}
10874
10875/// P2P integration settings for contract enforcement.
10876#[derive(Debug, Clone, Serialize, Deserialize)]
10877pub struct P2PIntegrationConfig {
10878    /// Rate of off-contract (maverick) purchases
10879    #[serde(default = "default_off_contract_rate")]
10880    pub off_contract_rate: f64,
10881    /// Price tolerance for contract price validation
10882    #[serde(default = "default_price_tolerance")]
10883    pub price_tolerance: f64,
10884    /// Whether to enforce catalog ordering
10885    #[serde(default)]
10886    pub catalog_enforcement: bool,
10887}
10888
10889impl Default for P2PIntegrationConfig {
10890    fn default() -> Self {
10891        Self {
10892            off_contract_rate: default_off_contract_rate(),
10893            price_tolerance: default_price_tolerance(),
10894            catalog_enforcement: false,
10895        }
10896    }
10897}
10898
10899fn default_off_contract_rate() -> f64 {
10900    0.15
10901}
10902fn default_price_tolerance() -> f64 {
10903    0.02
10904}
10905
10906// ----- Financial Reporting -----
10907
10908/// Financial reporting configuration.
10909#[derive(Debug, Clone, Serialize, Deserialize)]
10910pub struct FinancialReportingConfig {
10911    /// Enable financial reporting generation
10912    #[serde(default)]
10913    pub enabled: bool,
10914    /// Generate balance sheet
10915    #[serde(default = "default_true")]
10916    pub generate_balance_sheet: bool,
10917    /// Generate income statement
10918    #[serde(default = "default_true")]
10919    pub generate_income_statement: bool,
10920    /// Generate cash flow statement
10921    #[serde(default = "default_true")]
10922    pub generate_cash_flow: bool,
10923    /// Generate changes in equity statement
10924    #[serde(default = "default_true")]
10925    pub generate_changes_in_equity: bool,
10926    /// Number of comparative periods
10927    #[serde(default = "default_comparative_periods")]
10928    pub comparative_periods: u32,
10929    /// Management KPIs configuration
10930    #[serde(default)]
10931    pub management_kpis: ManagementKpisConfig,
10932    /// Budget configuration
10933    #[serde(default)]
10934    pub budgets: BudgetConfig,
10935}
10936
10937impl Default for FinancialReportingConfig {
10938    fn default() -> Self {
10939        Self {
10940            enabled: false,
10941            generate_balance_sheet: true,
10942            generate_income_statement: true,
10943            generate_cash_flow: true,
10944            generate_changes_in_equity: true,
10945            comparative_periods: default_comparative_periods(),
10946            management_kpis: ManagementKpisConfig::default(),
10947            budgets: BudgetConfig::default(),
10948        }
10949    }
10950}
10951
10952fn default_comparative_periods() -> u32 {
10953    1
10954}
10955
10956/// Management KPIs configuration.
10957#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10958pub struct ManagementKpisConfig {
10959    /// Enable KPI generation
10960    #[serde(default)]
10961    pub enabled: bool,
10962    /// KPI calculation frequency (monthly, quarterly)
10963    #[serde(default = "default_kpi_frequency")]
10964    pub frequency: String,
10965}
10966
10967fn default_kpi_frequency() -> String {
10968    "monthly".to_string()
10969}
10970
10971/// Budget configuration.
10972#[derive(Debug, Clone, Serialize, Deserialize)]
10973pub struct BudgetConfig {
10974    /// Enable budget generation
10975    #[serde(default)]
10976    pub enabled: bool,
10977    /// Expected revenue growth rate for budgeting
10978    #[serde(default = "default_revenue_growth_rate")]
10979    pub revenue_growth_rate: f64,
10980    /// Expected expense inflation rate
10981    #[serde(default = "default_expense_inflation_rate")]
10982    pub expense_inflation_rate: f64,
10983    /// Random noise to add to budget vs actual
10984    #[serde(default = "default_variance_noise")]
10985    pub variance_noise: f64,
10986}
10987
10988impl Default for BudgetConfig {
10989    fn default() -> Self {
10990        Self {
10991            enabled: false,
10992            revenue_growth_rate: default_revenue_growth_rate(),
10993            expense_inflation_rate: default_expense_inflation_rate(),
10994            variance_noise: default_variance_noise(),
10995        }
10996    }
10997}
10998
10999fn default_revenue_growth_rate() -> f64 {
11000    0.05
11001}
11002fn default_expense_inflation_rate() -> f64 {
11003    0.03
11004}
11005fn default_variance_noise() -> f64 {
11006    0.10
11007}
11008
11009// ----- HR Configuration -----
11010
11011/// HR (Hire-to-Retire) process configuration.
11012#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11013pub struct HrConfig {
11014    /// Enable HR generation
11015    #[serde(default)]
11016    pub enabled: bool,
11017    /// Payroll configuration
11018    #[serde(default)]
11019    pub payroll: PayrollConfig,
11020    /// Time and attendance configuration
11021    #[serde(default)]
11022    pub time_attendance: TimeAttendanceConfig,
11023    /// Expense management configuration
11024    #[serde(default)]
11025    pub expenses: ExpenseConfig,
11026}
11027
11028/// Payroll configuration.
11029#[derive(Debug, Clone, Serialize, Deserialize)]
11030pub struct PayrollConfig {
11031    /// Enable payroll generation
11032    #[serde(default = "default_true")]
11033    pub enabled: bool,
11034    /// Pay frequency (monthly, biweekly, weekly)
11035    #[serde(default = "default_pay_frequency")]
11036    pub pay_frequency: String,
11037    /// Salary ranges by job level
11038    #[serde(default)]
11039    pub salary_ranges: PayrollSalaryRanges,
11040    /// Effective tax rates
11041    #[serde(default)]
11042    pub tax_rates: PayrollTaxRates,
11043    /// Benefits enrollment rate
11044    #[serde(default = "default_benefits_enrollment_rate")]
11045    pub benefits_enrollment_rate: f64,
11046    /// Retirement plan participation rate
11047    #[serde(default = "default_retirement_participation_rate")]
11048    pub retirement_participation_rate: f64,
11049}
11050
11051impl Default for PayrollConfig {
11052    fn default() -> Self {
11053        Self {
11054            enabled: true,
11055            pay_frequency: default_pay_frequency(),
11056            salary_ranges: PayrollSalaryRanges::default(),
11057            tax_rates: PayrollTaxRates::default(),
11058            benefits_enrollment_rate: default_benefits_enrollment_rate(),
11059            retirement_participation_rate: default_retirement_participation_rate(),
11060        }
11061    }
11062}
11063
11064fn default_pay_frequency() -> String {
11065    "monthly".to_string()
11066}
11067fn default_benefits_enrollment_rate() -> f64 {
11068    0.60
11069}
11070fn default_retirement_participation_rate() -> f64 {
11071    0.45
11072}
11073
11074/// Salary ranges by job level.
11075#[derive(Debug, Clone, Serialize, Deserialize)]
11076pub struct PayrollSalaryRanges {
11077    /// Staff level min/max
11078    #[serde(default = "default_staff_min")]
11079    pub staff_min: f64,
11080    #[serde(default = "default_staff_max")]
11081    pub staff_max: f64,
11082    /// Manager level min/max
11083    #[serde(default = "default_manager_min")]
11084    pub manager_min: f64,
11085    #[serde(default = "default_manager_max")]
11086    pub manager_max: f64,
11087    /// Director level min/max
11088    #[serde(default = "default_director_min")]
11089    pub director_min: f64,
11090    #[serde(default = "default_director_max")]
11091    pub director_max: f64,
11092    /// Executive level min/max
11093    #[serde(default = "default_executive_min")]
11094    pub executive_min: f64,
11095    #[serde(default = "default_executive_max")]
11096    pub executive_max: f64,
11097}
11098
11099impl Default for PayrollSalaryRanges {
11100    fn default() -> Self {
11101        Self {
11102            staff_min: default_staff_min(),
11103            staff_max: default_staff_max(),
11104            manager_min: default_manager_min(),
11105            manager_max: default_manager_max(),
11106            director_min: default_director_min(),
11107            director_max: default_director_max(),
11108            executive_min: default_executive_min(),
11109            executive_max: default_executive_max(),
11110        }
11111    }
11112}
11113
11114fn default_staff_min() -> f64 {
11115    50_000.0
11116}
11117fn default_staff_max() -> f64 {
11118    70_000.0
11119}
11120fn default_manager_min() -> f64 {
11121    80_000.0
11122}
11123fn default_manager_max() -> f64 {
11124    120_000.0
11125}
11126fn default_director_min() -> f64 {
11127    120_000.0
11128}
11129fn default_director_max() -> f64 {
11130    180_000.0
11131}
11132fn default_executive_min() -> f64 {
11133    180_000.0
11134}
11135fn default_executive_max() -> f64 {
11136    350_000.0
11137}
11138
11139/// Effective tax rates for payroll.
11140#[derive(Debug, Clone, Serialize, Deserialize)]
11141pub struct PayrollTaxRates {
11142    /// Federal effective tax rate
11143    #[serde(default = "default_federal_rate")]
11144    pub federal_effective: f64,
11145    /// State effective tax rate
11146    #[serde(default = "default_state_rate")]
11147    pub state_effective: f64,
11148    /// FICA/social security rate
11149    #[serde(default = "default_fica_rate")]
11150    pub fica: f64,
11151}
11152
11153impl Default for PayrollTaxRates {
11154    fn default() -> Self {
11155        Self {
11156            federal_effective: default_federal_rate(),
11157            state_effective: default_state_rate(),
11158            fica: default_fica_rate(),
11159        }
11160    }
11161}
11162
11163fn default_federal_rate() -> f64 {
11164    0.22
11165}
11166fn default_state_rate() -> f64 {
11167    0.05
11168}
11169fn default_fica_rate() -> f64 {
11170    0.0765
11171}
11172
11173/// Time and attendance configuration.
11174#[derive(Debug, Clone, Serialize, Deserialize)]
11175pub struct TimeAttendanceConfig {
11176    /// Enable time tracking
11177    #[serde(default = "default_true")]
11178    pub enabled: bool,
11179    /// Overtime rate (% of employees with overtime in a period)
11180    #[serde(default = "default_overtime_rate")]
11181    pub overtime_rate: f64,
11182}
11183
11184impl Default for TimeAttendanceConfig {
11185    fn default() -> Self {
11186        Self {
11187            enabled: true,
11188            overtime_rate: default_overtime_rate(),
11189        }
11190    }
11191}
11192
11193fn default_overtime_rate() -> f64 {
11194    0.10
11195}
11196
11197/// Expense management configuration.
11198#[derive(Debug, Clone, Serialize, Deserialize)]
11199pub struct ExpenseConfig {
11200    /// Enable expense report generation
11201    #[serde(default = "default_true")]
11202    pub enabled: bool,
11203    /// Rate of employees submitting expenses per month
11204    #[serde(default = "default_expense_submission_rate")]
11205    pub submission_rate: f64,
11206    /// Rate of policy violations
11207    #[serde(default = "default_policy_violation_rate")]
11208    pub policy_violation_rate: f64,
11209}
11210
11211impl Default for ExpenseConfig {
11212    fn default() -> Self {
11213        Self {
11214            enabled: true,
11215            submission_rate: default_expense_submission_rate(),
11216            policy_violation_rate: default_policy_violation_rate(),
11217        }
11218    }
11219}
11220
11221fn default_expense_submission_rate() -> f64 {
11222    0.30
11223}
11224fn default_policy_violation_rate() -> f64 {
11225    0.08
11226}
11227
11228// ----- Manufacturing Configuration -----
11229
11230/// Manufacturing process configuration (production orders, WIP, routing).
11231#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11232pub struct ManufacturingProcessConfig {
11233    /// Enable manufacturing generation
11234    #[serde(default)]
11235    pub enabled: bool,
11236    /// Production order configuration
11237    #[serde(default)]
11238    pub production_orders: ProductionOrderConfig,
11239    /// Costing configuration
11240    #[serde(default)]
11241    pub costing: ManufacturingCostingConfig,
11242    /// Routing configuration
11243    #[serde(default)]
11244    pub routing: RoutingConfig,
11245}
11246
11247/// Production order configuration.
11248#[derive(Debug, Clone, Serialize, Deserialize)]
11249pub struct ProductionOrderConfig {
11250    /// Orders per month
11251    #[serde(default = "default_prod_orders_per_month")]
11252    pub orders_per_month: u32,
11253    /// Average batch size
11254    #[serde(default = "default_prod_avg_batch_size")]
11255    pub avg_batch_size: u32,
11256    /// Yield rate
11257    #[serde(default = "default_prod_yield_rate")]
11258    pub yield_rate: f64,
11259    /// Make-to-order rate (vs make-to-stock)
11260    #[serde(default = "default_prod_make_to_order_rate")]
11261    pub make_to_order_rate: f64,
11262    /// Rework rate
11263    #[serde(default = "default_prod_rework_rate")]
11264    pub rework_rate: f64,
11265}
11266
11267impl Default for ProductionOrderConfig {
11268    fn default() -> Self {
11269        Self {
11270            orders_per_month: default_prod_orders_per_month(),
11271            avg_batch_size: default_prod_avg_batch_size(),
11272            yield_rate: default_prod_yield_rate(),
11273            make_to_order_rate: default_prod_make_to_order_rate(),
11274            rework_rate: default_prod_rework_rate(),
11275        }
11276    }
11277}
11278
11279fn default_prod_orders_per_month() -> u32 {
11280    50
11281}
11282fn default_prod_avg_batch_size() -> u32 {
11283    100
11284}
11285fn default_prod_yield_rate() -> f64 {
11286    0.97
11287}
11288fn default_prod_make_to_order_rate() -> f64 {
11289    0.20
11290}
11291fn default_prod_rework_rate() -> f64 {
11292    0.03
11293}
11294
11295/// Manufacturing costing configuration.
11296#[derive(Debug, Clone, Serialize, Deserialize)]
11297pub struct ManufacturingCostingConfig {
11298    /// Labor rate per hour
11299    #[serde(default = "default_labor_rate")]
11300    pub labor_rate_per_hour: f64,
11301    /// Overhead application rate (multiplier on direct labor)
11302    #[serde(default = "default_overhead_rate")]
11303    pub overhead_rate: f64,
11304    /// Standard cost update frequency
11305    #[serde(default = "default_cost_update_frequency")]
11306    pub standard_cost_update_frequency: String,
11307}
11308
11309impl Default for ManufacturingCostingConfig {
11310    fn default() -> Self {
11311        Self {
11312            labor_rate_per_hour: default_labor_rate(),
11313            overhead_rate: default_overhead_rate(),
11314            standard_cost_update_frequency: default_cost_update_frequency(),
11315        }
11316    }
11317}
11318
11319fn default_labor_rate() -> f64 {
11320    35.0
11321}
11322fn default_overhead_rate() -> f64 {
11323    1.50
11324}
11325fn default_cost_update_frequency() -> String {
11326    "quarterly".to_string()
11327}
11328
11329/// Routing configuration for production operations.
11330#[derive(Debug, Clone, Serialize, Deserialize)]
11331pub struct RoutingConfig {
11332    /// Average number of operations per routing
11333    #[serde(default = "default_avg_operations")]
11334    pub avg_operations: u32,
11335    /// Average setup time in hours
11336    #[serde(default = "default_setup_time")]
11337    pub setup_time_hours: f64,
11338    /// Run time variation coefficient
11339    #[serde(default = "default_run_time_variation")]
11340    pub run_time_variation: f64,
11341}
11342
11343impl Default for RoutingConfig {
11344    fn default() -> Self {
11345        Self {
11346            avg_operations: default_avg_operations(),
11347            setup_time_hours: default_setup_time(),
11348            run_time_variation: default_run_time_variation(),
11349        }
11350    }
11351}
11352
11353fn default_avg_operations() -> u32 {
11354    4
11355}
11356fn default_setup_time() -> f64 {
11357    1.5
11358}
11359fn default_run_time_variation() -> f64 {
11360    0.15
11361}
11362
11363// ----- Sales Quote Configuration -----
11364
11365/// Sales quote (quote-to-order) pipeline configuration.
11366#[derive(Debug, Clone, Serialize, Deserialize)]
11367pub struct SalesQuoteConfig {
11368    /// Enable sales quote generation
11369    #[serde(default)]
11370    pub enabled: bool,
11371    /// Quotes per month
11372    #[serde(default = "default_quotes_per_month")]
11373    pub quotes_per_month: u32,
11374    /// Win rate (fraction of quotes that convert to orders)
11375    #[serde(default = "default_quote_win_rate")]
11376    pub win_rate: f64,
11377    /// Average quote validity in days
11378    #[serde(default = "default_quote_validity_days")]
11379    pub validity_days: u32,
11380}
11381
11382impl Default for SalesQuoteConfig {
11383    fn default() -> Self {
11384        Self {
11385            enabled: false,
11386            quotes_per_month: default_quotes_per_month(),
11387            win_rate: default_quote_win_rate(),
11388            validity_days: default_quote_validity_days(),
11389        }
11390    }
11391}
11392
11393fn default_quotes_per_month() -> u32 {
11394    30
11395}
11396fn default_quote_win_rate() -> f64 {
11397    0.35
11398}
11399fn default_quote_validity_days() -> u32 {
11400    30
11401}
11402
11403// =============================================================================
11404// Tax Accounting Configuration
11405// =============================================================================
11406
11407/// Tax accounting configuration.
11408///
11409/// Controls generation of tax-related data including VAT/GST, sales tax,
11410/// withholding tax, tax provisions, and payroll tax across multiple jurisdictions.
11411#[derive(Debug, Clone, Serialize, Deserialize)]
11412pub struct TaxConfig {
11413    /// Whether tax generation is enabled.
11414    #[serde(default)]
11415    pub enabled: bool,
11416    /// Tax jurisdiction configuration.
11417    #[serde(default)]
11418    pub jurisdictions: TaxJurisdictionConfig,
11419    /// VAT/GST configuration.
11420    #[serde(default)]
11421    pub vat_gst: VatGstConfig,
11422    /// Sales tax configuration.
11423    #[serde(default)]
11424    pub sales_tax: SalesTaxConfig,
11425    /// Withholding tax configuration.
11426    #[serde(default)]
11427    pub withholding: WithholdingTaxSchemaConfig,
11428    /// Tax provision configuration.
11429    #[serde(default)]
11430    pub provisions: TaxProvisionSchemaConfig,
11431    /// Payroll tax configuration.
11432    #[serde(default)]
11433    pub payroll_tax: PayrollTaxSchemaConfig,
11434    /// Anomaly injection rate for tax data (0.0 to 1.0).
11435    #[serde(default = "default_tax_anomaly_rate")]
11436    pub anomaly_rate: f64,
11437}
11438
11439fn default_tax_anomaly_rate() -> f64 {
11440    0.03
11441}
11442
11443impl Default for TaxConfig {
11444    fn default() -> Self {
11445        Self {
11446            enabled: false,
11447            jurisdictions: TaxJurisdictionConfig::default(),
11448            vat_gst: VatGstConfig::default(),
11449            sales_tax: SalesTaxConfig::default(),
11450            withholding: WithholdingTaxSchemaConfig::default(),
11451            provisions: TaxProvisionSchemaConfig::default(),
11452            payroll_tax: PayrollTaxSchemaConfig::default(),
11453            anomaly_rate: default_tax_anomaly_rate(),
11454        }
11455    }
11456}
11457
11458/// Tax jurisdiction configuration.
11459///
11460/// Specifies which countries and subnational jurisdictions to include
11461/// when generating tax data.
11462#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11463pub struct TaxJurisdictionConfig {
11464    /// List of country codes to include (e.g., ["US", "DE", "GB"]).
11465    #[serde(default)]
11466    pub countries: Vec<String>,
11467    /// Whether to include subnational jurisdictions (e.g., US states, Canadian provinces).
11468    #[serde(default)]
11469    pub include_subnational: bool,
11470}
11471
11472/// VAT/GST configuration.
11473///
11474/// Controls generation of Value Added Tax / Goods and Services Tax data,
11475/// including standard and reduced rates, exempt categories, and reverse charge.
11476#[derive(Debug, Clone, Serialize, Deserialize)]
11477pub struct VatGstConfig {
11478    /// Whether VAT/GST generation is enabled.
11479    #[serde(default)]
11480    pub enabled: bool,
11481    /// Standard VAT/GST rates by country code (e.g., {"DE": 0.19, "GB": 0.20}).
11482    #[serde(default)]
11483    pub standard_rates: std::collections::HashMap<String, f64>,
11484    /// Reduced VAT/GST rates by country code (e.g., {"DE": 0.07, "GB": 0.05}).
11485    #[serde(default)]
11486    pub reduced_rates: std::collections::HashMap<String, f64>,
11487    /// Categories exempt from VAT/GST (e.g., ["financial_services", "healthcare"]).
11488    #[serde(default)]
11489    pub exempt_categories: Vec<String>,
11490    /// Whether to apply reverse charge mechanism for cross-border B2B transactions.
11491    #[serde(default = "default_true")]
11492    pub reverse_charge: bool,
11493}
11494
11495impl Default for VatGstConfig {
11496    fn default() -> Self {
11497        Self {
11498            enabled: false,
11499            standard_rates: std::collections::HashMap::new(),
11500            reduced_rates: std::collections::HashMap::new(),
11501            exempt_categories: Vec::new(),
11502            reverse_charge: true,
11503        }
11504    }
11505}
11506
11507/// Sales tax configuration.
11508///
11509/// Controls generation of US-style sales tax data including nexus determination.
11510#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11511pub struct SalesTaxConfig {
11512    /// Whether sales tax generation is enabled.
11513    #[serde(default)]
11514    pub enabled: bool,
11515    /// US states where the company has nexus (e.g., ["CA", "NY", "TX"]).
11516    #[serde(default)]
11517    pub nexus_states: Vec<String>,
11518}
11519
11520/// Withholding tax configuration.
11521///
11522/// Controls generation of withholding tax data for cross-border payments,
11523/// including treaty network and rate overrides.
11524#[derive(Debug, Clone, Serialize, Deserialize)]
11525pub struct WithholdingTaxSchemaConfig {
11526    /// Whether withholding tax generation is enabled.
11527    #[serde(default)]
11528    pub enabled: bool,
11529    /// Whether to simulate a treaty network with reduced rates.
11530    #[serde(default = "default_true")]
11531    pub treaty_network: bool,
11532    /// Default withholding tax rate for non-treaty countries (0.0 to 1.0).
11533    #[serde(default = "default_withholding_rate")]
11534    pub default_rate: f64,
11535    /// Reduced withholding tax rate for treaty countries (0.0 to 1.0).
11536    #[serde(default = "default_treaty_reduced_rate")]
11537    pub treaty_reduced_rate: f64,
11538}
11539
11540fn default_withholding_rate() -> f64 {
11541    0.30
11542}
11543
11544fn default_treaty_reduced_rate() -> f64 {
11545    0.15
11546}
11547
11548impl Default for WithholdingTaxSchemaConfig {
11549    fn default() -> Self {
11550        Self {
11551            enabled: false,
11552            treaty_network: true,
11553            default_rate: default_withholding_rate(),
11554            treaty_reduced_rate: default_treaty_reduced_rate(),
11555        }
11556    }
11557}
11558
11559/// Tax provision configuration.
11560///
11561/// Controls generation of tax provision data including statutory rates
11562/// and uncertain tax positions (ASC 740 / IAS 12).
11563#[derive(Debug, Clone, Serialize, Deserialize)]
11564pub struct TaxProvisionSchemaConfig {
11565    /// Whether tax provision generation is enabled.
11566    /// Defaults to true when tax is enabled, as provisions are typically required.
11567    #[serde(default = "default_true")]
11568    pub enabled: bool,
11569    /// Statutory corporate tax rate (0.0 to 1.0).
11570    #[serde(default = "default_statutory_rate")]
11571    pub statutory_rate: f64,
11572    /// Whether to generate uncertain tax positions (FIN 48 / IFRIC 23).
11573    #[serde(default = "default_true")]
11574    pub uncertain_positions: bool,
11575}
11576
11577fn default_statutory_rate() -> f64 {
11578    0.21
11579}
11580
11581impl Default for TaxProvisionSchemaConfig {
11582    fn default() -> Self {
11583        Self {
11584            enabled: true,
11585            statutory_rate: default_statutory_rate(),
11586            uncertain_positions: true,
11587        }
11588    }
11589}
11590
11591/// Payroll tax configuration.
11592///
11593/// Controls generation of payroll tax data (employer/employee contributions,
11594/// social security, Medicare, etc.).
11595#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11596pub struct PayrollTaxSchemaConfig {
11597    /// Whether payroll tax generation is enabled.
11598    #[serde(default)]
11599    pub enabled: bool,
11600}
11601
11602// ---------------------------------------------------------------------------
11603// Treasury & Cash Management Configuration
11604// ---------------------------------------------------------------------------
11605
11606/// Treasury and cash management configuration.
11607///
11608/// Controls generation of cash positions, forecasts, pooling, hedging
11609/// instruments (ASC 815 / IFRS 9), debt instruments with covenants,
11610/// bank guarantees, and intercompany netting runs.
11611#[derive(Debug, Clone, Serialize, Deserialize)]
11612pub struct TreasuryConfig {
11613    /// Whether treasury generation is enabled.
11614    #[serde(default)]
11615    pub enabled: bool,
11616    /// Cash positioning configuration.
11617    #[serde(default)]
11618    pub cash_positioning: CashPositioningConfig,
11619    /// Cash forecasting configuration.
11620    #[serde(default)]
11621    pub cash_forecasting: CashForecastingConfig,
11622    /// Cash pooling configuration.
11623    #[serde(default)]
11624    pub cash_pooling: CashPoolingConfig,
11625    /// Hedging configuration (FX forwards, IR swaps, etc.).
11626    #[serde(default)]
11627    pub hedging: HedgingSchemaConfig,
11628    /// Debt instrument and covenant configuration.
11629    #[serde(default)]
11630    pub debt: DebtSchemaConfig,
11631    /// Intercompany netting configuration.
11632    #[serde(default)]
11633    pub netting: NettingSchemaConfig,
11634    /// Bank guarantee / letter of credit configuration.
11635    #[serde(default)]
11636    pub bank_guarantees: BankGuaranteeSchemaConfig,
11637    /// Anomaly injection rate for treasury data (0.0 to 1.0).
11638    #[serde(default = "default_treasury_anomaly_rate")]
11639    pub anomaly_rate: f64,
11640}
11641
11642fn default_treasury_anomaly_rate() -> f64 {
11643    0.02
11644}
11645
11646impl Default for TreasuryConfig {
11647    fn default() -> Self {
11648        Self {
11649            enabled: false,
11650            cash_positioning: CashPositioningConfig::default(),
11651            cash_forecasting: CashForecastingConfig::default(),
11652            cash_pooling: CashPoolingConfig::default(),
11653            hedging: HedgingSchemaConfig::default(),
11654            debt: DebtSchemaConfig::default(),
11655            netting: NettingSchemaConfig::default(),
11656            bank_guarantees: BankGuaranteeSchemaConfig::default(),
11657            anomaly_rate: default_treasury_anomaly_rate(),
11658        }
11659    }
11660}
11661
11662/// Cash positioning configuration.
11663///
11664/// Controls daily cash position generation per entity/bank account.
11665#[derive(Debug, Clone, Serialize, Deserialize)]
11666pub struct CashPositioningConfig {
11667    /// Whether cash positioning is enabled.
11668    #[serde(default = "default_true")]
11669    pub enabled: bool,
11670    /// Position generation frequency.
11671    #[serde(default = "default_cash_frequency")]
11672    pub frequency: String,
11673    /// Minimum cash balance policy threshold.
11674    #[serde(default = "default_minimum_balance_policy")]
11675    pub minimum_balance_policy: f64,
11676}
11677
11678fn default_cash_frequency() -> String {
11679    "daily".to_string()
11680}
11681
11682fn default_minimum_balance_policy() -> f64 {
11683    100_000.0
11684}
11685
11686impl Default for CashPositioningConfig {
11687    fn default() -> Self {
11688        Self {
11689            enabled: true,
11690            frequency: default_cash_frequency(),
11691            minimum_balance_policy: default_minimum_balance_policy(),
11692        }
11693    }
11694}
11695
11696/// Cash forecasting configuration.
11697///
11698/// Controls forward-looking cash forecast generation with probability-weighted items.
11699#[derive(Debug, Clone, Serialize, Deserialize)]
11700pub struct CashForecastingConfig {
11701    /// Whether cash forecasting is enabled.
11702    #[serde(default = "default_true")]
11703    pub enabled: bool,
11704    /// Number of days to forecast into the future.
11705    #[serde(default = "default_horizon_days")]
11706    pub horizon_days: u32,
11707    /// AR collection probability curve type ("aging" or "flat").
11708    #[serde(default = "default_ar_probability_curve")]
11709    pub ar_collection_probability_curve: String,
11710    /// Confidence interval for the forecast (0.0 to 1.0).
11711    #[serde(default = "default_confidence_interval")]
11712    pub confidence_interval: f64,
11713}
11714
11715fn default_horizon_days() -> u32 {
11716    90
11717}
11718
11719fn default_ar_probability_curve() -> String {
11720    "aging".to_string()
11721}
11722
11723fn default_confidence_interval() -> f64 {
11724    0.90
11725}
11726
11727impl Default for CashForecastingConfig {
11728    fn default() -> Self {
11729        Self {
11730            enabled: true,
11731            horizon_days: default_horizon_days(),
11732            ar_collection_probability_curve: default_ar_probability_curve(),
11733            confidence_interval: default_confidence_interval(),
11734        }
11735    }
11736}
11737
11738/// Cash pooling configuration.
11739///
11740/// Controls cash pool structure generation (physical, notional, zero-balancing).
11741#[derive(Debug, Clone, Serialize, Deserialize)]
11742pub struct CashPoolingConfig {
11743    /// Whether cash pooling is enabled.
11744    #[serde(default)]
11745    pub enabled: bool,
11746    /// Pool type: "physical_pooling", "notional_pooling", or "zero_balancing".
11747    #[serde(default = "default_pool_type")]
11748    pub pool_type: String,
11749    /// Time of day when sweeps occur (HH:MM format).
11750    #[serde(default = "default_sweep_time")]
11751    pub sweep_time: String,
11752}
11753
11754fn default_pool_type() -> String {
11755    "zero_balancing".to_string()
11756}
11757
11758fn default_sweep_time() -> String {
11759    "16:00".to_string()
11760}
11761
11762impl Default for CashPoolingConfig {
11763    fn default() -> Self {
11764        Self {
11765            enabled: false,
11766            pool_type: default_pool_type(),
11767            sweep_time: default_sweep_time(),
11768        }
11769    }
11770}
11771
11772/// Hedging configuration.
11773///
11774/// Controls generation of hedging instruments and hedge relationship designations
11775/// under ASC 815 / IFRS 9.
11776#[derive(Debug, Clone, Serialize, Deserialize)]
11777pub struct HedgingSchemaConfig {
11778    /// Whether hedging generation is enabled.
11779    #[serde(default)]
11780    pub enabled: bool,
11781    /// Target hedge ratio (0.0 to 1.0). Proportion of FX exposure to hedge.
11782    #[serde(default = "default_hedge_ratio")]
11783    pub hedge_ratio: f64,
11784    /// Types of instruments to generate (e.g., ["fx_forward", "interest_rate_swap"]).
11785    #[serde(default = "default_hedge_instruments")]
11786    pub instruments: Vec<String>,
11787    /// Whether to designate formal hedge accounting relationships.
11788    #[serde(default = "default_true")]
11789    pub hedge_accounting: bool,
11790    /// Effectiveness testing method: "dollar_offset", "regression", or "critical_terms".
11791    #[serde(default = "default_effectiveness_method")]
11792    pub effectiveness_method: String,
11793}
11794
11795fn default_hedge_ratio() -> f64 {
11796    0.75
11797}
11798
11799fn default_hedge_instruments() -> Vec<String> {
11800    vec!["fx_forward".to_string(), "interest_rate_swap".to_string()]
11801}
11802
11803fn default_effectiveness_method() -> String {
11804    "regression".to_string()
11805}
11806
11807impl Default for HedgingSchemaConfig {
11808    fn default() -> Self {
11809        Self {
11810            enabled: false,
11811            hedge_ratio: default_hedge_ratio(),
11812            instruments: default_hedge_instruments(),
11813            hedge_accounting: true,
11814            effectiveness_method: default_effectiveness_method(),
11815        }
11816    }
11817}
11818
11819/// Debt instrument configuration.
11820///
11821/// Controls generation of debt instruments (term loans, revolving credit, bonds)
11822/// with amortization schedules and financial covenants.
11823#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11824pub struct DebtSchemaConfig {
11825    /// Whether debt instrument generation is enabled.
11826    #[serde(default)]
11827    pub enabled: bool,
11828    /// Debt instrument definitions.
11829    #[serde(default)]
11830    pub instruments: Vec<DebtInstrumentDef>,
11831    /// Covenant definitions.
11832    #[serde(default)]
11833    pub covenants: Vec<CovenantDef>,
11834}
11835
11836/// Definition of a debt instrument in configuration.
11837#[derive(Debug, Clone, Serialize, Deserialize)]
11838pub struct DebtInstrumentDef {
11839    /// Instrument type: "term_loan", "revolving_credit", "bond", "commercial_paper", "bridge_loan".
11840    #[serde(rename = "type")]
11841    pub instrument_type: String,
11842    /// Principal amount (for term loans, bonds).
11843    #[serde(default)]
11844    pub principal: Option<f64>,
11845    /// Interest rate (annual, as decimal fraction).
11846    #[serde(default)]
11847    pub rate: Option<f64>,
11848    /// Maturity in months.
11849    #[serde(default)]
11850    pub maturity_months: Option<u32>,
11851    /// Facility limit (for revolving credit).
11852    #[serde(default)]
11853    pub facility: Option<f64>,
11854}
11855
11856/// Definition of a debt covenant in configuration.
11857#[derive(Debug, Clone, Serialize, Deserialize)]
11858pub struct CovenantDef {
11859    /// Covenant type: "debt_to_equity", "interest_coverage", "current_ratio",
11860    /// "net_worth", "debt_to_ebitda", "fixed_charge_coverage".
11861    #[serde(rename = "type")]
11862    pub covenant_type: String,
11863    /// Covenant threshold value.
11864    pub threshold: f64,
11865}
11866
11867/// Intercompany netting configuration.
11868///
11869/// Controls generation of multilateral netting runs.
11870#[derive(Debug, Clone, Serialize, Deserialize)]
11871pub struct NettingSchemaConfig {
11872    /// Whether netting generation is enabled.
11873    #[serde(default)]
11874    pub enabled: bool,
11875    /// Netting cycle: "daily", "weekly", or "monthly".
11876    #[serde(default = "default_netting_cycle")]
11877    pub cycle: String,
11878}
11879
11880fn default_netting_cycle() -> String {
11881    "monthly".to_string()
11882}
11883
11884impl Default for NettingSchemaConfig {
11885    fn default() -> Self {
11886        Self {
11887            enabled: false,
11888            cycle: default_netting_cycle(),
11889        }
11890    }
11891}
11892
11893/// Bank guarantee and letter of credit configuration.
11894///
11895/// Controls generation of bank guarantees, standby LCs, and performance bonds.
11896#[derive(Debug, Clone, Serialize, Deserialize)]
11897pub struct BankGuaranteeSchemaConfig {
11898    /// Whether bank guarantee generation is enabled.
11899    #[serde(default)]
11900    pub enabled: bool,
11901    /// Number of guarantees to generate.
11902    #[serde(default = "default_guarantee_count")]
11903    pub count: u32,
11904}
11905
11906fn default_guarantee_count() -> u32 {
11907    5
11908}
11909
11910impl Default for BankGuaranteeSchemaConfig {
11911    fn default() -> Self {
11912        Self {
11913            enabled: false,
11914            count: default_guarantee_count(),
11915        }
11916    }
11917}
11918
11919// ===========================================================================
11920// Project Accounting Configuration
11921// ===========================================================================
11922
11923/// Project accounting configuration.
11924///
11925/// Controls generation of project cost lines, revenue recognition,
11926/// milestones, change orders, retainage, and earned value metrics.
11927#[derive(Debug, Clone, Serialize, Deserialize)]
11928pub struct ProjectAccountingConfig {
11929    /// Whether project accounting is enabled.
11930    #[serde(default)]
11931    pub enabled: bool,
11932    /// Number of projects to generate.
11933    #[serde(default = "default_project_count")]
11934    pub project_count: u32,
11935    /// Distribution of project types (capital, internal, customer, r_and_d, maintenance, technology).
11936    #[serde(default)]
11937    pub project_types: ProjectTypeDistribution,
11938    /// WBS structure configuration.
11939    #[serde(default)]
11940    pub wbs: WbsSchemaConfig,
11941    /// Cost allocation rates (what % of source documents get project-tagged).
11942    #[serde(default)]
11943    pub cost_allocation: CostAllocationConfig,
11944    /// Revenue recognition configuration for project accounting.
11945    #[serde(default)]
11946    pub revenue_recognition: ProjectRevenueRecognitionConfig,
11947    /// Milestone configuration.
11948    #[serde(default)]
11949    pub milestones: MilestoneSchemaConfig,
11950    /// Change order configuration.
11951    #[serde(default)]
11952    pub change_orders: ChangeOrderSchemaConfig,
11953    /// Retainage configuration.
11954    #[serde(default)]
11955    pub retainage: RetainageSchemaConfig,
11956    /// Earned value management configuration.
11957    #[serde(default)]
11958    pub earned_value: EarnedValueSchemaConfig,
11959    /// Anomaly injection rate for project accounting data (0.0 to 1.0).
11960    #[serde(default = "default_project_anomaly_rate")]
11961    pub anomaly_rate: f64,
11962}
11963
11964fn default_project_count() -> u32 {
11965    10
11966}
11967
11968fn default_project_anomaly_rate() -> f64 {
11969    0.03
11970}
11971
11972impl Default for ProjectAccountingConfig {
11973    fn default() -> Self {
11974        Self {
11975            enabled: false,
11976            project_count: default_project_count(),
11977            project_types: ProjectTypeDistribution::default(),
11978            wbs: WbsSchemaConfig::default(),
11979            cost_allocation: CostAllocationConfig::default(),
11980            revenue_recognition: ProjectRevenueRecognitionConfig::default(),
11981            milestones: MilestoneSchemaConfig::default(),
11982            change_orders: ChangeOrderSchemaConfig::default(),
11983            retainage: RetainageSchemaConfig::default(),
11984            earned_value: EarnedValueSchemaConfig::default(),
11985            anomaly_rate: default_project_anomaly_rate(),
11986        }
11987    }
11988}
11989
11990/// Distribution of project types by weight.
11991#[derive(Debug, Clone, Serialize, Deserialize)]
11992pub struct ProjectTypeDistribution {
11993    /// Weight for capital projects (default 0.25).
11994    #[serde(default = "default_capital_weight")]
11995    pub capital: f64,
11996    /// Weight for internal projects (default 0.20).
11997    #[serde(default = "default_internal_weight")]
11998    pub internal: f64,
11999    /// Weight for customer projects (default 0.30).
12000    #[serde(default = "default_customer_weight")]
12001    pub customer: f64,
12002    /// Weight for R&D projects (default 0.10).
12003    #[serde(default = "default_rnd_weight")]
12004    pub r_and_d: f64,
12005    /// Weight for maintenance projects (default 0.10).
12006    #[serde(default = "default_maintenance_weight")]
12007    pub maintenance: f64,
12008    /// Weight for technology projects (default 0.05).
12009    #[serde(default = "default_technology_weight")]
12010    pub technology: f64,
12011}
12012
12013fn default_capital_weight() -> f64 {
12014    0.25
12015}
12016fn default_internal_weight() -> f64 {
12017    0.20
12018}
12019fn default_customer_weight() -> f64 {
12020    0.30
12021}
12022fn default_rnd_weight() -> f64 {
12023    0.10
12024}
12025fn default_maintenance_weight() -> f64 {
12026    0.10
12027}
12028fn default_technology_weight() -> f64 {
12029    0.05
12030}
12031
12032impl Default for ProjectTypeDistribution {
12033    fn default() -> Self {
12034        Self {
12035            capital: default_capital_weight(),
12036            internal: default_internal_weight(),
12037            customer: default_customer_weight(),
12038            r_and_d: default_rnd_weight(),
12039            maintenance: default_maintenance_weight(),
12040            technology: default_technology_weight(),
12041        }
12042    }
12043}
12044
12045/// WBS structure configuration.
12046#[derive(Debug, Clone, Serialize, Deserialize)]
12047pub struct WbsSchemaConfig {
12048    /// Maximum depth of WBS hierarchy (default 3).
12049    #[serde(default = "default_wbs_max_depth")]
12050    pub max_depth: u32,
12051    /// Minimum elements per level-1 WBS (default 2).
12052    #[serde(default = "default_wbs_min_elements")]
12053    pub min_elements_per_level: u32,
12054    /// Maximum elements per level-1 WBS (default 6).
12055    #[serde(default = "default_wbs_max_elements")]
12056    pub max_elements_per_level: u32,
12057}
12058
12059fn default_wbs_max_depth() -> u32 {
12060    3
12061}
12062fn default_wbs_min_elements() -> u32 {
12063    2
12064}
12065fn default_wbs_max_elements() -> u32 {
12066    6
12067}
12068
12069impl Default for WbsSchemaConfig {
12070    fn default() -> Self {
12071        Self {
12072            max_depth: default_wbs_max_depth(),
12073            min_elements_per_level: default_wbs_min_elements(),
12074            max_elements_per_level: default_wbs_max_elements(),
12075        }
12076    }
12077}
12078
12079/// Cost allocation rates — what fraction of each document type gets linked to a project.
12080#[derive(Debug, Clone, Serialize, Deserialize)]
12081pub struct CostAllocationConfig {
12082    /// Fraction of time entries assigned to projects (0.0 to 1.0).
12083    #[serde(default = "default_time_entry_rate")]
12084    pub time_entry_project_rate: f64,
12085    /// Fraction of expense reports assigned to projects (0.0 to 1.0).
12086    #[serde(default = "default_expense_rate")]
12087    pub expense_project_rate: f64,
12088    /// Fraction of purchase orders assigned to projects (0.0 to 1.0).
12089    #[serde(default = "default_po_rate")]
12090    pub purchase_order_project_rate: f64,
12091    /// Fraction of vendor invoices assigned to projects (0.0 to 1.0).
12092    #[serde(default = "default_vi_rate")]
12093    pub vendor_invoice_project_rate: f64,
12094}
12095
12096fn default_time_entry_rate() -> f64 {
12097    0.60
12098}
12099fn default_expense_rate() -> f64 {
12100    0.30
12101}
12102fn default_po_rate() -> f64 {
12103    0.40
12104}
12105fn default_vi_rate() -> f64 {
12106    0.35
12107}
12108
12109impl Default for CostAllocationConfig {
12110    fn default() -> Self {
12111        Self {
12112            time_entry_project_rate: default_time_entry_rate(),
12113            expense_project_rate: default_expense_rate(),
12114            purchase_order_project_rate: default_po_rate(),
12115            vendor_invoice_project_rate: default_vi_rate(),
12116        }
12117    }
12118}
12119
12120/// Revenue recognition configuration for project accounting.
12121#[derive(Debug, Clone, Serialize, Deserialize)]
12122pub struct ProjectRevenueRecognitionConfig {
12123    /// Whether revenue recognition is enabled for customer projects.
12124    #[serde(default = "default_true")]
12125    pub enabled: bool,
12126    /// Default method: "percentage_of_completion", "completed_contract", "milestone_based".
12127    #[serde(default = "default_revenue_method")]
12128    pub method: String,
12129    /// Default completion measure: "cost_to_cost", "labor_hours", "physical_completion".
12130    #[serde(default = "default_completion_measure")]
12131    pub completion_measure: String,
12132    /// Average contract value for customer projects.
12133    #[serde(default = "default_avg_contract_value")]
12134    pub avg_contract_value: f64,
12135}
12136
12137fn default_revenue_method() -> String {
12138    "percentage_of_completion".to_string()
12139}
12140fn default_completion_measure() -> String {
12141    "cost_to_cost".to_string()
12142}
12143fn default_avg_contract_value() -> f64 {
12144    500_000.0
12145}
12146
12147impl Default for ProjectRevenueRecognitionConfig {
12148    fn default() -> Self {
12149        Self {
12150            enabled: true,
12151            method: default_revenue_method(),
12152            completion_measure: default_completion_measure(),
12153            avg_contract_value: default_avg_contract_value(),
12154        }
12155    }
12156}
12157
12158/// Milestone configuration.
12159#[derive(Debug, Clone, Serialize, Deserialize)]
12160pub struct MilestoneSchemaConfig {
12161    /// Whether milestone generation is enabled.
12162    #[serde(default = "default_true")]
12163    pub enabled: bool,
12164    /// Average number of milestones per project.
12165    #[serde(default = "default_milestones_per_project")]
12166    pub avg_per_project: u32,
12167    /// Fraction of milestones that are payment milestones (0.0 to 1.0).
12168    #[serde(default = "default_payment_milestone_rate")]
12169    pub payment_milestone_rate: f64,
12170}
12171
12172fn default_milestones_per_project() -> u32 {
12173    4
12174}
12175fn default_payment_milestone_rate() -> f64 {
12176    0.50
12177}
12178
12179impl Default for MilestoneSchemaConfig {
12180    fn default() -> Self {
12181        Self {
12182            enabled: true,
12183            avg_per_project: default_milestones_per_project(),
12184            payment_milestone_rate: default_payment_milestone_rate(),
12185        }
12186    }
12187}
12188
12189/// Change order configuration.
12190#[derive(Debug, Clone, Serialize, Deserialize)]
12191pub struct ChangeOrderSchemaConfig {
12192    /// Whether change order generation is enabled.
12193    #[serde(default = "default_true")]
12194    pub enabled: bool,
12195    /// Probability that a project will have at least one change order (0.0 to 1.0).
12196    #[serde(default = "default_change_order_probability")]
12197    pub probability: f64,
12198    /// Maximum change orders per project.
12199    #[serde(default = "default_max_change_orders")]
12200    pub max_per_project: u32,
12201    /// Approval rate for change orders (0.0 to 1.0).
12202    #[serde(default = "default_change_order_approval_rate")]
12203    pub approval_rate: f64,
12204}
12205
12206fn default_change_order_probability() -> f64 {
12207    0.40
12208}
12209fn default_max_change_orders() -> u32 {
12210    3
12211}
12212fn default_change_order_approval_rate() -> f64 {
12213    0.75
12214}
12215
12216impl Default for ChangeOrderSchemaConfig {
12217    fn default() -> Self {
12218        Self {
12219            enabled: true,
12220            probability: default_change_order_probability(),
12221            max_per_project: default_max_change_orders(),
12222            approval_rate: default_change_order_approval_rate(),
12223        }
12224    }
12225}
12226
12227/// Retainage configuration.
12228#[derive(Debug, Clone, Serialize, Deserialize)]
12229pub struct RetainageSchemaConfig {
12230    /// Whether retainage is enabled.
12231    #[serde(default)]
12232    pub enabled: bool,
12233    /// Default retainage percentage (0.0 to 1.0, e.g., 0.10 for 10%).
12234    #[serde(default = "default_retainage_pct")]
12235    pub default_percentage: f64,
12236}
12237
12238fn default_retainage_pct() -> f64 {
12239    0.10
12240}
12241
12242impl Default for RetainageSchemaConfig {
12243    fn default() -> Self {
12244        Self {
12245            enabled: false,
12246            default_percentage: default_retainage_pct(),
12247        }
12248    }
12249}
12250
12251/// Earned value management (EVM) configuration.
12252#[derive(Debug, Clone, Serialize, Deserialize)]
12253pub struct EarnedValueSchemaConfig {
12254    /// Whether EVM metrics are generated.
12255    #[serde(default = "default_true")]
12256    pub enabled: bool,
12257    /// Measurement frequency: "weekly", "biweekly", "monthly".
12258    #[serde(default = "default_evm_frequency")]
12259    pub frequency: String,
12260}
12261
12262fn default_evm_frequency() -> String {
12263    "monthly".to_string()
12264}
12265
12266impl Default for EarnedValueSchemaConfig {
12267    fn default() -> Self {
12268        Self {
12269            enabled: true,
12270            frequency: default_evm_frequency(),
12271        }
12272    }
12273}
12274
12275// =============================================================================
12276// ESG / Sustainability Configuration
12277// =============================================================================
12278
12279/// Top-level ESG / sustainability reporting configuration.
12280#[derive(Debug, Clone, Serialize, Deserialize)]
12281pub struct EsgConfig {
12282    /// Whether ESG generation is enabled.
12283    #[serde(default)]
12284    pub enabled: bool,
12285    /// Environmental metrics (emissions, energy, water, waste).
12286    #[serde(default)]
12287    pub environmental: EnvironmentalConfig,
12288    /// Social metrics (diversity, pay equity, safety).
12289    #[serde(default)]
12290    pub social: SocialConfig,
12291    /// Governance metrics (board composition, ethics, compliance).
12292    #[serde(default)]
12293    pub governance: GovernanceSchemaConfig,
12294    /// Supply-chain ESG assessment settings.
12295    #[serde(default)]
12296    pub supply_chain_esg: SupplyChainEsgConfig,
12297    /// ESG reporting / disclosure framework settings.
12298    #[serde(default)]
12299    pub reporting: EsgReportingConfig,
12300    /// Climate scenario analysis settings.
12301    #[serde(default)]
12302    pub climate_scenarios: ClimateScenarioConfig,
12303    /// Anomaly injection rate for ESG data (0.0 to 1.0).
12304    #[serde(default = "default_esg_anomaly_rate")]
12305    pub anomaly_rate: f64,
12306}
12307
12308fn default_esg_anomaly_rate() -> f64 {
12309    0.02
12310}
12311
12312impl Default for EsgConfig {
12313    fn default() -> Self {
12314        Self {
12315            enabled: false,
12316            environmental: EnvironmentalConfig::default(),
12317            social: SocialConfig::default(),
12318            governance: GovernanceSchemaConfig::default(),
12319            supply_chain_esg: SupplyChainEsgConfig::default(),
12320            reporting: EsgReportingConfig::default(),
12321            climate_scenarios: ClimateScenarioConfig::default(),
12322            anomaly_rate: default_esg_anomaly_rate(),
12323        }
12324    }
12325}
12326
12327/// Country pack configuration.
12328///
12329/// Controls where to load additional country packs and per-country overrides.
12330/// When omitted, only the built-in packs (_default, US, DE, GB) are used.
12331#[derive(Debug, Clone, Serialize, Deserialize, Default)]
12332pub struct CountryPacksSchemaConfig {
12333    /// Optional directory containing additional `*.json` country packs.
12334    #[serde(default)]
12335    pub external_dir: Option<PathBuf>,
12336    /// Per-country overrides applied after loading.
12337    /// Keys are ISO 3166-1 alpha-2 codes; values are partial JSON objects
12338    /// that are deep-merged on top of the loaded pack.
12339    #[serde(default)]
12340    pub overrides: std::collections::HashMap<String, serde_json::Value>,
12341}
12342
12343/// Environmental metrics configuration.
12344#[derive(Debug, Clone, Serialize, Deserialize)]
12345pub struct EnvironmentalConfig {
12346    /// Whether environmental metrics are generated.
12347    #[serde(default = "default_true")]
12348    pub enabled: bool,
12349    /// Scope 1 (direct) emission generation settings.
12350    #[serde(default)]
12351    pub scope1: EmissionScopeConfig,
12352    /// Scope 2 (purchased energy) emission generation settings.
12353    #[serde(default)]
12354    pub scope2: EmissionScopeConfig,
12355    /// Scope 3 (value chain) emission generation settings.
12356    #[serde(default)]
12357    pub scope3: Scope3Config,
12358    /// Energy consumption tracking settings.
12359    #[serde(default)]
12360    pub energy: EnergySchemaConfig,
12361    /// Water usage tracking settings.
12362    #[serde(default)]
12363    pub water: WaterSchemaConfig,
12364    /// Waste management tracking settings.
12365    #[serde(default)]
12366    pub waste: WasteSchemaConfig,
12367}
12368
12369impl Default for EnvironmentalConfig {
12370    fn default() -> Self {
12371        Self {
12372            enabled: true,
12373            scope1: EmissionScopeConfig::default(),
12374            scope2: EmissionScopeConfig::default(),
12375            scope3: Scope3Config::default(),
12376            energy: EnergySchemaConfig::default(),
12377            water: WaterSchemaConfig::default(),
12378            waste: WasteSchemaConfig::default(),
12379        }
12380    }
12381}
12382
12383/// Configuration for a single emission scope (Scope 1 or 2).
12384#[derive(Debug, Clone, Serialize, Deserialize)]
12385pub struct EmissionScopeConfig {
12386    /// Whether this scope is enabled.
12387    #[serde(default = "default_true")]
12388    pub enabled: bool,
12389    /// Emission factor region (e.g., "US", "EU", "global").
12390    #[serde(default = "default_emission_region")]
12391    pub factor_region: String,
12392}
12393
12394fn default_emission_region() -> String {
12395    "US".to_string()
12396}
12397
12398impl Default for EmissionScopeConfig {
12399    fn default() -> Self {
12400        Self {
12401            enabled: true,
12402            factor_region: default_emission_region(),
12403        }
12404    }
12405}
12406
12407/// Scope 3 (value chain) emission configuration.
12408#[derive(Debug, Clone, Serialize, Deserialize)]
12409pub struct Scope3Config {
12410    /// Whether Scope 3 emissions are generated.
12411    #[serde(default = "default_true")]
12412    pub enabled: bool,
12413    /// Categories to include (e.g., "purchased_goods", "business_travel", "commuting").
12414    #[serde(default = "default_scope3_categories")]
12415    pub categories: Vec<String>,
12416    /// Spend-based emission intensity (kg CO2e per USD).
12417    #[serde(default = "default_spend_intensity")]
12418    pub default_spend_intensity_kg_per_usd: f64,
12419}
12420
12421fn default_scope3_categories() -> Vec<String> {
12422    vec![
12423        "purchased_goods".to_string(),
12424        "business_travel".to_string(),
12425        "employee_commuting".to_string(),
12426    ]
12427}
12428
12429fn default_spend_intensity() -> f64 {
12430    0.5
12431}
12432
12433impl Default for Scope3Config {
12434    fn default() -> Self {
12435        Self {
12436            enabled: true,
12437            categories: default_scope3_categories(),
12438            default_spend_intensity_kg_per_usd: default_spend_intensity(),
12439        }
12440    }
12441}
12442
12443/// Energy consumption configuration.
12444#[derive(Debug, Clone, Serialize, Deserialize)]
12445pub struct EnergySchemaConfig {
12446    /// Whether energy consumption tracking is enabled.
12447    #[serde(default = "default_true")]
12448    pub enabled: bool,
12449    /// Number of facilities to generate.
12450    #[serde(default = "default_facility_count")]
12451    pub facility_count: u32,
12452    /// Target percentage of energy from renewable sources (0.0 to 1.0).
12453    #[serde(default = "default_renewable_target")]
12454    pub renewable_target: f64,
12455}
12456
12457fn default_facility_count() -> u32 {
12458    5
12459}
12460
12461fn default_renewable_target() -> f64 {
12462    0.30
12463}
12464
12465impl Default for EnergySchemaConfig {
12466    fn default() -> Self {
12467        Self {
12468            enabled: true,
12469            facility_count: default_facility_count(),
12470            renewable_target: default_renewable_target(),
12471        }
12472    }
12473}
12474
12475/// Water usage configuration.
12476#[derive(Debug, Clone, Serialize, Deserialize)]
12477pub struct WaterSchemaConfig {
12478    /// Whether water usage tracking is enabled.
12479    #[serde(default = "default_true")]
12480    pub enabled: bool,
12481    /// Number of facilities with water tracking.
12482    #[serde(default = "default_water_facility_count")]
12483    pub facility_count: u32,
12484}
12485
12486fn default_water_facility_count() -> u32 {
12487    3
12488}
12489
12490impl Default for WaterSchemaConfig {
12491    fn default() -> Self {
12492        Self {
12493            enabled: true,
12494            facility_count: default_water_facility_count(),
12495        }
12496    }
12497}
12498
12499/// Waste management configuration.
12500#[derive(Debug, Clone, Serialize, Deserialize)]
12501pub struct WasteSchemaConfig {
12502    /// Whether waste tracking is enabled.
12503    #[serde(default = "default_true")]
12504    pub enabled: bool,
12505    /// Target diversion rate (0.0 to 1.0).
12506    #[serde(default = "default_diversion_target")]
12507    pub diversion_target: f64,
12508}
12509
12510fn default_diversion_target() -> f64 {
12511    0.50
12512}
12513
12514impl Default for WasteSchemaConfig {
12515    fn default() -> Self {
12516        Self {
12517            enabled: true,
12518            diversion_target: default_diversion_target(),
12519        }
12520    }
12521}
12522
12523/// Social metrics configuration.
12524#[derive(Debug, Clone, Serialize, Deserialize)]
12525pub struct SocialConfig {
12526    /// Whether social metrics are generated.
12527    #[serde(default = "default_true")]
12528    pub enabled: bool,
12529    /// Workforce diversity tracking settings.
12530    #[serde(default)]
12531    pub diversity: DiversitySchemaConfig,
12532    /// Pay equity analysis settings.
12533    #[serde(default)]
12534    pub pay_equity: PayEquitySchemaConfig,
12535    /// Safety incident and metrics settings.
12536    #[serde(default)]
12537    pub safety: SafetySchemaConfig,
12538}
12539
12540impl Default for SocialConfig {
12541    fn default() -> Self {
12542        Self {
12543            enabled: true,
12544            diversity: DiversitySchemaConfig::default(),
12545            pay_equity: PayEquitySchemaConfig::default(),
12546            safety: SafetySchemaConfig::default(),
12547        }
12548    }
12549}
12550
12551/// Workforce diversity configuration.
12552#[derive(Debug, Clone, Serialize, Deserialize)]
12553pub struct DiversitySchemaConfig {
12554    /// Whether diversity metrics are generated.
12555    #[serde(default = "default_true")]
12556    pub enabled: bool,
12557    /// Dimensions to track (e.g., "gender", "ethnicity", "age_group").
12558    #[serde(default = "default_diversity_dimensions")]
12559    pub dimensions: Vec<String>,
12560}
12561
12562fn default_diversity_dimensions() -> Vec<String> {
12563    vec![
12564        "gender".to_string(),
12565        "ethnicity".to_string(),
12566        "age_group".to_string(),
12567    ]
12568}
12569
12570impl Default for DiversitySchemaConfig {
12571    fn default() -> Self {
12572        Self {
12573            enabled: true,
12574            dimensions: default_diversity_dimensions(),
12575        }
12576    }
12577}
12578
12579/// Pay equity analysis configuration.
12580#[derive(Debug, Clone, Serialize, Deserialize)]
12581pub struct PayEquitySchemaConfig {
12582    /// Whether pay equity analysis is generated.
12583    #[serde(default = "default_true")]
12584    pub enabled: bool,
12585    /// Target pay gap threshold for flagging (e.g., 0.05 = 5% gap).
12586    #[serde(default = "default_pay_gap_threshold")]
12587    pub gap_threshold: f64,
12588}
12589
12590fn default_pay_gap_threshold() -> f64 {
12591    0.05
12592}
12593
12594impl Default for PayEquitySchemaConfig {
12595    fn default() -> Self {
12596        Self {
12597            enabled: true,
12598            gap_threshold: default_pay_gap_threshold(),
12599        }
12600    }
12601}
12602
12603/// Safety metrics configuration.
12604#[derive(Debug, Clone, Serialize, Deserialize)]
12605pub struct SafetySchemaConfig {
12606    /// Whether safety metrics are generated.
12607    #[serde(default = "default_true")]
12608    pub enabled: bool,
12609    /// Average annual recordable incidents per 200,000 hours.
12610    #[serde(default = "default_trir_target")]
12611    pub target_trir: f64,
12612    /// Number of safety incidents to generate.
12613    #[serde(default = "default_incident_count")]
12614    pub incident_count: u32,
12615}
12616
12617fn default_trir_target() -> f64 {
12618    2.5
12619}
12620
12621fn default_incident_count() -> u32 {
12622    20
12623}
12624
12625impl Default for SafetySchemaConfig {
12626    fn default() -> Self {
12627        Self {
12628            enabled: true,
12629            target_trir: default_trir_target(),
12630            incident_count: default_incident_count(),
12631        }
12632    }
12633}
12634
12635/// Governance metrics configuration.
12636#[derive(Debug, Clone, Serialize, Deserialize)]
12637pub struct GovernanceSchemaConfig {
12638    /// Whether governance metrics are generated.
12639    #[serde(default = "default_true")]
12640    pub enabled: bool,
12641    /// Number of board members.
12642    #[serde(default = "default_board_size")]
12643    pub board_size: u32,
12644    /// Target independent director ratio (0.0 to 1.0).
12645    #[serde(default = "default_independence_target")]
12646    pub independence_target: f64,
12647}
12648
12649fn default_board_size() -> u32 {
12650    11
12651}
12652
12653fn default_independence_target() -> f64 {
12654    0.67
12655}
12656
12657impl Default for GovernanceSchemaConfig {
12658    fn default() -> Self {
12659        Self {
12660            enabled: true,
12661            board_size: default_board_size(),
12662            independence_target: default_independence_target(),
12663        }
12664    }
12665}
12666
12667/// Supply-chain ESG assessment configuration.
12668#[derive(Debug, Clone, Serialize, Deserialize)]
12669pub struct SupplyChainEsgConfig {
12670    /// Whether supply chain ESG assessments are generated.
12671    #[serde(default = "default_true")]
12672    pub enabled: bool,
12673    /// Proportion of vendors to assess (0.0 to 1.0).
12674    #[serde(default = "default_assessment_coverage")]
12675    pub assessment_coverage: f64,
12676    /// High-risk country codes for automatic flagging.
12677    #[serde(default = "default_high_risk_countries")]
12678    pub high_risk_countries: Vec<String>,
12679}
12680
12681fn default_assessment_coverage() -> f64 {
12682    0.80
12683}
12684
12685fn default_high_risk_countries() -> Vec<String> {
12686    vec!["CN".to_string(), "BD".to_string(), "MM".to_string()]
12687}
12688
12689impl Default for SupplyChainEsgConfig {
12690    fn default() -> Self {
12691        Self {
12692            enabled: true,
12693            assessment_coverage: default_assessment_coverage(),
12694            high_risk_countries: default_high_risk_countries(),
12695        }
12696    }
12697}
12698
12699/// ESG reporting / disclosure framework configuration.
12700#[derive(Debug, Clone, Serialize, Deserialize)]
12701pub struct EsgReportingConfig {
12702    /// Whether ESG disclosures are generated.
12703    #[serde(default = "default_true")]
12704    pub enabled: bool,
12705    /// Frameworks to generate disclosures for.
12706    #[serde(default = "default_esg_frameworks")]
12707    pub frameworks: Vec<String>,
12708    /// Whether materiality assessment is performed.
12709    #[serde(default = "default_true")]
12710    pub materiality_assessment: bool,
12711    /// Materiality threshold for impact dimension (0.0 to 1.0).
12712    #[serde(default = "default_materiality_threshold")]
12713    pub impact_threshold: f64,
12714    /// Materiality threshold for financial dimension (0.0 to 1.0).
12715    #[serde(default = "default_materiality_threshold")]
12716    pub financial_threshold: f64,
12717}
12718
12719fn default_esg_frameworks() -> Vec<String> {
12720    vec!["GRI".to_string(), "ESRS".to_string()]
12721}
12722
12723fn default_materiality_threshold() -> f64 {
12724    0.6
12725}
12726
12727impl Default for EsgReportingConfig {
12728    fn default() -> Self {
12729        Self {
12730            enabled: true,
12731            frameworks: default_esg_frameworks(),
12732            materiality_assessment: true,
12733            impact_threshold: default_materiality_threshold(),
12734            financial_threshold: default_materiality_threshold(),
12735        }
12736    }
12737}
12738
12739/// Climate scenario analysis configuration.
12740#[derive(Debug, Clone, Serialize, Deserialize)]
12741pub struct ClimateScenarioConfig {
12742    /// Whether climate scenario analysis is generated.
12743    #[serde(default)]
12744    pub enabled: bool,
12745    /// Scenarios to model (e.g., "net_zero_2050", "stated_policies", "current_trajectory").
12746    #[serde(default = "default_climate_scenarios")]
12747    pub scenarios: Vec<String>,
12748    /// Time horizons in years to project.
12749    #[serde(default = "default_time_horizons")]
12750    pub time_horizons: Vec<u32>,
12751}
12752
12753fn default_climate_scenarios() -> Vec<String> {
12754    vec![
12755        "net_zero_2050".to_string(),
12756        "stated_policies".to_string(),
12757        "current_trajectory".to_string(),
12758    ]
12759}
12760
12761fn default_time_horizons() -> Vec<u32> {
12762    vec![5, 10, 30]
12763}
12764
12765impl Default for ClimateScenarioConfig {
12766    fn default() -> Self {
12767        Self {
12768            enabled: false,
12769            scenarios: default_climate_scenarios(),
12770            time_horizons: default_time_horizons(),
12771        }
12772    }
12773}
12774
12775// ===== Counterfactual Simulation Scenarios =====
12776
12777/// Configuration for counterfactual simulation scenarios.
12778#[derive(Debug, Clone, Serialize, Deserialize, Default)]
12779pub struct ScenariosConfig {
12780    /// Whether scenario generation is enabled.
12781    #[serde(default)]
12782    pub enabled: bool,
12783    /// List of scenario definitions.
12784    #[serde(default)]
12785    pub scenarios: Vec<ScenarioSchemaConfig>,
12786    /// Causal model configuration.
12787    #[serde(default)]
12788    pub causal_model: CausalModelSchemaConfig,
12789    /// Default settings applied to all scenarios.
12790    #[serde(default)]
12791    pub defaults: ScenarioDefaultsConfig,
12792    /// Generate counterfactual (original, mutated) JE pairs for ML training.
12793    /// When true, the orchestrator produces paired clean/anomalous journal entries.
12794    #[serde(default)]
12795    pub generate_counterfactuals: bool,
12796}
12797
12798/// A single scenario definition in the config.
12799#[derive(Debug, Clone, Serialize, Deserialize)]
12800pub struct ScenarioSchemaConfig {
12801    /// Scenario name (must be unique).
12802    pub name: String,
12803    /// Human-readable description.
12804    #[serde(default)]
12805    pub description: String,
12806    /// Tags for categorization.
12807    #[serde(default)]
12808    pub tags: Vec<String>,
12809    /// Base scenario name (None = default config).
12810    pub base: Option<String>,
12811    /// IFRS 9-style probability weight.
12812    pub probability_weight: Option<f64>,
12813    /// List of interventions to apply.
12814    #[serde(default)]
12815    pub interventions: Vec<InterventionSchemaConfig>,
12816    /// Constraint overrides for this scenario.
12817    #[serde(default)]
12818    pub constraints: ScenarioConstraintsSchemaConfig,
12819    /// Output configuration for this scenario.
12820    #[serde(default)]
12821    pub output: ScenarioOutputSchemaConfig,
12822    /// Arbitrary metadata.
12823    #[serde(default)]
12824    pub metadata: std::collections::HashMap<String, String>,
12825}
12826
12827/// An intervention definition in the config.
12828#[derive(Debug, Clone, Serialize, Deserialize)]
12829pub struct InterventionSchemaConfig {
12830    /// Intervention type and parameters (flattened tagged enum).
12831    #[serde(flatten)]
12832    pub intervention_type: serde_json::Value,
12833    /// Timing configuration.
12834    #[serde(default)]
12835    pub timing: InterventionTimingSchemaConfig,
12836    /// Human-readable label.
12837    pub label: Option<String>,
12838    /// Priority for conflict resolution (higher wins).
12839    #[serde(default)]
12840    pub priority: u32,
12841}
12842
12843/// Timing configuration for an intervention.
12844#[derive(Debug, Clone, Serialize, Deserialize)]
12845pub struct InterventionTimingSchemaConfig {
12846    /// Month offset from start (1-indexed).
12847    #[serde(default = "default_start_month")]
12848    pub start_month: u32,
12849    /// Duration in months.
12850    pub duration_months: Option<u32>,
12851    /// Onset type: "sudden", "gradual", "oscillating", "custom".
12852    #[serde(default = "default_onset")]
12853    pub onset: String,
12854    /// Ramp period in months.
12855    pub ramp_months: Option<u32>,
12856}
12857
12858fn default_start_month() -> u32 {
12859    1
12860}
12861
12862fn default_onset() -> String {
12863    "sudden".to_string()
12864}
12865
12866impl Default for InterventionTimingSchemaConfig {
12867    fn default() -> Self {
12868        Self {
12869            start_month: 1,
12870            duration_months: None,
12871            onset: "sudden".to_string(),
12872            ramp_months: None,
12873        }
12874    }
12875}
12876
12877/// Scenario constraint overrides.
12878#[derive(Debug, Clone, Serialize, Deserialize)]
12879pub struct ScenarioConstraintsSchemaConfig {
12880    #[serde(default = "default_true")]
12881    pub preserve_accounting_identity: bool,
12882    #[serde(default = "default_true")]
12883    pub preserve_document_chains: bool,
12884    #[serde(default = "default_true")]
12885    pub preserve_period_close: bool,
12886    #[serde(default = "default_true")]
12887    pub preserve_balance_coherence: bool,
12888    #[serde(default)]
12889    pub custom: Vec<CustomConstraintSchemaConfig>,
12890}
12891
12892impl Default for ScenarioConstraintsSchemaConfig {
12893    fn default() -> Self {
12894        Self {
12895            preserve_accounting_identity: true,
12896            preserve_document_chains: true,
12897            preserve_period_close: true,
12898            preserve_balance_coherence: true,
12899            custom: Vec::new(),
12900        }
12901    }
12902}
12903
12904/// Custom constraint in config.
12905#[derive(Debug, Clone, Serialize, Deserialize)]
12906pub struct CustomConstraintSchemaConfig {
12907    pub config_path: String,
12908    pub min: Option<f64>,
12909    pub max: Option<f64>,
12910    #[serde(default)]
12911    pub description: String,
12912}
12913
12914/// Output configuration for a scenario.
12915#[derive(Debug, Clone, Serialize, Deserialize)]
12916pub struct ScenarioOutputSchemaConfig {
12917    #[serde(default = "default_true")]
12918    pub paired: bool,
12919    #[serde(default = "default_diff_formats_schema")]
12920    pub diff_formats: Vec<String>,
12921    #[serde(default)]
12922    pub diff_scope: Vec<String>,
12923}
12924
12925fn default_diff_formats_schema() -> Vec<String> {
12926    vec!["summary".to_string(), "aggregate".to_string()]
12927}
12928
12929impl Default for ScenarioOutputSchemaConfig {
12930    fn default() -> Self {
12931        Self {
12932            paired: true,
12933            diff_formats: default_diff_formats_schema(),
12934            diff_scope: Vec::new(),
12935        }
12936    }
12937}
12938
12939/// Causal model configuration.
12940#[derive(Debug, Clone, Serialize, Deserialize)]
12941pub struct CausalModelSchemaConfig {
12942    /// Preset name: "default", "minimal", or "custom".
12943    #[serde(default = "default_causal_preset")]
12944    pub preset: String,
12945    /// Custom nodes (merged with preset).
12946    #[serde(default)]
12947    pub nodes: Vec<serde_json::Value>,
12948    /// Custom edges (merged with preset).
12949    #[serde(default)]
12950    pub edges: Vec<serde_json::Value>,
12951}
12952
12953fn default_causal_preset() -> String {
12954    "default".to_string()
12955}
12956
12957impl Default for CausalModelSchemaConfig {
12958    fn default() -> Self {
12959        Self {
12960            preset: "default".to_string(),
12961            nodes: Vec::new(),
12962            edges: Vec::new(),
12963        }
12964    }
12965}
12966
12967/// Default settings applied to all scenarios.
12968#[derive(Debug, Clone, Serialize, Deserialize, Default)]
12969pub struct ScenarioDefaultsConfig {
12970    #[serde(default)]
12971    pub constraints: ScenarioConstraintsSchemaConfig,
12972    #[serde(default)]
12973    pub output: ScenarioOutputSchemaConfig,
12974}
12975
12976// =====================================================================
12977// Compliance Regulations Framework Configuration
12978// =====================================================================
12979
12980/// Top-level configuration for the compliance regulations framework.
12981///
12982/// Controls standards registry, jurisdiction profiles, temporal versioning,
12983/// audit procedure templates, compliance graph integration, and output settings.
12984///
12985/// # Example
12986///
12987/// ```yaml
12988/// compliance_regulations:
12989///   enabled: true
12990///   jurisdictions: [US, DE, GB]
12991///   reference_date: "2025-06-30"
12992///   standards_selection:
12993///     categories: [accounting, auditing, regulatory]
12994///     include: ["IFRS-16", "ASC-606"]
12995///   audit_procedures:
12996///     enabled: true
12997///     procedures_per_standard: 3
12998///   findings:
12999///     enabled: true
13000///     finding_rate: 0.05
13001///   filings:
13002///     enabled: true
13003///   graph:
13004///     enabled: true
13005///     include_compliance_nodes: true
13006///     include_compliance_edges: true
13007/// ```
13008#[derive(Debug, Clone, Default, Serialize, Deserialize)]
13009pub struct ComplianceRegulationsConfig {
13010    /// Master switch for the compliance regulations framework.
13011    #[serde(default)]
13012    pub enabled: bool,
13013    /// Jurisdictions to generate compliance data for (ISO 3166-1 alpha-2 codes).
13014    /// If empty, inferred from company countries in the config.
13015    #[serde(default)]
13016    pub jurisdictions: Vec<String>,
13017    /// Reference date for temporal standard resolution (YYYY-MM-DD).
13018    /// Defaults to the global start_date if not set.
13019    #[serde(default)]
13020    pub reference_date: Option<String>,
13021    /// Standards selection filters.
13022    #[serde(default)]
13023    pub standards_selection: StandardsSelectionConfig,
13024    /// Audit procedure generation settings.
13025    #[serde(default)]
13026    pub audit_procedures: AuditProcedureGenConfig,
13027    /// Compliance finding generation settings.
13028    #[serde(default)]
13029    pub findings: ComplianceFindingGenConfig,
13030    /// Regulatory filing generation settings.
13031    #[serde(default)]
13032    pub filings: ComplianceFilingGenConfig,
13033    /// Compliance graph integration settings.
13034    #[serde(default)]
13035    pub graph: ComplianceGraphConfig,
13036    /// Output settings for compliance-specific files.
13037    #[serde(default)]
13038    pub output: ComplianceOutputConfig,
13039}
13040
13041/// Filters which standards are included in the generation.
13042#[derive(Debug, Clone, Default, Serialize, Deserialize)]
13043pub struct StandardsSelectionConfig {
13044    /// Standard categories to include (accounting, auditing, regulatory, tax, esg).
13045    /// Empty = all categories.
13046    #[serde(default)]
13047    pub categories: Vec<String>,
13048    /// Explicit standard IDs to include (e.g., ["IFRS-16", "ASC-606"]).
13049    /// When non-empty, only these standards (plus mandatory ones for selected jurisdictions) are used.
13050    #[serde(default)]
13051    pub include: Vec<String>,
13052    /// Standard IDs to exclude.
13053    #[serde(default)]
13054    pub exclude: Vec<String>,
13055    /// Include superseded standards in the output (for historical analysis).
13056    #[serde(default)]
13057    pub include_superseded: bool,
13058}
13059
13060/// Configuration for audit procedure template generation.
13061#[derive(Debug, Clone, Serialize, Deserialize)]
13062pub struct AuditProcedureGenConfig {
13063    /// Whether audit procedure generation is enabled.
13064    #[serde(default)]
13065    pub enabled: bool,
13066    /// Number of procedures to generate per applicable standard.
13067    #[serde(default = "default_procedures_per_standard")]
13068    pub procedures_per_standard: usize,
13069    /// Sampling methodology: "statistical", "non_statistical", "mixed".
13070    #[serde(default = "default_sampling_method")]
13071    pub sampling_method: String,
13072    /// Confidence level for statistical sampling (0.0-1.0).
13073    #[serde(default = "default_confidence_level")]
13074    pub confidence_level: f64,
13075    /// Tolerable misstatement rate for sampling (0.0-1.0).
13076    #[serde(default = "default_tolerable_misstatement")]
13077    pub tolerable_misstatement: f64,
13078}
13079
13080fn default_procedures_per_standard() -> usize {
13081    3
13082}
13083
13084fn default_sampling_method() -> String {
13085    "statistical".to_string()
13086}
13087
13088fn default_confidence_level() -> f64 {
13089    0.95
13090}
13091
13092fn default_tolerable_misstatement() -> f64 {
13093    0.05
13094}
13095
13096impl Default for AuditProcedureGenConfig {
13097    fn default() -> Self {
13098        Self {
13099            enabled: false,
13100            procedures_per_standard: default_procedures_per_standard(),
13101            sampling_method: default_sampling_method(),
13102            confidence_level: default_confidence_level(),
13103            tolerable_misstatement: default_tolerable_misstatement(),
13104        }
13105    }
13106}
13107
13108/// Configuration for compliance finding generation.
13109#[derive(Debug, Clone, Serialize, Deserialize)]
13110pub struct ComplianceFindingGenConfig {
13111    /// Whether finding generation is enabled.
13112    #[serde(default)]
13113    pub enabled: bool,
13114    /// Rate of findings per audit procedure (0.0-1.0).
13115    #[serde(default = "default_finding_rate")]
13116    pub finding_rate: f64,
13117    /// Rate of material weakness findings among all findings (0.0-1.0).
13118    #[serde(default = "default_cr_material_weakness_rate")]
13119    pub material_weakness_rate: f64,
13120    /// Rate of significant deficiency findings among all findings (0.0-1.0).
13121    #[serde(default = "default_cr_significant_deficiency_rate")]
13122    pub significant_deficiency_rate: f64,
13123    /// Whether to generate remediation plans for findings.
13124    #[serde(default = "default_true")]
13125    pub generate_remediation: bool,
13126}
13127
13128fn default_finding_rate() -> f64 {
13129    0.05
13130}
13131
13132fn default_cr_material_weakness_rate() -> f64 {
13133    0.02
13134}
13135
13136fn default_cr_significant_deficiency_rate() -> f64 {
13137    0.08
13138}
13139
13140impl Default for ComplianceFindingGenConfig {
13141    fn default() -> Self {
13142        Self {
13143            enabled: false,
13144            finding_rate: default_finding_rate(),
13145            material_weakness_rate: default_cr_material_weakness_rate(),
13146            significant_deficiency_rate: default_cr_significant_deficiency_rate(),
13147            generate_remediation: true,
13148        }
13149    }
13150}
13151
13152/// Configuration for regulatory filing generation.
13153#[derive(Debug, Clone, Serialize, Deserialize)]
13154pub struct ComplianceFilingGenConfig {
13155    /// Whether filing generation is enabled.
13156    #[serde(default)]
13157    pub enabled: bool,
13158    /// Filing types to include (e.g., ["10-K", "10-Q", "Jahresabschluss"]).
13159    /// Empty = all applicable filings for the selected jurisdictions.
13160    #[serde(default)]
13161    pub filing_types: Vec<String>,
13162    /// Generate filing status progression (draft → filed → accepted).
13163    #[serde(default = "default_true")]
13164    pub generate_status_progression: bool,
13165}
13166
13167impl Default for ComplianceFilingGenConfig {
13168    fn default() -> Self {
13169        Self {
13170            enabled: false,
13171            filing_types: Vec::new(),
13172            generate_status_progression: true,
13173        }
13174    }
13175}
13176
13177/// Configuration for compliance graph integration.
13178#[derive(Debug, Clone, Serialize, Deserialize)]
13179pub struct ComplianceGraphConfig {
13180    /// Whether compliance graph integration is enabled.
13181    #[serde(default)]
13182    pub enabled: bool,
13183    /// Include compliance nodes (Standard, Regulation, Jurisdiction, etc.).
13184    #[serde(default = "default_true")]
13185    pub include_compliance_nodes: bool,
13186    /// Include compliance edges (MapsToStandard, TestsControl, etc.).
13187    #[serde(default = "default_true")]
13188    pub include_compliance_edges: bool,
13189    /// Include cross-reference edges between standards.
13190    #[serde(default = "default_true")]
13191    pub include_cross_references: bool,
13192    /// Include temporal supersession edges.
13193    #[serde(default)]
13194    pub include_supersession_edges: bool,
13195    /// Include edges linking standards to the GL account types they govern.
13196    #[serde(default = "default_true")]
13197    pub include_account_links: bool,
13198    /// Include edges linking standards to the internal controls that implement them.
13199    #[serde(default = "default_true")]
13200    pub include_control_links: bool,
13201    /// Include edges linking filings and jurisdictions to the originating company.
13202    #[serde(default = "default_true")]
13203    pub include_company_links: bool,
13204}
13205
13206impl Default for ComplianceGraphConfig {
13207    fn default() -> Self {
13208        Self {
13209            enabled: false,
13210            include_compliance_nodes: true,
13211            include_compliance_edges: true,
13212            include_cross_references: true,
13213            include_supersession_edges: false,
13214            include_account_links: true,
13215            include_control_links: true,
13216            include_company_links: true,
13217        }
13218    }
13219}
13220
13221/// Output settings for compliance-specific data files.
13222#[derive(Debug, Clone, Serialize, Deserialize)]
13223pub struct ComplianceOutputConfig {
13224    /// Export the standards registry catalog.
13225    #[serde(default = "default_true")]
13226    pub export_registry: bool,
13227    /// Export jurisdiction profiles.
13228    #[serde(default = "default_true")]
13229    pub export_jurisdictions: bool,
13230    /// Export cross-reference map.
13231    #[serde(default = "default_true")]
13232    pub export_cross_references: bool,
13233    /// Export temporal version history.
13234    #[serde(default)]
13235    pub export_version_history: bool,
13236}
13237
13238impl Default for ComplianceOutputConfig {
13239    fn default() -> Self {
13240        Self {
13241            export_registry: true,
13242            export_jurisdictions: true,
13243            export_cross_references: true,
13244            export_version_history: false,
13245        }
13246    }
13247}
13248
13249#[cfg(test)]
13250#[allow(clippy::unwrap_used)]
13251mod tests {
13252    use super::*;
13253    use crate::presets::demo_preset;
13254
13255    // ==========================================================================
13256    // Serialization/Deserialization Tests
13257    // ==========================================================================
13258
13259    #[test]
13260    fn test_config_yaml_roundtrip() {
13261        let config = demo_preset();
13262        let yaml = serde_yaml::to_string(&config).expect("Failed to serialize to YAML");
13263        let deserialized: GeneratorConfig =
13264            serde_yaml::from_str(&yaml).expect("Failed to deserialize from YAML");
13265
13266        assert_eq!(
13267            config.global.period_months,
13268            deserialized.global.period_months
13269        );
13270        assert_eq!(config.global.industry, deserialized.global.industry);
13271        assert_eq!(config.companies.len(), deserialized.companies.len());
13272        assert_eq!(config.companies[0].code, deserialized.companies[0].code);
13273    }
13274
13275    #[test]
13276    fn test_config_json_roundtrip() {
13277        // Create a config without infinity values (JSON can't serialize f64::INFINITY)
13278        let mut config = demo_preset();
13279        // Replace infinity with a large but finite value for JSON compatibility
13280        config.master_data.employees.approval_limits.executive = 1e12;
13281
13282        let json = serde_json::to_string(&config).expect("Failed to serialize to JSON");
13283        let deserialized: GeneratorConfig =
13284            serde_json::from_str(&json).expect("Failed to deserialize from JSON");
13285
13286        assert_eq!(
13287            config.global.period_months,
13288            deserialized.global.period_months
13289        );
13290        assert_eq!(config.global.industry, deserialized.global.industry);
13291        assert_eq!(config.companies.len(), deserialized.companies.len());
13292    }
13293
13294    #[test]
13295    fn test_transaction_volume_serialization() {
13296        // Test various transaction volumes serialize correctly
13297        let volumes = vec![
13298            (TransactionVolume::TenK, "ten_k"),
13299            (TransactionVolume::HundredK, "hundred_k"),
13300            (TransactionVolume::OneM, "one_m"),
13301            (TransactionVolume::TenM, "ten_m"),
13302            (TransactionVolume::HundredM, "hundred_m"),
13303        ];
13304
13305        for (volume, expected_key) in volumes {
13306            let json = serde_json::to_string(&volume).expect("Failed to serialize");
13307            assert!(
13308                json.contains(expected_key),
13309                "Expected {} in JSON: {}",
13310                expected_key,
13311                json
13312            );
13313        }
13314    }
13315
13316    #[test]
13317    fn test_transaction_volume_custom_serialization() {
13318        let volume = TransactionVolume::Custom(12345);
13319        let json = serde_json::to_string(&volume).expect("Failed to serialize");
13320        let deserialized: TransactionVolume =
13321            serde_json::from_str(&json).expect("Failed to deserialize");
13322        assert_eq!(deserialized.count(), 12345);
13323    }
13324
13325    #[test]
13326    fn test_output_mode_serialization() {
13327        let modes = vec![
13328            OutputMode::Streaming,
13329            OutputMode::FlatFile,
13330            OutputMode::Both,
13331        ];
13332
13333        for mode in modes {
13334            let json = serde_json::to_string(&mode).expect("Failed to serialize");
13335            let deserialized: OutputMode =
13336                serde_json::from_str(&json).expect("Failed to deserialize");
13337            assert!(format!("{:?}", mode) == format!("{:?}", deserialized));
13338        }
13339    }
13340
13341    #[test]
13342    fn test_file_format_serialization() {
13343        let formats = vec![
13344            FileFormat::Csv,
13345            FileFormat::Parquet,
13346            FileFormat::Json,
13347            FileFormat::JsonLines,
13348        ];
13349
13350        for format in formats {
13351            let json = serde_json::to_string(&format).expect("Failed to serialize");
13352            let deserialized: FileFormat =
13353                serde_json::from_str(&json).expect("Failed to deserialize");
13354            assert!(format!("{:?}", format) == format!("{:?}", deserialized));
13355        }
13356    }
13357
13358    #[test]
13359    fn test_compression_algorithm_serialization() {
13360        let algos = vec![
13361            CompressionAlgorithm::Gzip,
13362            CompressionAlgorithm::Zstd,
13363            CompressionAlgorithm::Lz4,
13364            CompressionAlgorithm::Snappy,
13365        ];
13366
13367        for algo in algos {
13368            let json = serde_json::to_string(&algo).expect("Failed to serialize");
13369            let deserialized: CompressionAlgorithm =
13370                serde_json::from_str(&json).expect("Failed to deserialize");
13371            assert!(format!("{:?}", algo) == format!("{:?}", deserialized));
13372        }
13373    }
13374
13375    #[test]
13376    fn test_transfer_pricing_method_serialization() {
13377        let methods = vec![
13378            TransferPricingMethod::CostPlus,
13379            TransferPricingMethod::ComparableUncontrolled,
13380            TransferPricingMethod::ResalePrice,
13381            TransferPricingMethod::TransactionalNetMargin,
13382            TransferPricingMethod::ProfitSplit,
13383        ];
13384
13385        for method in methods {
13386            let json = serde_json::to_string(&method).expect("Failed to serialize");
13387            let deserialized: TransferPricingMethod =
13388                serde_json::from_str(&json).expect("Failed to deserialize");
13389            assert!(format!("{:?}", method) == format!("{:?}", deserialized));
13390        }
13391    }
13392
13393    #[test]
13394    fn test_benford_exemption_serialization() {
13395        let exemptions = vec![
13396            BenfordExemption::Recurring,
13397            BenfordExemption::Payroll,
13398            BenfordExemption::FixedFees,
13399            BenfordExemption::RoundAmounts,
13400        ];
13401
13402        for exemption in exemptions {
13403            let json = serde_json::to_string(&exemption).expect("Failed to serialize");
13404            let deserialized: BenfordExemption =
13405                serde_json::from_str(&json).expect("Failed to deserialize");
13406            assert!(format!("{:?}", exemption) == format!("{:?}", deserialized));
13407        }
13408    }
13409
13410    // ==========================================================================
13411    // Default Value Tests
13412    // ==========================================================================
13413
13414    #[test]
13415    fn test_global_config_defaults() {
13416        let yaml = r#"
13417            industry: manufacturing
13418            start_date: "2024-01-01"
13419            period_months: 6
13420        "#;
13421        let config: GlobalConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13422        assert_eq!(config.group_currency, "USD");
13423        assert!(config.parallel);
13424        assert_eq!(config.worker_threads, 0);
13425        assert_eq!(config.memory_limit_mb, 0);
13426    }
13427
13428    #[test]
13429    fn test_fraud_config_defaults() {
13430        let config = FraudConfig::default();
13431        assert!(!config.enabled);
13432        assert_eq!(config.fraud_rate, 0.005);
13433        assert!(!config.clustering_enabled);
13434    }
13435
13436    #[test]
13437    fn test_internal_controls_config_defaults() {
13438        let config = InternalControlsConfig::default();
13439        assert!(!config.enabled);
13440        assert_eq!(config.exception_rate, 0.02);
13441        assert_eq!(config.sod_violation_rate, 0.01);
13442        assert!(config.export_control_master_data);
13443        assert_eq!(config.sox_materiality_threshold, 10000.0);
13444        // COSO fields
13445        assert!(config.coso_enabled);
13446        assert!(!config.include_entity_level_controls);
13447        assert_eq!(config.target_maturity_level, "mixed");
13448    }
13449
13450    #[test]
13451    fn test_output_config_defaults() {
13452        let config = OutputConfig::default();
13453        assert!(matches!(config.mode, OutputMode::FlatFile));
13454        assert_eq!(config.formats, vec![FileFormat::Parquet]);
13455        assert!(config.compression.enabled);
13456        assert!(matches!(
13457            config.compression.algorithm,
13458            CompressionAlgorithm::Zstd
13459        ));
13460        assert!(config.include_acdoca);
13461        assert!(!config.include_bseg);
13462        assert!(config.partition_by_period);
13463        assert!(!config.partition_by_company);
13464    }
13465
13466    #[test]
13467    fn test_approval_config_defaults() {
13468        let config = ApprovalConfig::default();
13469        assert!(!config.enabled);
13470        assert_eq!(config.auto_approve_threshold, 1000.0);
13471        assert_eq!(config.rejection_rate, 0.02);
13472        assert_eq!(config.revision_rate, 0.05);
13473        assert_eq!(config.average_approval_delay_hours, 4.0);
13474        assert_eq!(config.thresholds.len(), 4);
13475    }
13476
13477    #[test]
13478    fn test_p2p_flow_config_defaults() {
13479        let config = P2PFlowConfig::default();
13480        assert!(config.enabled);
13481        assert_eq!(config.three_way_match_rate, 0.95);
13482        assert_eq!(config.partial_delivery_rate, 0.15);
13483        assert_eq!(config.average_po_to_gr_days, 14);
13484    }
13485
13486    #[test]
13487    fn test_o2c_flow_config_defaults() {
13488        let config = O2CFlowConfig::default();
13489        assert!(config.enabled);
13490        assert_eq!(config.credit_check_failure_rate, 0.02);
13491        assert_eq!(config.return_rate, 0.03);
13492        assert_eq!(config.bad_debt_rate, 0.01);
13493    }
13494
13495    #[test]
13496    fn test_balance_config_defaults() {
13497        let config = BalanceConfig::default();
13498        assert!(!config.generate_opening_balances);
13499        assert!(config.generate_trial_balances);
13500        assert_eq!(config.target_gross_margin, 0.35);
13501        assert!(config.validate_balance_equation);
13502        assert!(config.reconcile_subledgers);
13503    }
13504
13505    // ==========================================================================
13506    // Partial Config Deserialization Tests
13507    // ==========================================================================
13508
13509    #[test]
13510    fn test_partial_config_with_defaults() {
13511        // Minimal config that should use all defaults
13512        let yaml = r#"
13513            global:
13514              industry: manufacturing
13515              start_date: "2024-01-01"
13516              period_months: 3
13517            companies:
13518              - code: "TEST"
13519                name: "Test Company"
13520                currency: "USD"
13521                country: "US"
13522                annual_transaction_volume: ten_k
13523            chart_of_accounts:
13524              complexity: small
13525            output:
13526              output_directory: "./output"
13527        "#;
13528
13529        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13530        assert_eq!(config.global.period_months, 3);
13531        assert_eq!(config.companies.len(), 1);
13532        assert!(!config.fraud.enabled); // Default
13533        assert!(!config.internal_controls.enabled); // Default
13534    }
13535
13536    #[test]
13537    fn test_config_with_fraud_enabled() {
13538        let yaml = r#"
13539            global:
13540              industry: retail
13541              start_date: "2024-01-01"
13542              period_months: 12
13543            companies:
13544              - code: "RETAIL"
13545                name: "Retail Co"
13546                currency: "USD"
13547                country: "US"
13548                annual_transaction_volume: hundred_k
13549            chart_of_accounts:
13550              complexity: medium
13551            output:
13552              output_directory: "./output"
13553            fraud:
13554              enabled: true
13555              fraud_rate: 0.05
13556              clustering_enabled: true
13557        "#;
13558
13559        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13560        assert!(config.fraud.enabled);
13561        assert_eq!(config.fraud.fraud_rate, 0.05);
13562        assert!(config.fraud.clustering_enabled);
13563    }
13564
13565    #[test]
13566    fn test_config_with_multiple_companies() {
13567        let yaml = r#"
13568            global:
13569              industry: manufacturing
13570              start_date: "2024-01-01"
13571              period_months: 6
13572            companies:
13573              - code: "HQ"
13574                name: "Headquarters"
13575                currency: "USD"
13576                country: "US"
13577                annual_transaction_volume: hundred_k
13578                volume_weight: 1.0
13579              - code: "EU"
13580                name: "European Subsidiary"
13581                currency: "EUR"
13582                country: "DE"
13583                annual_transaction_volume: hundred_k
13584                volume_weight: 0.5
13585              - code: "APAC"
13586                name: "Asia Pacific"
13587                currency: "JPY"
13588                country: "JP"
13589                annual_transaction_volume: ten_k
13590                volume_weight: 0.3
13591            chart_of_accounts:
13592              complexity: large
13593            output:
13594              output_directory: "./output"
13595        "#;
13596
13597        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13598        assert_eq!(config.companies.len(), 3);
13599        assert_eq!(config.companies[0].code, "HQ");
13600        assert_eq!(config.companies[1].currency, "EUR");
13601        assert_eq!(config.companies[2].volume_weight, 0.3);
13602    }
13603
13604    #[test]
13605    fn test_intercompany_config() {
13606        let yaml = r#"
13607            enabled: true
13608            ic_transaction_rate: 0.20
13609            transfer_pricing_method: cost_plus
13610            markup_percent: 0.08
13611            generate_matched_pairs: true
13612            generate_eliminations: true
13613        "#;
13614
13615        let config: IntercompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13616        assert!(config.enabled);
13617        assert_eq!(config.ic_transaction_rate, 0.20);
13618        assert!(matches!(
13619            config.transfer_pricing_method,
13620            TransferPricingMethod::CostPlus
13621        ));
13622        assert_eq!(config.markup_percent, 0.08);
13623        assert!(config.generate_eliminations);
13624    }
13625
13626    // ==========================================================================
13627    // Company Config Tests
13628    // ==========================================================================
13629
13630    #[test]
13631    fn test_company_config_defaults() {
13632        let yaml = r#"
13633            code: "TEST"
13634            name: "Test Company"
13635            currency: "USD"
13636            country: "US"
13637            annual_transaction_volume: ten_k
13638        "#;
13639
13640        let config: CompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13641        assert_eq!(config.fiscal_year_variant, "K4"); // Default
13642        assert_eq!(config.volume_weight, 1.0); // Default
13643    }
13644
13645    // ==========================================================================
13646    // Chart of Accounts Config Tests
13647    // ==========================================================================
13648
13649    #[test]
13650    fn test_coa_config_defaults() {
13651        let yaml = r#"
13652            complexity: medium
13653        "#;
13654
13655        let config: ChartOfAccountsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13656        assert!(config.industry_specific); // Default true
13657        assert!(config.custom_accounts.is_none());
13658        assert_eq!(config.min_hierarchy_depth, 2); // Default
13659        assert_eq!(config.max_hierarchy_depth, 5); // Default
13660    }
13661
13662    // ==========================================================================
13663    // Accounting Standards Config Tests
13664    // ==========================================================================
13665
13666    #[test]
13667    fn test_accounting_standards_config_defaults() {
13668        let config = AccountingStandardsConfig::default();
13669        assert!(!config.enabled);
13670        assert!(config.framework.is_none());
13671        assert!(!config.revenue_recognition.enabled);
13672        assert!(!config.leases.enabled);
13673        assert!(!config.fair_value.enabled);
13674        assert!(!config.impairment.enabled);
13675        assert!(!config.generate_differences);
13676    }
13677
13678    #[test]
13679    fn test_accounting_standards_config_yaml() {
13680        let yaml = r#"
13681            enabled: true
13682            framework: ifrs
13683            revenue_recognition:
13684              enabled: true
13685              generate_contracts: true
13686              avg_obligations_per_contract: 2.5
13687              variable_consideration_rate: 0.20
13688              over_time_recognition_rate: 0.35
13689              contract_count: 150
13690            leases:
13691              enabled: true
13692              lease_count: 75
13693              finance_lease_percent: 0.25
13694              avg_lease_term_months: 48
13695            generate_differences: true
13696        "#;
13697
13698        let config: AccountingStandardsConfig =
13699            serde_yaml::from_str(yaml).expect("Failed to parse");
13700        assert!(config.enabled);
13701        assert!(matches!(
13702            config.framework,
13703            Some(AccountingFrameworkConfig::Ifrs)
13704        ));
13705        assert!(config.revenue_recognition.enabled);
13706        assert_eq!(config.revenue_recognition.contract_count, 150);
13707        assert_eq!(config.revenue_recognition.avg_obligations_per_contract, 2.5);
13708        assert!(config.leases.enabled);
13709        assert_eq!(config.leases.lease_count, 75);
13710        assert_eq!(config.leases.finance_lease_percent, 0.25);
13711        assert!(config.generate_differences);
13712    }
13713
13714    #[test]
13715    fn test_accounting_framework_serialization() {
13716        let frameworks = [
13717            AccountingFrameworkConfig::UsGaap,
13718            AccountingFrameworkConfig::Ifrs,
13719            AccountingFrameworkConfig::DualReporting,
13720            AccountingFrameworkConfig::FrenchGaap,
13721            AccountingFrameworkConfig::GermanGaap,
13722        ];
13723
13724        for framework in frameworks {
13725            let json = serde_json::to_string(&framework).expect("Failed to serialize");
13726            let deserialized: AccountingFrameworkConfig =
13727                serde_json::from_str(&json).expect("Failed to deserialize");
13728            assert!(format!("{:?}", framework) == format!("{:?}", deserialized));
13729        }
13730    }
13731
13732    #[test]
13733    fn test_revenue_recognition_config_defaults() {
13734        let config = RevenueRecognitionConfig::default();
13735        assert!(!config.enabled);
13736        assert!(config.generate_contracts);
13737        assert_eq!(config.avg_obligations_per_contract, 2.0);
13738        assert_eq!(config.variable_consideration_rate, 0.15);
13739        assert_eq!(config.over_time_recognition_rate, 0.30);
13740        assert_eq!(config.contract_count, 100);
13741    }
13742
13743    #[test]
13744    fn test_lease_accounting_config_defaults() {
13745        let config = LeaseAccountingConfig::default();
13746        assert!(!config.enabled);
13747        assert_eq!(config.lease_count, 50);
13748        assert_eq!(config.finance_lease_percent, 0.30);
13749        assert_eq!(config.avg_lease_term_months, 60);
13750        assert!(config.generate_amortization);
13751        assert_eq!(config.real_estate_percent, 0.40);
13752    }
13753
13754    #[test]
13755    fn test_fair_value_config_defaults() {
13756        let config = FairValueConfig::default();
13757        assert!(!config.enabled);
13758        assert_eq!(config.measurement_count, 25);
13759        assert_eq!(config.level1_percent, 0.40);
13760        assert_eq!(config.level2_percent, 0.35);
13761        assert_eq!(config.level3_percent, 0.25);
13762        assert!(!config.include_sensitivity_analysis);
13763    }
13764
13765    #[test]
13766    fn test_impairment_config_defaults() {
13767        let config = ImpairmentConfig::default();
13768        assert!(!config.enabled);
13769        assert_eq!(config.test_count, 15);
13770        assert_eq!(config.impairment_rate, 0.10);
13771        assert!(config.generate_projections);
13772        assert!(!config.include_goodwill);
13773    }
13774
13775    // ==========================================================================
13776    // Audit Standards Config Tests
13777    // ==========================================================================
13778
13779    #[test]
13780    fn test_audit_standards_config_defaults() {
13781        let config = AuditStandardsConfig::default();
13782        assert!(!config.enabled);
13783        assert!(!config.isa_compliance.enabled);
13784        assert!(!config.analytical_procedures.enabled);
13785        assert!(!config.confirmations.enabled);
13786        assert!(!config.opinion.enabled);
13787        assert!(!config.generate_audit_trail);
13788        assert!(!config.sox.enabled);
13789        assert!(!config.pcaob.enabled);
13790    }
13791
13792    #[test]
13793    fn test_audit_standards_config_yaml() {
13794        let yaml = r#"
13795            enabled: true
13796            isa_compliance:
13797              enabled: true
13798              compliance_level: comprehensive
13799              generate_isa_mappings: true
13800              include_pcaob: true
13801              framework: dual
13802            analytical_procedures:
13803              enabled: true
13804              procedures_per_account: 5
13805              variance_probability: 0.25
13806            confirmations:
13807              enabled: true
13808              confirmation_count: 75
13809              positive_response_rate: 0.90
13810              exception_rate: 0.08
13811            opinion:
13812              enabled: true
13813              generate_kam: true
13814              average_kam_count: 4
13815            sox:
13816              enabled: true
13817              generate_302_certifications: true
13818              generate_404_assessments: true
13819              material_weakness_rate: 0.03
13820            pcaob:
13821              enabled: true
13822              is_pcaob_audit: true
13823              include_icfr_opinion: true
13824            generate_audit_trail: true
13825        "#;
13826
13827        let config: AuditStandardsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13828        assert!(config.enabled);
13829        assert!(config.isa_compliance.enabled);
13830        assert_eq!(config.isa_compliance.compliance_level, "comprehensive");
13831        assert!(config.isa_compliance.include_pcaob);
13832        assert_eq!(config.isa_compliance.framework, "dual");
13833        assert!(config.analytical_procedures.enabled);
13834        assert_eq!(config.analytical_procedures.procedures_per_account, 5);
13835        assert!(config.confirmations.enabled);
13836        assert_eq!(config.confirmations.confirmation_count, 75);
13837        assert!(config.opinion.enabled);
13838        assert_eq!(config.opinion.average_kam_count, 4);
13839        assert!(config.sox.enabled);
13840        assert!(config.sox.generate_302_certifications);
13841        assert_eq!(config.sox.material_weakness_rate, 0.03);
13842        assert!(config.pcaob.enabled);
13843        assert!(config.pcaob.is_pcaob_audit);
13844        assert!(config.pcaob.include_icfr_opinion);
13845        assert!(config.generate_audit_trail);
13846    }
13847
13848    #[test]
13849    fn test_isa_compliance_config_defaults() {
13850        let config = IsaComplianceConfig::default();
13851        assert!(!config.enabled);
13852        assert_eq!(config.compliance_level, "standard");
13853        assert!(config.generate_isa_mappings);
13854        assert!(config.generate_coverage_summary);
13855        assert!(!config.include_pcaob);
13856        assert_eq!(config.framework, "isa");
13857    }
13858
13859    #[test]
13860    fn test_sox_compliance_config_defaults() {
13861        let config = SoxComplianceConfig::default();
13862        assert!(!config.enabled);
13863        assert!(config.generate_302_certifications);
13864        assert!(config.generate_404_assessments);
13865        assert_eq!(config.materiality_threshold, 10000.0);
13866        assert_eq!(config.material_weakness_rate, 0.02);
13867        assert_eq!(config.significant_deficiency_rate, 0.08);
13868    }
13869
13870    #[test]
13871    fn test_pcaob_config_defaults() {
13872        let config = PcaobConfig::default();
13873        assert!(!config.enabled);
13874        assert!(!config.is_pcaob_audit);
13875        assert!(config.generate_cam);
13876        assert!(!config.include_icfr_opinion);
13877        assert!(!config.generate_standard_mappings);
13878    }
13879
13880    #[test]
13881    fn test_config_with_standards_enabled() {
13882        let yaml = r#"
13883            global:
13884              industry: financial_services
13885              start_date: "2024-01-01"
13886              period_months: 12
13887            companies:
13888              - code: "BANK"
13889                name: "Test Bank"
13890                currency: "USD"
13891                country: "US"
13892                annual_transaction_volume: hundred_k
13893            chart_of_accounts:
13894              complexity: large
13895            output:
13896              output_directory: "./output"
13897            accounting_standards:
13898              enabled: true
13899              framework: us_gaap
13900              revenue_recognition:
13901                enabled: true
13902              leases:
13903                enabled: true
13904            audit_standards:
13905              enabled: true
13906              isa_compliance:
13907                enabled: true
13908              sox:
13909                enabled: true
13910        "#;
13911
13912        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13913        assert!(config.accounting_standards.enabled);
13914        assert!(matches!(
13915            config.accounting_standards.framework,
13916            Some(AccountingFrameworkConfig::UsGaap)
13917        ));
13918        assert!(config.accounting_standards.revenue_recognition.enabled);
13919        assert!(config.accounting_standards.leases.enabled);
13920        assert!(config.audit_standards.enabled);
13921        assert!(config.audit_standards.isa_compliance.enabled);
13922        assert!(config.audit_standards.sox.enabled);
13923    }
13924
13925    // ==========================================================================
13926    // Industry-Specific Config Tests
13927    // ==========================================================================
13928
13929    #[test]
13930    fn test_industry_specific_config_defaults() {
13931        let config = IndustrySpecificConfig::default();
13932        assert!(!config.enabled);
13933        assert!(!config.manufacturing.enabled);
13934        assert!(!config.retail.enabled);
13935        assert!(!config.healthcare.enabled);
13936        assert!(!config.technology.enabled);
13937        assert!(!config.financial_services.enabled);
13938        assert!(!config.professional_services.enabled);
13939    }
13940
13941    #[test]
13942    fn test_manufacturing_config_defaults() {
13943        let config = ManufacturingConfig::default();
13944        assert!(!config.enabled);
13945        assert_eq!(config.bom_depth, 4);
13946        assert!(!config.just_in_time);
13947        assert_eq!(config.supplier_tiers, 2);
13948        assert_eq!(config.target_yield_rate, 0.97);
13949        assert_eq!(config.scrap_alert_threshold, 0.03);
13950    }
13951
13952    #[test]
13953    fn test_retail_config_defaults() {
13954        let config = RetailConfig::default();
13955        assert!(!config.enabled);
13956        assert_eq!(config.avg_daily_transactions, 500);
13957        assert!(config.loss_prevention);
13958        assert_eq!(config.shrinkage_rate, 0.015);
13959    }
13960
13961    #[test]
13962    fn test_healthcare_config_defaults() {
13963        let config = HealthcareConfig::default();
13964        assert!(!config.enabled);
13965        assert_eq!(config.facility_type, "hospital");
13966        assert_eq!(config.avg_daily_encounters, 150);
13967        assert!(config.compliance.hipaa);
13968        assert!(config.compliance.stark_law);
13969        assert!(config.coding_systems.icd10);
13970        assert!(config.coding_systems.cpt);
13971    }
13972
13973    #[test]
13974    fn test_technology_config_defaults() {
13975        let config = TechnologyConfig::default();
13976        assert!(!config.enabled);
13977        assert_eq!(config.revenue_model, "saas");
13978        assert_eq!(config.subscription_revenue_pct, 0.60);
13979        assert!(config.rd_capitalization.enabled);
13980    }
13981
13982    #[test]
13983    fn test_config_with_industry_specific() {
13984        let yaml = r#"
13985            global:
13986              industry: healthcare
13987              start_date: "2024-01-01"
13988              period_months: 12
13989            companies:
13990              - code: "HOSP"
13991                name: "Test Hospital"
13992                currency: "USD"
13993                country: "US"
13994                annual_transaction_volume: hundred_k
13995            chart_of_accounts:
13996              complexity: medium
13997            output:
13998              output_directory: "./output"
13999            industry_specific:
14000              enabled: true
14001              healthcare:
14002                enabled: true
14003                facility_type: hospital
14004                payer_mix:
14005                  medicare: 0.45
14006                  medicaid: 0.15
14007                  commercial: 0.35
14008                  self_pay: 0.05
14009                coding_systems:
14010                  icd10: true
14011                  cpt: true
14012                  drg: true
14013                compliance:
14014                  hipaa: true
14015                  stark_law: true
14016                anomaly_rates:
14017                  upcoding: 0.03
14018                  unbundling: 0.02
14019        "#;
14020
14021        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14022        assert!(config.industry_specific.enabled);
14023        assert!(config.industry_specific.healthcare.enabled);
14024        assert_eq!(
14025            config.industry_specific.healthcare.facility_type,
14026            "hospital"
14027        );
14028        assert_eq!(config.industry_specific.healthcare.payer_mix.medicare, 0.45);
14029        assert_eq!(config.industry_specific.healthcare.payer_mix.self_pay, 0.05);
14030        assert!(config.industry_specific.healthcare.coding_systems.icd10);
14031        assert!(config.industry_specific.healthcare.compliance.hipaa);
14032        assert_eq!(
14033            config.industry_specific.healthcare.anomaly_rates.upcoding,
14034            0.03
14035        );
14036    }
14037
14038    #[test]
14039    fn test_config_with_manufacturing_specific() {
14040        let yaml = r#"
14041            global:
14042              industry: manufacturing
14043              start_date: "2024-01-01"
14044              period_months: 12
14045            companies:
14046              - code: "MFG"
14047                name: "Test Manufacturing"
14048                currency: "USD"
14049                country: "US"
14050                annual_transaction_volume: hundred_k
14051            chart_of_accounts:
14052              complexity: medium
14053            output:
14054              output_directory: "./output"
14055            industry_specific:
14056              enabled: true
14057              manufacturing:
14058                enabled: true
14059                bom_depth: 5
14060                just_in_time: true
14061                supplier_tiers: 3
14062                target_yield_rate: 0.98
14063                anomaly_rates:
14064                  yield_manipulation: 0.02
14065                  phantom_production: 0.01
14066        "#;
14067
14068        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14069        assert!(config.industry_specific.enabled);
14070        assert!(config.industry_specific.manufacturing.enabled);
14071        assert_eq!(config.industry_specific.manufacturing.bom_depth, 5);
14072        assert!(config.industry_specific.manufacturing.just_in_time);
14073        assert_eq!(config.industry_specific.manufacturing.supplier_tiers, 3);
14074        assert_eq!(
14075            config.industry_specific.manufacturing.target_yield_rate,
14076            0.98
14077        );
14078        assert_eq!(
14079            config
14080                .industry_specific
14081                .manufacturing
14082                .anomaly_rates
14083                .yield_manipulation,
14084            0.02
14085        );
14086    }
14087
14088    // ==========================================================================
14089    // Tax Configuration Tests
14090    // ==========================================================================
14091
14092    #[test]
14093    fn test_tax_config_defaults() {
14094        let tax = TaxConfig::default();
14095        assert!(!tax.enabled);
14096        assert!(tax.jurisdictions.countries.is_empty());
14097        assert!(!tax.jurisdictions.include_subnational);
14098        assert!(!tax.vat_gst.enabled);
14099        assert!(tax.vat_gst.standard_rates.is_empty());
14100        assert!(tax.vat_gst.reduced_rates.is_empty());
14101        assert!(tax.vat_gst.exempt_categories.is_empty());
14102        assert!(tax.vat_gst.reverse_charge);
14103        assert!(!tax.sales_tax.enabled);
14104        assert!(tax.sales_tax.nexus_states.is_empty());
14105        assert!(!tax.withholding.enabled);
14106        assert!(tax.withholding.treaty_network);
14107        assert_eq!(tax.withholding.default_rate, 0.30);
14108        assert_eq!(tax.withholding.treaty_reduced_rate, 0.15);
14109        assert!(tax.provisions.enabled);
14110        assert_eq!(tax.provisions.statutory_rate, 0.21);
14111        assert!(tax.provisions.uncertain_positions);
14112        assert!(!tax.payroll_tax.enabled);
14113        assert_eq!(tax.anomaly_rate, 0.03);
14114    }
14115
14116    #[test]
14117    fn test_tax_config_from_yaml() {
14118        let yaml = r#"
14119            global:
14120              seed: 42
14121              start_date: "2024-01-01"
14122              period_months: 12
14123              industry: retail
14124            companies:
14125              - code: C001
14126                name: Test Corp
14127                currency: USD
14128                country: US
14129                annual_transaction_volume: ten_k
14130            chart_of_accounts:
14131              complexity: small
14132            output:
14133              output_directory: ./output
14134            tax:
14135              enabled: true
14136              anomaly_rate: 0.05
14137              jurisdictions:
14138                countries: ["US", "DE", "GB"]
14139                include_subnational: true
14140              vat_gst:
14141                enabled: true
14142                standard_rates:
14143                  DE: 0.19
14144                  GB: 0.20
14145                reduced_rates:
14146                  DE: 0.07
14147                  GB: 0.05
14148                exempt_categories:
14149                  - financial_services
14150                  - healthcare
14151                reverse_charge: false
14152              sales_tax:
14153                enabled: true
14154                nexus_states: ["CA", "NY", "TX"]
14155              withholding:
14156                enabled: true
14157                treaty_network: false
14158                default_rate: 0.25
14159                treaty_reduced_rate: 0.10
14160              provisions:
14161                enabled: false
14162                statutory_rate: 0.28
14163                uncertain_positions: false
14164              payroll_tax:
14165                enabled: true
14166        "#;
14167
14168        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14169        assert!(config.tax.enabled);
14170        assert_eq!(config.tax.anomaly_rate, 0.05);
14171
14172        // Jurisdictions
14173        assert_eq!(config.tax.jurisdictions.countries.len(), 3);
14174        assert!(config
14175            .tax
14176            .jurisdictions
14177            .countries
14178            .contains(&"DE".to_string()));
14179        assert!(config.tax.jurisdictions.include_subnational);
14180
14181        // VAT/GST
14182        assert!(config.tax.vat_gst.enabled);
14183        assert_eq!(config.tax.vat_gst.standard_rates.get("DE"), Some(&0.19));
14184        assert_eq!(config.tax.vat_gst.standard_rates.get("GB"), Some(&0.20));
14185        assert_eq!(config.tax.vat_gst.reduced_rates.get("DE"), Some(&0.07));
14186        assert_eq!(config.tax.vat_gst.exempt_categories.len(), 2);
14187        assert!(!config.tax.vat_gst.reverse_charge);
14188
14189        // Sales tax
14190        assert!(config.tax.sales_tax.enabled);
14191        assert_eq!(config.tax.sales_tax.nexus_states.len(), 3);
14192        assert!(config
14193            .tax
14194            .sales_tax
14195            .nexus_states
14196            .contains(&"CA".to_string()));
14197
14198        // Withholding
14199        assert!(config.tax.withholding.enabled);
14200        assert!(!config.tax.withholding.treaty_network);
14201        assert_eq!(config.tax.withholding.default_rate, 0.25);
14202        assert_eq!(config.tax.withholding.treaty_reduced_rate, 0.10);
14203
14204        // Provisions
14205        assert!(!config.tax.provisions.enabled);
14206        assert_eq!(config.tax.provisions.statutory_rate, 0.28);
14207        assert!(!config.tax.provisions.uncertain_positions);
14208
14209        // Payroll tax
14210        assert!(config.tax.payroll_tax.enabled);
14211    }
14212
14213    #[test]
14214    fn test_generator_config_with_tax_default() {
14215        let yaml = r#"
14216            global:
14217              seed: 42
14218              start_date: "2024-01-01"
14219              period_months: 12
14220              industry: retail
14221            companies:
14222              - code: C001
14223                name: Test Corp
14224                currency: USD
14225                country: US
14226                annual_transaction_volume: ten_k
14227            chart_of_accounts:
14228              complexity: small
14229            output:
14230              output_directory: ./output
14231        "#;
14232
14233        let config: GeneratorConfig =
14234            serde_yaml::from_str(yaml).expect("Failed to parse config without tax section");
14235        // Tax should be present with defaults when not specified in YAML
14236        assert!(!config.tax.enabled);
14237        assert!(config.tax.jurisdictions.countries.is_empty());
14238        assert_eq!(config.tax.anomaly_rate, 0.03);
14239        assert!(config.tax.provisions.enabled); // provisions default to enabled=true
14240        assert_eq!(config.tax.provisions.statutory_rate, 0.21);
14241    }
14242
14243    // ==========================================================================
14244    // SessionSchemaConfig Tests
14245    // ==========================================================================
14246
14247    #[test]
14248    fn test_session_config_default_disabled() {
14249        let yaml = "{}";
14250        let config: SessionSchemaConfig =
14251            serde_yaml::from_str(yaml).expect("Failed to parse empty session config");
14252        assert!(!config.enabled);
14253        assert!(config.checkpoint_path.is_none());
14254        assert!(config.per_period_output);
14255        assert!(config.consolidated_output);
14256    }
14257
14258    #[test]
14259    fn test_config_backward_compatible_without_session() {
14260        let yaml = r#"
14261            global:
14262              seed: 42
14263              start_date: "2024-01-01"
14264              period_months: 12
14265              industry: retail
14266            companies:
14267              - code: C001
14268                name: Test Corp
14269                currency: USD
14270                country: US
14271                annual_transaction_volume: ten_k
14272            chart_of_accounts:
14273              complexity: small
14274            output:
14275              output_directory: ./output
14276        "#;
14277
14278        let config: GeneratorConfig =
14279            serde_yaml::from_str(yaml).expect("Failed to parse config without session");
14280        // Session should default to disabled
14281        assert!(!config.session.enabled);
14282        assert!(config.session.per_period_output);
14283        assert!(config.session.consolidated_output);
14284        // fiscal_year_months should be None
14285        assert!(config.global.fiscal_year_months.is_none());
14286    }
14287
14288    #[test]
14289    fn test_fiscal_year_months_parsed() {
14290        let yaml = r#"
14291            global:
14292              seed: 42
14293              start_date: "2024-01-01"
14294              period_months: 24
14295              industry: retail
14296              fiscal_year_months: 12
14297            companies:
14298              - code: C001
14299                name: Test Corp
14300                currency: USD
14301                country: US
14302                annual_transaction_volume: ten_k
14303            chart_of_accounts:
14304              complexity: small
14305            output:
14306              output_directory: ./output
14307            session:
14308              enabled: true
14309              checkpoint_path: /tmp/checkpoints
14310              per_period_output: true
14311              consolidated_output: false
14312        "#;
14313
14314        let config: GeneratorConfig =
14315            serde_yaml::from_str(yaml).expect("Failed to parse config with fiscal_year_months");
14316        assert_eq!(config.global.fiscal_year_months, Some(12));
14317        assert!(config.session.enabled);
14318        assert_eq!(
14319            config.session.checkpoint_path,
14320            Some("/tmp/checkpoints".to_string())
14321        );
14322        assert!(config.session.per_period_output);
14323        assert!(!config.session.consolidated_output);
14324    }
14325}