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
156/// LLM enrichment configuration.
157///
158/// Controls AI-augmented metadata enrichment using LLM providers.
159/// When enabled, vendor names, transaction descriptions, and anomaly explanations
160/// are enriched using the configured provider (mock by default).
161#[derive(Debug, Clone, Serialize, Deserialize)]
162pub struct LlmSchemaConfig {
163    /// Whether LLM enrichment is enabled.
164    #[serde(default)]
165    pub enabled: bool,
166    /// Provider type: "mock", "openai", "anthropic", "custom".
167    #[serde(default = "default_llm_provider")]
168    pub provider: String,
169    /// Model name/ID for the provider.
170    #[serde(default = "default_llm_model_name")]
171    pub model: String,
172    /// Maximum number of vendor names to enrich per run.
173    #[serde(default = "default_llm_batch_size")]
174    pub max_vendor_enrichments: usize,
175}
176
177fn default_llm_provider() -> String {
178    "mock".to_string()
179}
180
181fn default_llm_model_name() -> String {
182    "gpt-4o-mini".to_string()
183}
184
185fn default_llm_batch_size() -> usize {
186    50
187}
188
189impl Default for LlmSchemaConfig {
190    fn default() -> Self {
191        Self {
192            enabled: false,
193            provider: default_llm_provider(),
194            model: default_llm_model_name(),
195            max_vendor_enrichments: default_llm_batch_size(),
196        }
197    }
198}
199
200/// Diffusion model configuration.
201///
202/// Controls statistical diffusion-based data enhancement that generates samples
203/// matching target distribution properties (means, standard deviations, correlations).
204#[derive(Debug, Clone, Serialize, Deserialize)]
205pub struct DiffusionSchemaConfig {
206    /// Whether diffusion enhancement is enabled.
207    #[serde(default)]
208    pub enabled: bool,
209    /// Number of diffusion steps (higher = better quality, slower).
210    #[serde(default = "default_diffusion_steps")]
211    pub n_steps: usize,
212    /// Noise schedule type: "linear", "cosine", "sigmoid".
213    #[serde(default = "default_diffusion_schedule")]
214    pub schedule: String,
215    /// Number of sample rows to generate for demonstration.
216    #[serde(default = "default_diffusion_sample_size")]
217    pub sample_size: usize,
218}
219
220fn default_diffusion_steps() -> usize {
221    100
222}
223
224fn default_diffusion_schedule() -> String {
225    "linear".to_string()
226}
227
228fn default_diffusion_sample_size() -> usize {
229    100
230}
231
232impl Default for DiffusionSchemaConfig {
233    fn default() -> Self {
234        Self {
235            enabled: false,
236            n_steps: default_diffusion_steps(),
237            schedule: default_diffusion_schedule(),
238            sample_size: default_diffusion_sample_size(),
239        }
240    }
241}
242
243/// Causal generation configuration.
244///
245/// Controls structural causal model (SCM) based data generation that respects
246/// causal relationships between variables, supports do-calculus interventions,
247/// and enables counterfactual scenarios.
248#[derive(Debug, Clone, Serialize, Deserialize)]
249pub struct CausalSchemaConfig {
250    /// Whether causal generation is enabled.
251    #[serde(default)]
252    pub enabled: bool,
253    /// Built-in template to use: "fraud_detection", "revenue_cycle", or "custom".
254    #[serde(default = "default_causal_template")]
255    pub template: String,
256    /// Number of causal samples to generate.
257    #[serde(default = "default_causal_sample_size")]
258    pub sample_size: usize,
259    /// Whether to run causal validation on the output.
260    #[serde(default = "default_true")]
261    pub validate: bool,
262}
263
264fn default_causal_template() -> String {
265    "fraud_detection".to_string()
266}
267
268fn default_causal_sample_size() -> usize {
269    500
270}
271
272impl Default for CausalSchemaConfig {
273    fn default() -> Self {
274        Self {
275            enabled: false,
276            template: default_causal_template(),
277            sample_size: default_causal_sample_size(),
278            validate: true,
279        }
280    }
281}
282
283/// Graph export configuration for accounting network and ML training exports.
284///
285/// This section enables exporting generated data as graphs for:
286/// - Network reconstruction algorithms
287/// - Graph neural network training
288/// - Neo4j graph database import
289#[derive(Debug, Clone, Serialize, Deserialize)]
290pub struct GraphExportConfig {
291    /// Enable graph export.
292    #[serde(default)]
293    pub enabled: bool,
294
295    /// Graph types to generate.
296    #[serde(default = "default_graph_types")]
297    pub graph_types: Vec<GraphTypeConfig>,
298
299    /// Export formats to generate.
300    #[serde(default = "default_graph_formats")]
301    pub formats: Vec<GraphExportFormat>,
302
303    /// Train split ratio for ML datasets.
304    #[serde(default = "default_train_ratio")]
305    pub train_ratio: f64,
306
307    /// Validation split ratio for ML datasets.
308    #[serde(default = "default_val_ratio")]
309    pub validation_ratio: f64,
310
311    /// Random seed for train/val/test splits.
312    #[serde(default)]
313    pub split_seed: Option<u64>,
314
315    /// Output subdirectory for graph exports (relative to output directory).
316    #[serde(default = "default_graph_subdir")]
317    pub output_subdirectory: String,
318
319    /// Multi-layer hypergraph export settings for RustGraph integration.
320    #[serde(default)]
321    pub hypergraph: HypergraphExportSettings,
322}
323
324fn default_graph_types() -> Vec<GraphTypeConfig> {
325    vec![GraphTypeConfig::default()]
326}
327
328fn default_graph_formats() -> Vec<GraphExportFormat> {
329    vec![GraphExportFormat::PytorchGeometric]
330}
331
332fn default_train_ratio() -> f64 {
333    0.7
334}
335
336fn default_val_ratio() -> f64 {
337    0.15
338}
339
340fn default_graph_subdir() -> String {
341    "graphs".to_string()
342}
343
344impl Default for GraphExportConfig {
345    fn default() -> Self {
346        Self {
347            enabled: false,
348            graph_types: default_graph_types(),
349            formats: default_graph_formats(),
350            train_ratio: 0.7,
351            validation_ratio: 0.15,
352            split_seed: None,
353            output_subdirectory: "graphs".to_string(),
354            hypergraph: HypergraphExportSettings::default(),
355        }
356    }
357}
358
359/// Settings for the multi-layer hypergraph export (RustGraph integration).
360///
361/// Produces a 3-layer hypergraph:
362/// - Layer 1: Governance & Controls (COSO, SOX, internal controls, organizational)
363/// - Layer 2: Process Events (P2P/O2C document flows, OCPM events)
364/// - Layer 3: Accounting Network (GL accounts, journal entries as hyperedges)
365#[derive(Debug, Clone, Serialize, Deserialize)]
366pub struct HypergraphExportSettings {
367    /// Enable hypergraph export.
368    #[serde(default)]
369    pub enabled: bool,
370
371    /// Maximum total nodes across all layers (default 50000).
372    #[serde(default = "default_hypergraph_max_nodes")]
373    pub max_nodes: usize,
374
375    /// Aggregation strategy when node budget is exceeded.
376    #[serde(default = "default_aggregation_strategy")]
377    pub aggregation_strategy: String,
378
379    /// Layer 1 (Governance & Controls) settings.
380    #[serde(default)]
381    pub governance_layer: GovernanceLayerSettings,
382
383    /// Layer 2 (Process Events) settings.
384    #[serde(default)]
385    pub process_layer: ProcessLayerSettings,
386
387    /// Layer 3 (Accounting Network) settings.
388    #[serde(default)]
389    pub accounting_layer: AccountingLayerSettings,
390
391    /// Cross-layer edge generation settings.
392    #[serde(default)]
393    pub cross_layer: CrossLayerSettings,
394
395    /// Output subdirectory for hypergraph files (relative to graph output directory).
396    #[serde(default = "default_hypergraph_subdir")]
397    pub output_subdirectory: String,
398
399    /// Output format: "native" (default) for internal field names, "unified" for RustGraph format.
400    #[serde(default = "default_hypergraph_format")]
401    pub output_format: String,
402
403    /// Optional URL for streaming unified JSONL to a RustGraph ingest endpoint.
404    #[serde(default)]
405    pub stream_target: Option<String>,
406
407    /// Batch size for streaming (number of JSONL lines per HTTP POST). Default: 1000.
408    #[serde(default = "default_stream_batch_size")]
409    pub stream_batch_size: usize,
410}
411
412fn default_hypergraph_max_nodes() -> usize {
413    50_000
414}
415
416fn default_aggregation_strategy() -> String {
417    "pool_by_counterparty".to_string()
418}
419
420fn default_hypergraph_subdir() -> String {
421    "hypergraph".to_string()
422}
423
424fn default_hypergraph_format() -> String {
425    "native".to_string()
426}
427
428fn default_stream_batch_size() -> usize {
429    1000
430}
431
432impl Default for HypergraphExportSettings {
433    fn default() -> Self {
434        Self {
435            enabled: false,
436            max_nodes: 50_000,
437            aggregation_strategy: "pool_by_counterparty".to_string(),
438            governance_layer: GovernanceLayerSettings::default(),
439            process_layer: ProcessLayerSettings::default(),
440            accounting_layer: AccountingLayerSettings::default(),
441            cross_layer: CrossLayerSettings::default(),
442            output_subdirectory: "hypergraph".to_string(),
443            output_format: "native".to_string(),
444            stream_target: None,
445            stream_batch_size: 1000,
446        }
447    }
448}
449
450/// Layer 1: Governance & Controls layer settings.
451#[derive(Debug, Clone, Serialize, Deserialize)]
452pub struct GovernanceLayerSettings {
453    /// Include COSO framework nodes (5 components + 17 principles).
454    #[serde(default = "default_true")]
455    pub include_coso: bool,
456    /// Include internal control nodes.
457    #[serde(default = "default_true")]
458    pub include_controls: bool,
459    /// Include SOX assertion nodes.
460    #[serde(default = "default_true")]
461    pub include_sox: bool,
462    /// Include vendor master data nodes.
463    #[serde(default = "default_true")]
464    pub include_vendors: bool,
465    /// Include customer master data nodes.
466    #[serde(default = "default_true")]
467    pub include_customers: bool,
468    /// Include employee/organizational nodes.
469    #[serde(default = "default_true")]
470    pub include_employees: bool,
471}
472
473impl Default for GovernanceLayerSettings {
474    fn default() -> Self {
475        Self {
476            include_coso: true,
477            include_controls: true,
478            include_sox: true,
479            include_vendors: true,
480            include_customers: true,
481            include_employees: true,
482        }
483    }
484}
485
486/// Layer 2: Process Events layer settings.
487#[derive(Debug, Clone, Serialize, Deserialize)]
488pub struct ProcessLayerSettings {
489    /// Include P2P (Procure-to-Pay) document flow nodes.
490    #[serde(default = "default_true")]
491    pub include_p2p: bool,
492    /// Include O2C (Order-to-Cash) document flow nodes.
493    #[serde(default = "default_true")]
494    pub include_o2c: bool,
495    /// Export OCPM events as hyperedges.
496    #[serde(default = "default_true")]
497    pub events_as_hyperedges: bool,
498    /// Threshold: if a counterparty has more documents than this, aggregate into pool nodes.
499    #[serde(default = "default_docs_per_counterparty_threshold")]
500    pub docs_per_counterparty_threshold: usize,
501}
502
503fn default_docs_per_counterparty_threshold() -> usize {
504    20
505}
506
507impl Default for ProcessLayerSettings {
508    fn default() -> Self {
509        Self {
510            include_p2p: true,
511            include_o2c: true,
512            events_as_hyperedges: true,
513            docs_per_counterparty_threshold: 20,
514        }
515    }
516}
517
518/// Layer 3: Accounting Network layer settings.
519#[derive(Debug, Clone, Serialize, Deserialize)]
520pub struct AccountingLayerSettings {
521    /// Include GL account nodes.
522    #[serde(default = "default_true")]
523    pub include_accounts: bool,
524    /// Export journal entries as hyperedges (debit+credit accounts as participants).
525    #[serde(default = "default_true")]
526    pub je_as_hyperedges: bool,
527}
528
529impl Default for AccountingLayerSettings {
530    fn default() -> Self {
531        Self {
532            include_accounts: true,
533            je_as_hyperedges: true,
534        }
535    }
536}
537
538/// Cross-layer edge generation settings.
539#[derive(Debug, Clone, Serialize, Deserialize)]
540pub struct CrossLayerSettings {
541    /// Generate cross-layer edges (Control→Account, Vendor→PO, etc.).
542    #[serde(default = "default_true")]
543    pub enabled: bool,
544}
545
546impl Default for CrossLayerSettings {
547    fn default() -> Self {
548        Self { enabled: true }
549    }
550}
551
552/// Configuration for a specific graph type to export.
553#[derive(Debug, Clone, Serialize, Deserialize)]
554pub struct GraphTypeConfig {
555    /// Name identifier for this graph configuration.
556    #[serde(default = "default_graph_name")]
557    pub name: String,
558
559    /// Whether to aggregate parallel edges between the same nodes.
560    #[serde(default)]
561    pub aggregate_edges: bool,
562
563    /// Minimum edge weight to include (filters out small transactions).
564    #[serde(default)]
565    pub min_edge_weight: f64,
566
567    /// Whether to include document nodes (creates hub-and-spoke structure).
568    #[serde(default)]
569    pub include_document_nodes: bool,
570}
571
572fn default_graph_name() -> String {
573    "accounting_network".to_string()
574}
575
576impl Default for GraphTypeConfig {
577    fn default() -> Self {
578        Self {
579            name: "accounting_network".to_string(),
580            aggregate_edges: false,
581            min_edge_weight: 0.0,
582            include_document_nodes: false,
583        }
584    }
585}
586
587/// Export format for graph data.
588#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
589#[serde(rename_all = "snake_case")]
590pub enum GraphExportFormat {
591    /// PyTorch Geometric format (.npy files + metadata.json).
592    PytorchGeometric,
593    /// Neo4j format (CSV files + Cypher import scripts).
594    Neo4j,
595    /// Deep Graph Library format.
596    Dgl,
597    /// RustGraph/RustAssureTwin JSON format.
598    RustGraph,
599    /// RustGraph multi-layer hypergraph format (nodes.jsonl + edges.jsonl + hyperedges.jsonl).
600    RustGraphHypergraph,
601}
602
603/// Scenario configuration for metadata, tagging, and ML training setup.
604///
605/// This section enables tracking the purpose and characteristics of a generation run.
606#[derive(Debug, Clone, Default, Serialize, Deserialize)]
607pub struct ScenarioConfig {
608    /// Tags for categorizing and filtering datasets.
609    /// Examples: "fraud_detection", "retail", "month_end_stress", "ml_training"
610    #[serde(default)]
611    pub tags: Vec<String>,
612
613    /// Data quality profile preset.
614    /// - "clean": Minimal data quality issues (0.1% missing, 0.05% typos)
615    /// - "noisy": Moderate issues (5% missing, 2% typos, 1% duplicates)
616    /// - "legacy": Heavy issues simulating legacy system data (10% missing, 5% typos)
617    #[serde(default)]
618    pub profile: Option<String>,
619
620    /// Human-readable description of the scenario purpose.
621    #[serde(default)]
622    pub description: Option<String>,
623
624    /// Whether this run is for ML training (enables balanced labeling).
625    #[serde(default)]
626    pub ml_training: bool,
627
628    /// Target anomaly class balance for ML training.
629    /// If set, anomalies will be injected to achieve this ratio.
630    #[serde(default)]
631    pub target_anomaly_ratio: Option<f64>,
632
633    /// Custom metadata key-value pairs.
634    #[serde(default)]
635    pub metadata: std::collections::HashMap<String, String>,
636}
637
638/// Temporal drift configuration for simulating distribution changes over time.
639///
640/// This enables generation of data that shows realistic temporal evolution,
641/// useful for training drift detection models and testing temporal robustness.
642#[derive(Debug, Clone, Serialize, Deserialize)]
643pub struct TemporalDriftConfig {
644    /// Enable temporal drift simulation.
645    #[serde(default)]
646    pub enabled: bool,
647
648    /// Amount mean drift per period (e.g., 0.02 = 2% mean shift per month).
649    /// Simulates gradual inflation or business growth.
650    #[serde(default = "default_amount_drift")]
651    pub amount_mean_drift: f64,
652
653    /// Amount variance drift per period (e.g., 0.01 = 1% variance increase per month).
654    /// Simulates increasing volatility over time.
655    #[serde(default)]
656    pub amount_variance_drift: f64,
657
658    /// Anomaly rate drift per period (e.g., 0.001 = 0.1% increase per month).
659    /// Simulates increasing fraud attempts or degrading controls.
660    #[serde(default)]
661    pub anomaly_rate_drift: f64,
662
663    /// Concept drift rate - how quickly feature distributions change (0.0-1.0).
664    /// Higher values cause more rapid distribution shifts.
665    #[serde(default = "default_concept_drift")]
666    pub concept_drift_rate: f64,
667
668    /// Sudden drift events - probability of a sudden distribution shift in any period.
669    #[serde(default)]
670    pub sudden_drift_probability: f64,
671
672    /// Magnitude of sudden drift events when they occur (multiplier).
673    #[serde(default = "default_sudden_drift_magnitude")]
674    pub sudden_drift_magnitude: f64,
675
676    /// Seasonal drift - enable cyclic patterns that repeat annually.
677    #[serde(default)]
678    pub seasonal_drift: bool,
679
680    /// Drift start period (0 = from beginning). Use to simulate stable baseline before drift.
681    #[serde(default)]
682    pub drift_start_period: u32,
683
684    /// Drift type: "gradual", "sudden", "recurring", "mixed"
685    #[serde(default = "default_drift_type")]
686    pub drift_type: DriftType,
687}
688
689fn default_amount_drift() -> f64 {
690    0.02
691}
692
693fn default_concept_drift() -> f64 {
694    0.01
695}
696
697fn default_sudden_drift_magnitude() -> f64 {
698    2.0
699}
700
701fn default_drift_type() -> DriftType {
702    DriftType::Gradual
703}
704
705impl Default for TemporalDriftConfig {
706    fn default() -> Self {
707        Self {
708            enabled: false,
709            amount_mean_drift: 0.02,
710            amount_variance_drift: 0.0,
711            anomaly_rate_drift: 0.0,
712            concept_drift_rate: 0.01,
713            sudden_drift_probability: 0.0,
714            sudden_drift_magnitude: 2.0,
715            seasonal_drift: false,
716            drift_start_period: 0,
717            drift_type: DriftType::Gradual,
718        }
719    }
720}
721
722impl TemporalDriftConfig {
723    /// Convert to core DriftConfig for use in generators.
724    pub fn to_core_config(&self) -> datasynth_core::distributions::DriftConfig {
725        datasynth_core::distributions::DriftConfig {
726            enabled: self.enabled,
727            amount_mean_drift: self.amount_mean_drift,
728            amount_variance_drift: self.amount_variance_drift,
729            anomaly_rate_drift: self.anomaly_rate_drift,
730            concept_drift_rate: self.concept_drift_rate,
731            sudden_drift_probability: self.sudden_drift_probability,
732            sudden_drift_magnitude: self.sudden_drift_magnitude,
733            seasonal_drift: self.seasonal_drift,
734            drift_start_period: self.drift_start_period,
735            drift_type: match self.drift_type {
736                DriftType::Gradual => datasynth_core::distributions::DriftType::Gradual,
737                DriftType::Sudden => datasynth_core::distributions::DriftType::Sudden,
738                DriftType::Recurring => datasynth_core::distributions::DriftType::Recurring,
739                DriftType::Mixed => datasynth_core::distributions::DriftType::Mixed,
740            },
741            regime_changes: Vec::new(),
742            economic_cycle: Default::default(),
743            parameter_drifts: Vec::new(),
744        }
745    }
746}
747
748/// Types of temporal drift patterns.
749#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
750#[serde(rename_all = "snake_case")]
751pub enum DriftType {
752    /// Gradual, continuous drift over time (like inflation).
753    #[default]
754    Gradual,
755    /// Sudden, point-in-time shifts (like policy changes).
756    Sudden,
757    /// Recurring patterns that cycle (like seasonal variations).
758    Recurring,
759    /// Combination of gradual background drift with occasional sudden shifts.
760    Mixed,
761}
762
763// ============================================================================
764// Streaming Output API Configuration (Phase 2)
765// ============================================================================
766
767/// Configuration for streaming output API.
768#[derive(Debug, Clone, Serialize, Deserialize)]
769pub struct StreamingSchemaConfig {
770    /// Enable streaming output.
771    #[serde(default)]
772    pub enabled: bool,
773    /// Buffer size for streaming (number of items).
774    #[serde(default = "default_buffer_size")]
775    pub buffer_size: usize,
776    /// Enable progress reporting.
777    #[serde(default = "default_true")]
778    pub enable_progress: bool,
779    /// Progress reporting interval (number of items).
780    #[serde(default = "default_progress_interval")]
781    pub progress_interval: u64,
782    /// Backpressure strategy.
783    #[serde(default)]
784    pub backpressure: BackpressureSchemaStrategy,
785}
786
787fn default_buffer_size() -> usize {
788    1000
789}
790
791fn default_progress_interval() -> u64 {
792    100
793}
794
795impl Default for StreamingSchemaConfig {
796    fn default() -> Self {
797        Self {
798            enabled: false,
799            buffer_size: 1000,
800            enable_progress: true,
801            progress_interval: 100,
802            backpressure: BackpressureSchemaStrategy::Block,
803        }
804    }
805}
806
807/// Backpressure strategy for streaming output.
808#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
809#[serde(rename_all = "snake_case")]
810pub enum BackpressureSchemaStrategy {
811    /// Block until space is available in the buffer.
812    #[default]
813    Block,
814    /// Drop oldest items when buffer is full.
815    DropOldest,
816    /// Drop newest items when buffer is full.
817    DropNewest,
818    /// Buffer overflow items up to a limit, then block.
819    Buffer,
820}
821
822// ============================================================================
823// Rate Limiting Configuration (Phase 5)
824// ============================================================================
825
826/// Configuration for rate limiting.
827#[derive(Debug, Clone, Serialize, Deserialize)]
828pub struct RateLimitSchemaConfig {
829    /// Enable rate limiting.
830    #[serde(default)]
831    pub enabled: bool,
832    /// Entities per second limit.
833    #[serde(default = "default_entities_per_second")]
834    pub entities_per_second: f64,
835    /// Burst size (number of tokens in bucket).
836    #[serde(default = "default_burst_size")]
837    pub burst_size: u32,
838    /// Backpressure strategy for rate limiting.
839    #[serde(default)]
840    pub backpressure: RateLimitBackpressureSchema,
841}
842
843fn default_entities_per_second() -> f64 {
844    1000.0
845}
846
847fn default_burst_size() -> u32 {
848    100
849}
850
851impl Default for RateLimitSchemaConfig {
852    fn default() -> Self {
853        Self {
854            enabled: false,
855            entities_per_second: 1000.0,
856            burst_size: 100,
857            backpressure: RateLimitBackpressureSchema::Block,
858        }
859    }
860}
861
862/// Backpressure strategy for rate limiting.
863#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
864#[serde(rename_all = "snake_case")]
865pub enum RateLimitBackpressureSchema {
866    /// Block until rate allows.
867    #[default]
868    Block,
869    /// Drop items that exceed rate.
870    Drop,
871    /// Buffer items and process when rate allows.
872    Buffer,
873}
874
875// ============================================================================
876// Temporal Attribute Generation Configuration (Phase 3)
877// ============================================================================
878
879/// Configuration for temporal attribute generation.
880#[derive(Debug, Clone, Serialize, Deserialize)]
881pub struct TemporalAttributeSchemaConfig {
882    /// Enable temporal attribute generation.
883    #[serde(default)]
884    pub enabled: bool,
885    /// Valid time configuration.
886    #[serde(default)]
887    pub valid_time: ValidTimeSchemaConfig,
888    /// Transaction time configuration.
889    #[serde(default)]
890    pub transaction_time: TransactionTimeSchemaConfig,
891    /// Generate version chains for entities.
892    #[serde(default)]
893    pub generate_version_chains: bool,
894    /// Average number of versions per entity.
895    #[serde(default = "default_avg_versions")]
896    pub avg_versions_per_entity: f64,
897}
898
899fn default_avg_versions() -> f64 {
900    1.5
901}
902
903impl Default for TemporalAttributeSchemaConfig {
904    fn default() -> Self {
905        Self {
906            enabled: false,
907            valid_time: ValidTimeSchemaConfig::default(),
908            transaction_time: TransactionTimeSchemaConfig::default(),
909            generate_version_chains: false,
910            avg_versions_per_entity: 1.5,
911        }
912    }
913}
914
915/// Configuration for valid time (business time) generation.
916#[derive(Debug, Clone, Serialize, Deserialize)]
917pub struct ValidTimeSchemaConfig {
918    /// Probability that valid_to is set (entity has ended validity).
919    #[serde(default = "default_closed_probability")]
920    pub closed_probability: f64,
921    /// Average validity duration in days.
922    #[serde(default = "default_avg_validity_days")]
923    pub avg_validity_days: u32,
924    /// Standard deviation of validity duration in days.
925    #[serde(default = "default_validity_stddev")]
926    pub validity_stddev_days: u32,
927}
928
929fn default_closed_probability() -> f64 {
930    0.1
931}
932
933fn default_avg_validity_days() -> u32 {
934    365
935}
936
937fn default_validity_stddev() -> u32 {
938    90
939}
940
941impl Default for ValidTimeSchemaConfig {
942    fn default() -> Self {
943        Self {
944            closed_probability: 0.1,
945            avg_validity_days: 365,
946            validity_stddev_days: 90,
947        }
948    }
949}
950
951/// Configuration for transaction time (system time) generation.
952#[derive(Debug, Clone, Serialize, Deserialize)]
953pub struct TransactionTimeSchemaConfig {
954    /// Average recording delay in seconds (0 = immediate).
955    #[serde(default)]
956    pub avg_recording_delay_seconds: u32,
957    /// Allow backdating (recording time before valid time).
958    #[serde(default)]
959    pub allow_backdating: bool,
960    /// Probability of backdating if allowed.
961    #[serde(default = "default_backdating_probability")]
962    pub backdating_probability: f64,
963    /// Maximum backdate days.
964    #[serde(default = "default_max_backdate_days")]
965    pub max_backdate_days: u32,
966}
967
968fn default_backdating_probability() -> f64 {
969    0.01
970}
971
972fn default_max_backdate_days() -> u32 {
973    30
974}
975
976impl Default for TransactionTimeSchemaConfig {
977    fn default() -> Self {
978        Self {
979            avg_recording_delay_seconds: 0,
980            allow_backdating: false,
981            backdating_probability: 0.01,
982            max_backdate_days: 30,
983        }
984    }
985}
986
987// ============================================================================
988// Relationship Generation Configuration (Phase 4)
989// ============================================================================
990
991/// Configuration for relationship generation.
992#[derive(Debug, Clone, Serialize, Deserialize)]
993pub struct RelationshipSchemaConfig {
994    /// Relationship type definitions.
995    #[serde(default)]
996    pub relationship_types: Vec<RelationshipTypeSchemaConfig>,
997    /// Allow orphan entities (entities with no relationships).
998    #[serde(default = "default_true")]
999    pub allow_orphans: bool,
1000    /// Probability of creating an orphan entity.
1001    #[serde(default = "default_orphan_probability")]
1002    pub orphan_probability: f64,
1003    /// Allow circular relationships.
1004    #[serde(default)]
1005    pub allow_circular: bool,
1006    /// Maximum depth for circular relationship detection.
1007    #[serde(default = "default_max_circular_depth")]
1008    pub max_circular_depth: u32,
1009}
1010
1011fn default_orphan_probability() -> f64 {
1012    0.01
1013}
1014
1015fn default_max_circular_depth() -> u32 {
1016    3
1017}
1018
1019impl Default for RelationshipSchemaConfig {
1020    fn default() -> Self {
1021        Self {
1022            relationship_types: Vec::new(),
1023            allow_orphans: true,
1024            orphan_probability: 0.01,
1025            allow_circular: false,
1026            max_circular_depth: 3,
1027        }
1028    }
1029}
1030
1031/// Configuration for a specific relationship type.
1032#[derive(Debug, Clone, Serialize, Deserialize)]
1033pub struct RelationshipTypeSchemaConfig {
1034    /// Name of the relationship type (e.g., "debits", "credits", "created").
1035    pub name: String,
1036    /// Source entity type (e.g., "journal_entry").
1037    pub source_type: String,
1038    /// Target entity type (e.g., "account").
1039    pub target_type: String,
1040    /// Cardinality rule for this relationship.
1041    #[serde(default)]
1042    pub cardinality: CardinalitySchemaRule,
1043    /// Weight for this relationship in random selection.
1044    #[serde(default = "default_relationship_weight")]
1045    pub weight: f64,
1046    /// Whether this relationship is required.
1047    #[serde(default)]
1048    pub required: bool,
1049    /// Whether this relationship is directed.
1050    #[serde(default = "default_true")]
1051    pub directed: bool,
1052}
1053
1054fn default_relationship_weight() -> f64 {
1055    1.0
1056}
1057
1058impl Default for RelationshipTypeSchemaConfig {
1059    fn default() -> Self {
1060        Self {
1061            name: String::new(),
1062            source_type: String::new(),
1063            target_type: String::new(),
1064            cardinality: CardinalitySchemaRule::default(),
1065            weight: 1.0,
1066            required: false,
1067            directed: true,
1068        }
1069    }
1070}
1071
1072/// Cardinality rule for relationships in schema config.
1073#[derive(Debug, Clone, Serialize, Deserialize)]
1074#[serde(rename_all = "snake_case")]
1075pub enum CardinalitySchemaRule {
1076    /// One source to one target.
1077    OneToOne,
1078    /// One source to many targets.
1079    OneToMany {
1080        /// Minimum number of targets.
1081        min: u32,
1082        /// Maximum number of targets.
1083        max: u32,
1084    },
1085    /// Many sources to one target.
1086    ManyToOne {
1087        /// Minimum number of sources.
1088        min: u32,
1089        /// Maximum number of sources.
1090        max: u32,
1091    },
1092    /// Many sources to many targets.
1093    ManyToMany {
1094        /// Minimum targets per source.
1095        min_per_source: u32,
1096        /// Maximum targets per source.
1097        max_per_source: u32,
1098    },
1099}
1100
1101impl Default for CardinalitySchemaRule {
1102    fn default() -> Self {
1103        Self::OneToMany { min: 1, max: 5 }
1104    }
1105}
1106
1107/// Global configuration settings.
1108#[derive(Debug, Clone, Serialize, Deserialize)]
1109pub struct GlobalConfig {
1110    /// Random seed for reproducibility
1111    pub seed: Option<u64>,
1112    /// Industry sector
1113    pub industry: IndustrySector,
1114    /// Simulation start date (YYYY-MM-DD)
1115    pub start_date: String,
1116    /// Simulation period in months
1117    pub period_months: u32,
1118    /// Base currency for group reporting
1119    #[serde(default = "default_currency")]
1120    pub group_currency: String,
1121    /// Enable parallel generation
1122    #[serde(default = "default_true")]
1123    pub parallel: bool,
1124    /// Number of worker threads (0 = auto-detect)
1125    #[serde(default)]
1126    pub worker_threads: usize,
1127    /// Memory limit in MB (0 = unlimited)
1128    #[serde(default)]
1129    pub memory_limit_mb: usize,
1130}
1131
1132fn default_currency() -> String {
1133    "USD".to_string()
1134}
1135fn default_true() -> bool {
1136    true
1137}
1138
1139/// Company code configuration.
1140#[derive(Debug, Clone, Serialize, Deserialize)]
1141pub struct CompanyConfig {
1142    /// Company code identifier
1143    pub code: String,
1144    /// Company name
1145    pub name: String,
1146    /// Local currency (ISO 4217)
1147    pub currency: String,
1148    /// Country code (ISO 3166-1 alpha-2)
1149    pub country: String,
1150    /// Fiscal year variant
1151    #[serde(default = "default_fiscal_variant")]
1152    pub fiscal_year_variant: String,
1153    /// Transaction volume per year
1154    pub annual_transaction_volume: TransactionVolume,
1155    /// Company-specific transaction weight
1156    #[serde(default = "default_weight")]
1157    pub volume_weight: f64,
1158}
1159
1160fn default_fiscal_variant() -> String {
1161    "K4".to_string()
1162}
1163fn default_weight() -> f64 {
1164    1.0
1165}
1166
1167/// Transaction volume presets.
1168#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1169#[serde(rename_all = "snake_case")]
1170pub enum TransactionVolume {
1171    /// 10,000 transactions per year
1172    TenK,
1173    /// 100,000 transactions per year
1174    HundredK,
1175    /// 1,000,000 transactions per year
1176    OneM,
1177    /// 10,000,000 transactions per year
1178    TenM,
1179    /// 100,000,000 transactions per year
1180    HundredM,
1181    /// Custom count
1182    Custom(u64),
1183}
1184
1185impl TransactionVolume {
1186    /// Get the transaction count.
1187    pub fn count(&self) -> u64 {
1188        match self {
1189            Self::TenK => 10_000,
1190            Self::HundredK => 100_000,
1191            Self::OneM => 1_000_000,
1192            Self::TenM => 10_000_000,
1193            Self::HundredM => 100_000_000,
1194            Self::Custom(n) => *n,
1195        }
1196    }
1197}
1198
1199/// Chart of Accounts configuration.
1200#[derive(Debug, Clone, Serialize, Deserialize)]
1201pub struct ChartOfAccountsConfig {
1202    /// CoA complexity level
1203    pub complexity: CoAComplexity,
1204    /// Use industry-specific accounts
1205    #[serde(default = "default_true")]
1206    pub industry_specific: bool,
1207    /// Custom account definitions file
1208    pub custom_accounts: Option<PathBuf>,
1209    /// Minimum hierarchy depth
1210    #[serde(default = "default_min_depth")]
1211    pub min_hierarchy_depth: u8,
1212    /// Maximum hierarchy depth
1213    #[serde(default = "default_max_depth")]
1214    pub max_hierarchy_depth: u8,
1215}
1216
1217fn default_min_depth() -> u8 {
1218    2
1219}
1220fn default_max_depth() -> u8 {
1221    5
1222}
1223
1224impl Default for ChartOfAccountsConfig {
1225    fn default() -> Self {
1226        Self {
1227            complexity: CoAComplexity::Small,
1228            industry_specific: true,
1229            custom_accounts: None,
1230            min_hierarchy_depth: default_min_depth(),
1231            max_hierarchy_depth: default_max_depth(),
1232        }
1233    }
1234}
1235
1236/// Transaction generation configuration.
1237#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1238pub struct TransactionConfig {
1239    /// Line item distribution
1240    #[serde(default)]
1241    pub line_item_distribution: LineItemDistributionConfig,
1242    /// Debit/credit balance distribution
1243    #[serde(default)]
1244    pub debit_credit_distribution: DebitCreditDistributionConfig,
1245    /// Even/odd line count distribution
1246    #[serde(default)]
1247    pub even_odd_distribution: EvenOddDistributionConfig,
1248    /// Transaction source distribution
1249    #[serde(default)]
1250    pub source_distribution: SourceDistribution,
1251    /// Seasonality configuration
1252    #[serde(default)]
1253    pub seasonality: SeasonalityConfig,
1254    /// Amount distribution
1255    #[serde(default)]
1256    pub amounts: AmountDistributionConfig,
1257    /// Benford's Law compliance configuration
1258    #[serde(default)]
1259    pub benford: BenfordConfig,
1260}
1261
1262/// Benford's Law compliance configuration.
1263#[derive(Debug, Clone, Serialize, Deserialize)]
1264pub struct BenfordConfig {
1265    /// Enable Benford's Law compliance for amount generation
1266    #[serde(default = "default_true")]
1267    pub enabled: bool,
1268    /// Tolerance for deviation from ideal Benford distribution (0.0-1.0)
1269    #[serde(default = "default_benford_tolerance")]
1270    pub tolerance: f64,
1271    /// Transaction sources exempt from Benford's Law (fixed amounts)
1272    #[serde(default)]
1273    pub exempt_sources: Vec<BenfordExemption>,
1274}
1275
1276fn default_benford_tolerance() -> f64 {
1277    0.05
1278}
1279
1280impl Default for BenfordConfig {
1281    fn default() -> Self {
1282        Self {
1283            enabled: true,
1284            tolerance: default_benford_tolerance(),
1285            exempt_sources: vec![BenfordExemption::Recurring, BenfordExemption::Payroll],
1286        }
1287    }
1288}
1289
1290/// Types of transactions exempt from Benford's Law.
1291#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1292#[serde(rename_all = "snake_case")]
1293pub enum BenfordExemption {
1294    /// Recurring fixed amounts (rent, subscriptions)
1295    Recurring,
1296    /// Payroll (standardized salaries)
1297    Payroll,
1298    /// Fixed fees and charges
1299    FixedFees,
1300    /// Round number purchases (often legitimate)
1301    RoundAmounts,
1302}
1303
1304/// Distribution of transaction sources.
1305#[derive(Debug, Clone, Serialize, Deserialize)]
1306pub struct SourceDistribution {
1307    /// Manual entries percentage
1308    pub manual: f64,
1309    /// Automated system entries
1310    pub automated: f64,
1311    /// Recurring entries
1312    pub recurring: f64,
1313    /// Adjustment entries
1314    pub adjustment: f64,
1315}
1316
1317impl Default for SourceDistribution {
1318    fn default() -> Self {
1319        Self {
1320            manual: 0.20,
1321            automated: 0.70,
1322            recurring: 0.07,
1323            adjustment: 0.03,
1324        }
1325    }
1326}
1327
1328/// Output configuration.
1329#[derive(Debug, Clone, Serialize, Deserialize)]
1330pub struct OutputConfig {
1331    /// Output mode
1332    #[serde(default)]
1333    pub mode: OutputMode,
1334    /// Output directory
1335    pub output_directory: PathBuf,
1336    /// File formats to generate
1337    #[serde(default = "default_formats")]
1338    pub formats: Vec<FileFormat>,
1339    /// Compression settings
1340    #[serde(default)]
1341    pub compression: CompressionConfig,
1342    /// Batch size for writes
1343    #[serde(default = "default_batch_size")]
1344    pub batch_size: usize,
1345    /// Include ACDOCA format
1346    #[serde(default = "default_true")]
1347    pub include_acdoca: bool,
1348    /// Include BSEG format
1349    #[serde(default)]
1350    pub include_bseg: bool,
1351    /// Partition by fiscal period
1352    #[serde(default = "default_true")]
1353    pub partition_by_period: bool,
1354    /// Partition by company code
1355    #[serde(default)]
1356    pub partition_by_company: bool,
1357}
1358
1359fn default_formats() -> Vec<FileFormat> {
1360    vec![FileFormat::Parquet]
1361}
1362fn default_batch_size() -> usize {
1363    100_000
1364}
1365
1366impl Default for OutputConfig {
1367    fn default() -> Self {
1368        Self {
1369            mode: OutputMode::FlatFile,
1370            output_directory: PathBuf::from("./output"),
1371            formats: default_formats(),
1372            compression: CompressionConfig::default(),
1373            batch_size: default_batch_size(),
1374            include_acdoca: true,
1375            include_bseg: false,
1376            partition_by_period: true,
1377            partition_by_company: false,
1378        }
1379    }
1380}
1381
1382/// Output mode.
1383#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1384#[serde(rename_all = "snake_case")]
1385pub enum OutputMode {
1386    /// Stream records as generated
1387    Streaming,
1388    /// Write to flat files
1389    #[default]
1390    FlatFile,
1391    /// Both streaming and flat file
1392    Both,
1393}
1394
1395/// Supported file formats.
1396#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1397#[serde(rename_all = "snake_case")]
1398pub enum FileFormat {
1399    Csv,
1400    Parquet,
1401    Json,
1402    JsonLines,
1403}
1404
1405/// Compression configuration.
1406#[derive(Debug, Clone, Serialize, Deserialize)]
1407pub struct CompressionConfig {
1408    /// Enable compression
1409    #[serde(default = "default_true")]
1410    pub enabled: bool,
1411    /// Compression algorithm
1412    #[serde(default)]
1413    pub algorithm: CompressionAlgorithm,
1414    /// Compression level (1-9)
1415    #[serde(default = "default_compression_level")]
1416    pub level: u8,
1417}
1418
1419fn default_compression_level() -> u8 {
1420    3
1421}
1422
1423impl Default for CompressionConfig {
1424    fn default() -> Self {
1425        Self {
1426            enabled: true,
1427            algorithm: CompressionAlgorithm::default(),
1428            level: default_compression_level(),
1429        }
1430    }
1431}
1432
1433/// Compression algorithms.
1434#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1435#[serde(rename_all = "snake_case")]
1436pub enum CompressionAlgorithm {
1437    Gzip,
1438    #[default]
1439    Zstd,
1440    Lz4,
1441    Snappy,
1442}
1443
1444/// Fraud simulation configuration.
1445#[derive(Debug, Clone, Serialize, Deserialize)]
1446pub struct FraudConfig {
1447    /// Enable fraud scenario generation
1448    #[serde(default)]
1449    pub enabled: bool,
1450    /// Overall fraud rate (0.0 to 1.0)
1451    #[serde(default = "default_fraud_rate")]
1452    pub fraud_rate: f64,
1453    /// Fraud type distribution
1454    #[serde(default)]
1455    pub fraud_type_distribution: FraudTypeDistribution,
1456    /// Enable fraud clustering
1457    #[serde(default)]
1458    pub clustering_enabled: bool,
1459    /// Clustering factor
1460    #[serde(default = "default_clustering_factor")]
1461    pub clustering_factor: f64,
1462    /// Approval thresholds for threshold-adjacent fraud pattern
1463    #[serde(default = "default_approval_thresholds")]
1464    pub approval_thresholds: Vec<f64>,
1465}
1466
1467fn default_approval_thresholds() -> Vec<f64> {
1468    vec![1000.0, 5000.0, 10000.0, 25000.0, 50000.0, 100000.0]
1469}
1470
1471fn default_fraud_rate() -> f64 {
1472    0.005
1473}
1474fn default_clustering_factor() -> f64 {
1475    3.0
1476}
1477
1478impl Default for FraudConfig {
1479    fn default() -> Self {
1480        Self {
1481            enabled: false,
1482            fraud_rate: default_fraud_rate(),
1483            fraud_type_distribution: FraudTypeDistribution::default(),
1484            clustering_enabled: false,
1485            clustering_factor: default_clustering_factor(),
1486            approval_thresholds: default_approval_thresholds(),
1487        }
1488    }
1489}
1490
1491/// Distribution of fraud types.
1492#[derive(Debug, Clone, Serialize, Deserialize)]
1493pub struct FraudTypeDistribution {
1494    pub suspense_account_abuse: f64,
1495    pub fictitious_transaction: f64,
1496    pub revenue_manipulation: f64,
1497    pub expense_capitalization: f64,
1498    pub split_transaction: f64,
1499    pub timing_anomaly: f64,
1500    pub unauthorized_access: f64,
1501    pub duplicate_payment: f64,
1502}
1503
1504impl Default for FraudTypeDistribution {
1505    fn default() -> Self {
1506        Self {
1507            suspense_account_abuse: 0.25,
1508            fictitious_transaction: 0.15,
1509            revenue_manipulation: 0.10,
1510            expense_capitalization: 0.10,
1511            split_transaction: 0.15,
1512            timing_anomaly: 0.10,
1513            unauthorized_access: 0.10,
1514            duplicate_payment: 0.05,
1515        }
1516    }
1517}
1518
1519/// Internal Controls System (ICS) configuration.
1520#[derive(Debug, Clone, Serialize, Deserialize)]
1521pub struct InternalControlsConfig {
1522    /// Enable internal controls system
1523    #[serde(default)]
1524    pub enabled: bool,
1525    /// Rate at which controls result in exceptions (0.0 - 1.0)
1526    #[serde(default = "default_exception_rate")]
1527    pub exception_rate: f64,
1528    /// Rate at which SoD violations occur (0.0 - 1.0)
1529    #[serde(default = "default_sod_violation_rate")]
1530    pub sod_violation_rate: f64,
1531    /// Export control master data to separate files
1532    #[serde(default = "default_true")]
1533    pub export_control_master_data: bool,
1534    /// SOX materiality threshold for marking transactions as SOX-relevant
1535    #[serde(default = "default_sox_materiality_threshold")]
1536    pub sox_materiality_threshold: f64,
1537    /// Enable COSO 2013 framework integration
1538    #[serde(default = "default_true")]
1539    pub coso_enabled: bool,
1540    /// Include entity-level controls in generation
1541    #[serde(default)]
1542    pub include_entity_level_controls: bool,
1543    /// Target maturity level for controls
1544    /// Valid values: "ad_hoc", "repeatable", "defined", "managed", "optimized", "mixed"
1545    #[serde(default = "default_target_maturity_level")]
1546    pub target_maturity_level: String,
1547}
1548
1549fn default_exception_rate() -> f64 {
1550    0.02
1551}
1552
1553fn default_sod_violation_rate() -> f64 {
1554    0.01
1555}
1556
1557fn default_sox_materiality_threshold() -> f64 {
1558    10000.0
1559}
1560
1561fn default_target_maturity_level() -> String {
1562    "mixed".to_string()
1563}
1564
1565impl Default for InternalControlsConfig {
1566    fn default() -> Self {
1567        Self {
1568            enabled: false,
1569            exception_rate: default_exception_rate(),
1570            sod_violation_rate: default_sod_violation_rate(),
1571            export_control_master_data: true,
1572            sox_materiality_threshold: default_sox_materiality_threshold(),
1573            coso_enabled: true,
1574            include_entity_level_controls: false,
1575            target_maturity_level: default_target_maturity_level(),
1576        }
1577    }
1578}
1579
1580/// Business process configuration.
1581#[derive(Debug, Clone, Serialize, Deserialize)]
1582pub struct BusinessProcessConfig {
1583    /// Order-to-Cash weight
1584    #[serde(default = "default_o2c")]
1585    pub o2c_weight: f64,
1586    /// Procure-to-Pay weight
1587    #[serde(default = "default_p2p")]
1588    pub p2p_weight: f64,
1589    /// Record-to-Report weight
1590    #[serde(default = "default_r2r")]
1591    pub r2r_weight: f64,
1592    /// Hire-to-Retire weight
1593    #[serde(default = "default_h2r")]
1594    pub h2r_weight: f64,
1595    /// Acquire-to-Retire weight
1596    #[serde(default = "default_a2r")]
1597    pub a2r_weight: f64,
1598}
1599
1600fn default_o2c() -> f64 {
1601    0.35
1602}
1603fn default_p2p() -> f64 {
1604    0.30
1605}
1606fn default_r2r() -> f64 {
1607    0.20
1608}
1609fn default_h2r() -> f64 {
1610    0.10
1611}
1612fn default_a2r() -> f64 {
1613    0.05
1614}
1615
1616impl Default for BusinessProcessConfig {
1617    fn default() -> Self {
1618        Self {
1619            o2c_weight: default_o2c(),
1620            p2p_weight: default_p2p(),
1621            r2r_weight: default_r2r(),
1622            h2r_weight: default_h2r(),
1623            a2r_weight: default_a2r(),
1624        }
1625    }
1626}
1627
1628/// User persona configuration.
1629#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1630pub struct UserPersonaConfig {
1631    /// Distribution of user personas
1632    #[serde(default)]
1633    pub persona_distribution: PersonaDistribution,
1634    /// Users per persona type
1635    #[serde(default)]
1636    pub users_per_persona: UsersPerPersona,
1637}
1638
1639/// Distribution of user personas for transaction generation.
1640#[derive(Debug, Clone, Serialize, Deserialize)]
1641pub struct PersonaDistribution {
1642    pub junior_accountant: f64,
1643    pub senior_accountant: f64,
1644    pub controller: f64,
1645    pub manager: f64,
1646    pub automated_system: f64,
1647}
1648
1649impl Default for PersonaDistribution {
1650    fn default() -> Self {
1651        Self {
1652            junior_accountant: 0.15,
1653            senior_accountant: 0.15,
1654            controller: 0.05,
1655            manager: 0.05,
1656            automated_system: 0.60,
1657        }
1658    }
1659}
1660
1661/// Number of users per persona type.
1662#[derive(Debug, Clone, Serialize, Deserialize)]
1663pub struct UsersPerPersona {
1664    pub junior_accountant: usize,
1665    pub senior_accountant: usize,
1666    pub controller: usize,
1667    pub manager: usize,
1668    pub automated_system: usize,
1669}
1670
1671impl Default for UsersPerPersona {
1672    fn default() -> Self {
1673        Self {
1674            junior_accountant: 10,
1675            senior_accountant: 5,
1676            controller: 2,
1677            manager: 3,
1678            automated_system: 20,
1679        }
1680    }
1681}
1682
1683/// Template configuration for realistic data generation.
1684#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1685pub struct TemplateConfig {
1686    /// Name generation settings
1687    #[serde(default)]
1688    pub names: NameTemplateConfig,
1689    /// Description generation settings
1690    #[serde(default)]
1691    pub descriptions: DescriptionTemplateConfig,
1692    /// Reference number settings
1693    #[serde(default)]
1694    pub references: ReferenceTemplateConfig,
1695}
1696
1697/// Name template configuration.
1698#[derive(Debug, Clone, Serialize, Deserialize)]
1699pub struct NameTemplateConfig {
1700    /// Distribution of name cultures
1701    #[serde(default)]
1702    pub culture_distribution: CultureDistribution,
1703    /// Email domain for generated users
1704    #[serde(default = "default_email_domain")]
1705    pub email_domain: String,
1706    /// Generate realistic display names
1707    #[serde(default = "default_true")]
1708    pub generate_realistic_names: bool,
1709}
1710
1711fn default_email_domain() -> String {
1712    "company.com".to_string()
1713}
1714
1715impl Default for NameTemplateConfig {
1716    fn default() -> Self {
1717        Self {
1718            culture_distribution: CultureDistribution::default(),
1719            email_domain: default_email_domain(),
1720            generate_realistic_names: true,
1721        }
1722    }
1723}
1724
1725/// Distribution of name cultures for generation.
1726#[derive(Debug, Clone, Serialize, Deserialize)]
1727pub struct CultureDistribution {
1728    pub western_us: f64,
1729    pub hispanic: f64,
1730    pub german: f64,
1731    pub french: f64,
1732    pub chinese: f64,
1733    pub japanese: f64,
1734    pub indian: f64,
1735}
1736
1737impl Default for CultureDistribution {
1738    fn default() -> Self {
1739        Self {
1740            western_us: 0.40,
1741            hispanic: 0.20,
1742            german: 0.10,
1743            french: 0.05,
1744            chinese: 0.10,
1745            japanese: 0.05,
1746            indian: 0.10,
1747        }
1748    }
1749}
1750
1751/// Description template configuration.
1752#[derive(Debug, Clone, Serialize, Deserialize)]
1753pub struct DescriptionTemplateConfig {
1754    /// Generate header text for journal entries
1755    #[serde(default = "default_true")]
1756    pub generate_header_text: bool,
1757    /// Generate line text for journal entry lines
1758    #[serde(default = "default_true")]
1759    pub generate_line_text: bool,
1760}
1761
1762impl Default for DescriptionTemplateConfig {
1763    fn default() -> Self {
1764        Self {
1765            generate_header_text: true,
1766            generate_line_text: true,
1767        }
1768    }
1769}
1770
1771/// Reference number template configuration.
1772#[derive(Debug, Clone, Serialize, Deserialize)]
1773pub struct ReferenceTemplateConfig {
1774    /// Generate reference numbers
1775    #[serde(default = "default_true")]
1776    pub generate_references: bool,
1777    /// Invoice prefix
1778    #[serde(default = "default_invoice_prefix")]
1779    pub invoice_prefix: String,
1780    /// Purchase order prefix
1781    #[serde(default = "default_po_prefix")]
1782    pub po_prefix: String,
1783    /// Sales order prefix
1784    #[serde(default = "default_so_prefix")]
1785    pub so_prefix: String,
1786}
1787
1788fn default_invoice_prefix() -> String {
1789    "INV".to_string()
1790}
1791fn default_po_prefix() -> String {
1792    "PO".to_string()
1793}
1794fn default_so_prefix() -> String {
1795    "SO".to_string()
1796}
1797
1798impl Default for ReferenceTemplateConfig {
1799    fn default() -> Self {
1800        Self {
1801            generate_references: true,
1802            invoice_prefix: default_invoice_prefix(),
1803            po_prefix: default_po_prefix(),
1804            so_prefix: default_so_prefix(),
1805        }
1806    }
1807}
1808
1809/// Approval workflow configuration.
1810#[derive(Debug, Clone, Serialize, Deserialize)]
1811pub struct ApprovalConfig {
1812    /// Enable approval workflow generation
1813    #[serde(default)]
1814    pub enabled: bool,
1815    /// Threshold below which transactions are auto-approved
1816    #[serde(default = "default_auto_approve_threshold")]
1817    pub auto_approve_threshold: f64,
1818    /// Rate at which approvals are rejected (0.0 to 1.0)
1819    #[serde(default = "default_rejection_rate")]
1820    pub rejection_rate: f64,
1821    /// Rate at which approvals require revision (0.0 to 1.0)
1822    #[serde(default = "default_revision_rate")]
1823    pub revision_rate: f64,
1824    /// Average delay in hours for approval processing
1825    #[serde(default = "default_approval_delay_hours")]
1826    pub average_approval_delay_hours: f64,
1827    /// Approval chain thresholds
1828    #[serde(default)]
1829    pub thresholds: Vec<ApprovalThresholdConfig>,
1830}
1831
1832fn default_auto_approve_threshold() -> f64 {
1833    1000.0
1834}
1835fn default_rejection_rate() -> f64 {
1836    0.02
1837}
1838fn default_revision_rate() -> f64 {
1839    0.05
1840}
1841fn default_approval_delay_hours() -> f64 {
1842    4.0
1843}
1844
1845impl Default for ApprovalConfig {
1846    fn default() -> Self {
1847        Self {
1848            enabled: false,
1849            auto_approve_threshold: default_auto_approve_threshold(),
1850            rejection_rate: default_rejection_rate(),
1851            revision_rate: default_revision_rate(),
1852            average_approval_delay_hours: default_approval_delay_hours(),
1853            thresholds: vec![
1854                ApprovalThresholdConfig {
1855                    amount: 1000.0,
1856                    level: 1,
1857                    roles: vec!["senior_accountant".to_string()],
1858                },
1859                ApprovalThresholdConfig {
1860                    amount: 10000.0,
1861                    level: 2,
1862                    roles: vec!["senior_accountant".to_string(), "controller".to_string()],
1863                },
1864                ApprovalThresholdConfig {
1865                    amount: 100000.0,
1866                    level: 3,
1867                    roles: vec![
1868                        "senior_accountant".to_string(),
1869                        "controller".to_string(),
1870                        "manager".to_string(),
1871                    ],
1872                },
1873                ApprovalThresholdConfig {
1874                    amount: 500000.0,
1875                    level: 4,
1876                    roles: vec![
1877                        "senior_accountant".to_string(),
1878                        "controller".to_string(),
1879                        "manager".to_string(),
1880                        "executive".to_string(),
1881                    ],
1882                },
1883            ],
1884        }
1885    }
1886}
1887
1888/// Configuration for a single approval threshold.
1889#[derive(Debug, Clone, Serialize, Deserialize)]
1890pub struct ApprovalThresholdConfig {
1891    /// Amount threshold
1892    pub amount: f64,
1893    /// Approval level required
1894    pub level: u8,
1895    /// Roles that can approve at this level
1896    pub roles: Vec<String>,
1897}
1898
1899/// Department configuration.
1900#[derive(Debug, Clone, Serialize, Deserialize)]
1901pub struct DepartmentConfig {
1902    /// Enable department assignment
1903    #[serde(default)]
1904    pub enabled: bool,
1905    /// Multiplier for department headcounts
1906    #[serde(default = "default_headcount_multiplier")]
1907    pub headcount_multiplier: f64,
1908    /// Custom department definitions (optional)
1909    #[serde(default)]
1910    pub custom_departments: Vec<CustomDepartmentConfig>,
1911}
1912
1913fn default_headcount_multiplier() -> f64 {
1914    1.0
1915}
1916
1917impl Default for DepartmentConfig {
1918    fn default() -> Self {
1919        Self {
1920            enabled: false,
1921            headcount_multiplier: default_headcount_multiplier(),
1922            custom_departments: Vec::new(),
1923        }
1924    }
1925}
1926
1927/// Custom department definition.
1928#[derive(Debug, Clone, Serialize, Deserialize)]
1929pub struct CustomDepartmentConfig {
1930    /// Department code
1931    pub code: String,
1932    /// Department name
1933    pub name: String,
1934    /// Associated cost center
1935    #[serde(default)]
1936    pub cost_center: Option<String>,
1937    /// Primary business processes
1938    #[serde(default)]
1939    pub primary_processes: Vec<String>,
1940    /// Parent department code
1941    #[serde(default)]
1942    pub parent_code: Option<String>,
1943}
1944
1945// ============================================================================
1946// Master Data Configuration
1947// ============================================================================
1948
1949/// Master data generation configuration.
1950#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1951pub struct MasterDataConfig {
1952    /// Vendor master data settings
1953    #[serde(default)]
1954    pub vendors: VendorMasterConfig,
1955    /// Customer master data settings
1956    #[serde(default)]
1957    pub customers: CustomerMasterConfig,
1958    /// Material master data settings
1959    #[serde(default)]
1960    pub materials: MaterialMasterConfig,
1961    /// Fixed asset master data settings
1962    #[serde(default)]
1963    pub fixed_assets: FixedAssetMasterConfig,
1964    /// Employee master data settings
1965    #[serde(default)]
1966    pub employees: EmployeeMasterConfig,
1967    /// Cost center master data settings
1968    #[serde(default)]
1969    pub cost_centers: CostCenterMasterConfig,
1970}
1971
1972/// Vendor master data configuration.
1973#[derive(Debug, Clone, Serialize, Deserialize)]
1974pub struct VendorMasterConfig {
1975    /// Number of vendors to generate
1976    #[serde(default = "default_vendor_count")]
1977    pub count: usize,
1978    /// Percentage of vendors that are intercompany (0.0 to 1.0)
1979    #[serde(default = "default_intercompany_percent")]
1980    pub intercompany_percent: f64,
1981    /// Payment terms distribution
1982    #[serde(default)]
1983    pub payment_terms_distribution: PaymentTermsDistribution,
1984    /// Vendor behavior distribution
1985    #[serde(default)]
1986    pub behavior_distribution: VendorBehaviorDistribution,
1987    /// Generate bank account details
1988    #[serde(default = "default_true")]
1989    pub generate_bank_accounts: bool,
1990    /// Generate tax IDs
1991    #[serde(default = "default_true")]
1992    pub generate_tax_ids: bool,
1993}
1994
1995fn default_vendor_count() -> usize {
1996    500
1997}
1998
1999fn default_intercompany_percent() -> f64 {
2000    0.05
2001}
2002
2003impl Default for VendorMasterConfig {
2004    fn default() -> Self {
2005        Self {
2006            count: default_vendor_count(),
2007            intercompany_percent: default_intercompany_percent(),
2008            payment_terms_distribution: PaymentTermsDistribution::default(),
2009            behavior_distribution: VendorBehaviorDistribution::default(),
2010            generate_bank_accounts: true,
2011            generate_tax_ids: true,
2012        }
2013    }
2014}
2015
2016/// Payment terms distribution for vendors.
2017#[derive(Debug, Clone, Serialize, Deserialize)]
2018pub struct PaymentTermsDistribution {
2019    /// Net 30 days
2020    pub net_30: f64,
2021    /// Net 60 days
2022    pub net_60: f64,
2023    /// Net 90 days
2024    pub net_90: f64,
2025    /// 2% 10 Net 30 (early payment discount)
2026    pub two_ten_net_30: f64,
2027    /// Due on receipt
2028    pub due_on_receipt: f64,
2029    /// End of month
2030    pub end_of_month: f64,
2031}
2032
2033impl Default for PaymentTermsDistribution {
2034    fn default() -> Self {
2035        Self {
2036            net_30: 0.40,
2037            net_60: 0.20,
2038            net_90: 0.10,
2039            two_ten_net_30: 0.15,
2040            due_on_receipt: 0.05,
2041            end_of_month: 0.10,
2042        }
2043    }
2044}
2045
2046/// Vendor behavior distribution.
2047#[derive(Debug, Clone, Serialize, Deserialize)]
2048pub struct VendorBehaviorDistribution {
2049    /// Reliable vendors (consistent delivery, quality)
2050    pub reliable: f64,
2051    /// Sometimes late vendors
2052    pub sometimes_late: f64,
2053    /// Inconsistent quality vendors
2054    pub inconsistent_quality: f64,
2055    /// Premium vendors (high quality, premium pricing)
2056    pub premium: f64,
2057    /// Budget vendors (lower quality, lower pricing)
2058    pub budget: f64,
2059}
2060
2061impl Default for VendorBehaviorDistribution {
2062    fn default() -> Self {
2063        Self {
2064            reliable: 0.50,
2065            sometimes_late: 0.20,
2066            inconsistent_quality: 0.10,
2067            premium: 0.10,
2068            budget: 0.10,
2069        }
2070    }
2071}
2072
2073/// Customer master data configuration.
2074#[derive(Debug, Clone, Serialize, Deserialize)]
2075pub struct CustomerMasterConfig {
2076    /// Number of customers to generate
2077    #[serde(default = "default_customer_count")]
2078    pub count: usize,
2079    /// Percentage of customers that are intercompany (0.0 to 1.0)
2080    #[serde(default = "default_intercompany_percent")]
2081    pub intercompany_percent: f64,
2082    /// Credit rating distribution
2083    #[serde(default)]
2084    pub credit_rating_distribution: CreditRatingDistribution,
2085    /// Payment behavior distribution
2086    #[serde(default)]
2087    pub payment_behavior_distribution: PaymentBehaviorDistribution,
2088    /// Generate credit limits based on rating
2089    #[serde(default = "default_true")]
2090    pub generate_credit_limits: bool,
2091}
2092
2093fn default_customer_count() -> usize {
2094    2000
2095}
2096
2097impl Default for CustomerMasterConfig {
2098    fn default() -> Self {
2099        Self {
2100            count: default_customer_count(),
2101            intercompany_percent: default_intercompany_percent(),
2102            credit_rating_distribution: CreditRatingDistribution::default(),
2103            payment_behavior_distribution: PaymentBehaviorDistribution::default(),
2104            generate_credit_limits: true,
2105        }
2106    }
2107}
2108
2109/// Credit rating distribution for customers.
2110#[derive(Debug, Clone, Serialize, Deserialize)]
2111pub struct CreditRatingDistribution {
2112    /// AAA rating
2113    pub aaa: f64,
2114    /// AA rating
2115    pub aa: f64,
2116    /// A rating
2117    pub a: f64,
2118    /// BBB rating
2119    pub bbb: f64,
2120    /// BB rating
2121    pub bb: f64,
2122    /// B rating
2123    pub b: f64,
2124    /// Below B rating
2125    pub below_b: f64,
2126}
2127
2128impl Default for CreditRatingDistribution {
2129    fn default() -> Self {
2130        Self {
2131            aaa: 0.05,
2132            aa: 0.10,
2133            a: 0.20,
2134            bbb: 0.30,
2135            bb: 0.20,
2136            b: 0.10,
2137            below_b: 0.05,
2138        }
2139    }
2140}
2141
2142/// Payment behavior distribution for customers.
2143#[derive(Debug, Clone, Serialize, Deserialize)]
2144pub struct PaymentBehaviorDistribution {
2145    /// Always pays early
2146    pub early_payer: f64,
2147    /// Pays on time
2148    pub on_time: f64,
2149    /// Occasionally late
2150    pub occasional_late: f64,
2151    /// Frequently late
2152    pub frequent_late: f64,
2153    /// Takes early payment discounts
2154    pub discount_taker: f64,
2155}
2156
2157impl Default for PaymentBehaviorDistribution {
2158    fn default() -> Self {
2159        Self {
2160            early_payer: 0.10,
2161            on_time: 0.50,
2162            occasional_late: 0.25,
2163            frequent_late: 0.10,
2164            discount_taker: 0.05,
2165        }
2166    }
2167}
2168
2169/// Material master data configuration.
2170#[derive(Debug, Clone, Serialize, Deserialize)]
2171pub struct MaterialMasterConfig {
2172    /// Number of materials to generate
2173    #[serde(default = "default_material_count")]
2174    pub count: usize,
2175    /// Material type distribution
2176    #[serde(default)]
2177    pub type_distribution: MaterialTypeDistribution,
2178    /// Valuation method distribution
2179    #[serde(default)]
2180    pub valuation_distribution: ValuationMethodDistribution,
2181    /// Percentage of materials with BOM (bill of materials)
2182    #[serde(default = "default_bom_percent")]
2183    pub bom_percent: f64,
2184    /// Maximum BOM depth
2185    #[serde(default = "default_max_bom_depth")]
2186    pub max_bom_depth: u8,
2187}
2188
2189fn default_material_count() -> usize {
2190    5000
2191}
2192
2193fn default_bom_percent() -> f64 {
2194    0.20
2195}
2196
2197fn default_max_bom_depth() -> u8 {
2198    3
2199}
2200
2201impl Default for MaterialMasterConfig {
2202    fn default() -> Self {
2203        Self {
2204            count: default_material_count(),
2205            type_distribution: MaterialTypeDistribution::default(),
2206            valuation_distribution: ValuationMethodDistribution::default(),
2207            bom_percent: default_bom_percent(),
2208            max_bom_depth: default_max_bom_depth(),
2209        }
2210    }
2211}
2212
2213/// Material type distribution.
2214#[derive(Debug, Clone, Serialize, Deserialize)]
2215pub struct MaterialTypeDistribution {
2216    /// Raw materials
2217    pub raw_material: f64,
2218    /// Semi-finished goods
2219    pub semi_finished: f64,
2220    /// Finished goods
2221    pub finished_good: f64,
2222    /// Trading goods (purchased for resale)
2223    pub trading_good: f64,
2224    /// Operating supplies
2225    pub operating_supply: f64,
2226    /// Services
2227    pub service: f64,
2228}
2229
2230impl Default for MaterialTypeDistribution {
2231    fn default() -> Self {
2232        Self {
2233            raw_material: 0.30,
2234            semi_finished: 0.15,
2235            finished_good: 0.25,
2236            trading_good: 0.15,
2237            operating_supply: 0.10,
2238            service: 0.05,
2239        }
2240    }
2241}
2242
2243/// Valuation method distribution for materials.
2244#[derive(Debug, Clone, Serialize, Deserialize)]
2245pub struct ValuationMethodDistribution {
2246    /// Standard cost
2247    pub standard_cost: f64,
2248    /// Moving average
2249    pub moving_average: f64,
2250    /// FIFO (First In, First Out)
2251    pub fifo: f64,
2252    /// LIFO (Last In, First Out)
2253    pub lifo: f64,
2254}
2255
2256impl Default for ValuationMethodDistribution {
2257    fn default() -> Self {
2258        Self {
2259            standard_cost: 0.50,
2260            moving_average: 0.30,
2261            fifo: 0.15,
2262            lifo: 0.05,
2263        }
2264    }
2265}
2266
2267/// Fixed asset master data configuration.
2268#[derive(Debug, Clone, Serialize, Deserialize)]
2269pub struct FixedAssetMasterConfig {
2270    /// Number of fixed assets to generate
2271    #[serde(default = "default_asset_count")]
2272    pub count: usize,
2273    /// Asset class distribution
2274    #[serde(default)]
2275    pub class_distribution: AssetClassDistribution,
2276    /// Depreciation method distribution
2277    #[serde(default)]
2278    pub depreciation_distribution: DepreciationMethodDistribution,
2279    /// Percentage of assets that are fully depreciated
2280    #[serde(default = "default_fully_depreciated_percent")]
2281    pub fully_depreciated_percent: f64,
2282    /// Generate acquisition history
2283    #[serde(default = "default_true")]
2284    pub generate_acquisition_history: bool,
2285}
2286
2287fn default_asset_count() -> usize {
2288    800
2289}
2290
2291fn default_fully_depreciated_percent() -> f64 {
2292    0.15
2293}
2294
2295impl Default for FixedAssetMasterConfig {
2296    fn default() -> Self {
2297        Self {
2298            count: default_asset_count(),
2299            class_distribution: AssetClassDistribution::default(),
2300            depreciation_distribution: DepreciationMethodDistribution::default(),
2301            fully_depreciated_percent: default_fully_depreciated_percent(),
2302            generate_acquisition_history: true,
2303        }
2304    }
2305}
2306
2307/// Asset class distribution.
2308#[derive(Debug, Clone, Serialize, Deserialize)]
2309pub struct AssetClassDistribution {
2310    /// Buildings and structures
2311    pub buildings: f64,
2312    /// Machinery and equipment
2313    pub machinery: f64,
2314    /// Vehicles
2315    pub vehicles: f64,
2316    /// IT equipment
2317    pub it_equipment: f64,
2318    /// Furniture and fixtures
2319    pub furniture: f64,
2320    /// Land (non-depreciable)
2321    pub land: f64,
2322    /// Leasehold improvements
2323    pub leasehold: f64,
2324}
2325
2326impl Default for AssetClassDistribution {
2327    fn default() -> Self {
2328        Self {
2329            buildings: 0.15,
2330            machinery: 0.30,
2331            vehicles: 0.15,
2332            it_equipment: 0.20,
2333            furniture: 0.10,
2334            land: 0.05,
2335            leasehold: 0.05,
2336        }
2337    }
2338}
2339
2340/// Depreciation method distribution.
2341#[derive(Debug, Clone, Serialize, Deserialize)]
2342pub struct DepreciationMethodDistribution {
2343    /// Straight line
2344    pub straight_line: f64,
2345    /// Declining balance
2346    pub declining_balance: f64,
2347    /// Double declining balance
2348    pub double_declining: f64,
2349    /// Sum of years' digits
2350    pub sum_of_years: f64,
2351    /// Units of production
2352    pub units_of_production: f64,
2353}
2354
2355impl Default for DepreciationMethodDistribution {
2356    fn default() -> Self {
2357        Self {
2358            straight_line: 0.60,
2359            declining_balance: 0.20,
2360            double_declining: 0.10,
2361            sum_of_years: 0.05,
2362            units_of_production: 0.05,
2363        }
2364    }
2365}
2366
2367/// Employee master data configuration.
2368#[derive(Debug, Clone, Serialize, Deserialize)]
2369pub struct EmployeeMasterConfig {
2370    /// Number of employees to generate
2371    #[serde(default = "default_employee_count")]
2372    pub count: usize,
2373    /// Generate organizational hierarchy
2374    #[serde(default = "default_true")]
2375    pub generate_hierarchy: bool,
2376    /// Maximum hierarchy depth
2377    #[serde(default = "default_hierarchy_depth")]
2378    pub max_hierarchy_depth: u8,
2379    /// Average span of control (direct reports per manager)
2380    #[serde(default = "default_span_of_control")]
2381    pub average_span_of_control: f64,
2382    /// Approval limit distribution by job level
2383    #[serde(default)]
2384    pub approval_limits: ApprovalLimitDistribution,
2385    /// Department distribution
2386    #[serde(default)]
2387    pub department_distribution: EmployeeDepartmentDistribution,
2388}
2389
2390fn default_employee_count() -> usize {
2391    1500
2392}
2393
2394fn default_hierarchy_depth() -> u8 {
2395    6
2396}
2397
2398fn default_span_of_control() -> f64 {
2399    5.0
2400}
2401
2402impl Default for EmployeeMasterConfig {
2403    fn default() -> Self {
2404        Self {
2405            count: default_employee_count(),
2406            generate_hierarchy: true,
2407            max_hierarchy_depth: default_hierarchy_depth(),
2408            average_span_of_control: default_span_of_control(),
2409            approval_limits: ApprovalLimitDistribution::default(),
2410            department_distribution: EmployeeDepartmentDistribution::default(),
2411        }
2412    }
2413}
2414
2415/// Approval limit distribution by job level.
2416#[derive(Debug, Clone, Serialize, Deserialize)]
2417pub struct ApprovalLimitDistribution {
2418    /// Staff level approval limit
2419    #[serde(default = "default_staff_limit")]
2420    pub staff: f64,
2421    /// Senior staff approval limit
2422    #[serde(default = "default_senior_limit")]
2423    pub senior: f64,
2424    /// Manager approval limit
2425    #[serde(default = "default_manager_limit")]
2426    pub manager: f64,
2427    /// Director approval limit
2428    #[serde(default = "default_director_limit")]
2429    pub director: f64,
2430    /// VP approval limit
2431    #[serde(default = "default_vp_limit")]
2432    pub vp: f64,
2433    /// Executive approval limit
2434    #[serde(default = "default_executive_limit")]
2435    pub executive: f64,
2436}
2437
2438fn default_staff_limit() -> f64 {
2439    1000.0
2440}
2441fn default_senior_limit() -> f64 {
2442    5000.0
2443}
2444fn default_manager_limit() -> f64 {
2445    25000.0
2446}
2447fn default_director_limit() -> f64 {
2448    100000.0
2449}
2450fn default_vp_limit() -> f64 {
2451    500000.0
2452}
2453fn default_executive_limit() -> f64 {
2454    f64::INFINITY
2455}
2456
2457impl Default for ApprovalLimitDistribution {
2458    fn default() -> Self {
2459        Self {
2460            staff: default_staff_limit(),
2461            senior: default_senior_limit(),
2462            manager: default_manager_limit(),
2463            director: default_director_limit(),
2464            vp: default_vp_limit(),
2465            executive: default_executive_limit(),
2466        }
2467    }
2468}
2469
2470/// Employee distribution across departments.
2471#[derive(Debug, Clone, Serialize, Deserialize)]
2472pub struct EmployeeDepartmentDistribution {
2473    /// Finance and Accounting
2474    pub finance: f64,
2475    /// Procurement
2476    pub procurement: f64,
2477    /// Sales
2478    pub sales: f64,
2479    /// Warehouse and Logistics
2480    pub warehouse: f64,
2481    /// IT
2482    pub it: f64,
2483    /// Human Resources
2484    pub hr: f64,
2485    /// Operations
2486    pub operations: f64,
2487    /// Executive
2488    pub executive: f64,
2489}
2490
2491impl Default for EmployeeDepartmentDistribution {
2492    fn default() -> Self {
2493        Self {
2494            finance: 0.12,
2495            procurement: 0.10,
2496            sales: 0.25,
2497            warehouse: 0.15,
2498            it: 0.10,
2499            hr: 0.05,
2500            operations: 0.20,
2501            executive: 0.03,
2502        }
2503    }
2504}
2505
2506/// Cost center master data configuration.
2507#[derive(Debug, Clone, Serialize, Deserialize)]
2508pub struct CostCenterMasterConfig {
2509    /// Number of cost centers to generate
2510    #[serde(default = "default_cost_center_count")]
2511    pub count: usize,
2512    /// Generate cost center hierarchy
2513    #[serde(default = "default_true")]
2514    pub generate_hierarchy: bool,
2515    /// Maximum hierarchy depth
2516    #[serde(default = "default_cc_hierarchy_depth")]
2517    pub max_hierarchy_depth: u8,
2518}
2519
2520fn default_cost_center_count() -> usize {
2521    50
2522}
2523
2524fn default_cc_hierarchy_depth() -> u8 {
2525    3
2526}
2527
2528impl Default for CostCenterMasterConfig {
2529    fn default() -> Self {
2530        Self {
2531            count: default_cost_center_count(),
2532            generate_hierarchy: true,
2533            max_hierarchy_depth: default_cc_hierarchy_depth(),
2534        }
2535    }
2536}
2537
2538// ============================================================================
2539// Document Flow Configuration
2540// ============================================================================
2541
2542/// Document flow generation configuration.
2543#[derive(Debug, Clone, Serialize, Deserialize)]
2544pub struct DocumentFlowConfig {
2545    /// P2P (Procure-to-Pay) flow configuration
2546    #[serde(default)]
2547    pub p2p: P2PFlowConfig,
2548    /// O2C (Order-to-Cash) flow configuration
2549    #[serde(default)]
2550    pub o2c: O2CFlowConfig,
2551    /// Generate document reference chains
2552    #[serde(default = "default_true")]
2553    pub generate_document_references: bool,
2554    /// Export document flow graph
2555    #[serde(default)]
2556    pub export_flow_graph: bool,
2557}
2558
2559impl Default for DocumentFlowConfig {
2560    fn default() -> Self {
2561        Self {
2562            p2p: P2PFlowConfig::default(),
2563            o2c: O2CFlowConfig::default(),
2564            generate_document_references: true,
2565            export_flow_graph: false,
2566        }
2567    }
2568}
2569
2570/// P2P (Procure-to-Pay) flow configuration.
2571#[derive(Debug, Clone, Serialize, Deserialize)]
2572pub struct P2PFlowConfig {
2573    /// Enable P2P document flow generation
2574    #[serde(default = "default_true")]
2575    pub enabled: bool,
2576    /// Three-way match success rate (PO-GR-Invoice)
2577    #[serde(default = "default_three_way_match_rate")]
2578    pub three_way_match_rate: f64,
2579    /// Rate of partial deliveries
2580    #[serde(default = "default_partial_delivery_rate")]
2581    pub partial_delivery_rate: f64,
2582    /// Rate of price variances between PO and Invoice
2583    #[serde(default = "default_price_variance_rate")]
2584    pub price_variance_rate: f64,
2585    /// Maximum price variance percentage
2586    #[serde(default = "default_max_price_variance")]
2587    pub max_price_variance_percent: f64,
2588    /// Rate of quantity variances between PO/GR and Invoice
2589    #[serde(default = "default_quantity_variance_rate")]
2590    pub quantity_variance_rate: f64,
2591    /// Average days from PO to goods receipt
2592    #[serde(default = "default_po_to_gr_days")]
2593    pub average_po_to_gr_days: u32,
2594    /// Average days from GR to invoice
2595    #[serde(default = "default_gr_to_invoice_days")]
2596    pub average_gr_to_invoice_days: u32,
2597    /// Average days from invoice to payment
2598    #[serde(default = "default_invoice_to_payment_days")]
2599    pub average_invoice_to_payment_days: u32,
2600    /// PO line count distribution
2601    #[serde(default)]
2602    pub line_count_distribution: DocumentLineCountDistribution,
2603    /// Payment behavior configuration
2604    #[serde(default)]
2605    pub payment_behavior: P2PPaymentBehaviorConfig,
2606}
2607
2608fn default_three_way_match_rate() -> f64 {
2609    0.95
2610}
2611
2612fn default_partial_delivery_rate() -> f64 {
2613    0.15
2614}
2615
2616fn default_price_variance_rate() -> f64 {
2617    0.08
2618}
2619
2620fn default_max_price_variance() -> f64 {
2621    0.05
2622}
2623
2624fn default_quantity_variance_rate() -> f64 {
2625    0.05
2626}
2627
2628fn default_po_to_gr_days() -> u32 {
2629    14
2630}
2631
2632fn default_gr_to_invoice_days() -> u32 {
2633    5
2634}
2635
2636fn default_invoice_to_payment_days() -> u32 {
2637    30
2638}
2639
2640impl Default for P2PFlowConfig {
2641    fn default() -> Self {
2642        Self {
2643            enabled: true,
2644            three_way_match_rate: default_three_way_match_rate(),
2645            partial_delivery_rate: default_partial_delivery_rate(),
2646            price_variance_rate: default_price_variance_rate(),
2647            max_price_variance_percent: default_max_price_variance(),
2648            quantity_variance_rate: default_quantity_variance_rate(),
2649            average_po_to_gr_days: default_po_to_gr_days(),
2650            average_gr_to_invoice_days: default_gr_to_invoice_days(),
2651            average_invoice_to_payment_days: default_invoice_to_payment_days(),
2652            line_count_distribution: DocumentLineCountDistribution::default(),
2653            payment_behavior: P2PPaymentBehaviorConfig::default(),
2654        }
2655    }
2656}
2657
2658// ============================================================================
2659// P2P Payment Behavior Configuration
2660// ============================================================================
2661
2662/// P2P payment behavior configuration.
2663#[derive(Debug, Clone, Serialize, Deserialize)]
2664pub struct P2PPaymentBehaviorConfig {
2665    /// Rate of late payments (beyond due date)
2666    #[serde(default = "default_p2p_late_payment_rate")]
2667    pub late_payment_rate: f64,
2668    /// Distribution of late payment days
2669    #[serde(default)]
2670    pub late_payment_days_distribution: LatePaymentDaysDistribution,
2671    /// Rate of partial payments
2672    #[serde(default = "default_p2p_partial_payment_rate")]
2673    pub partial_payment_rate: f64,
2674    /// Rate of payment corrections (NSF, chargebacks, reversals)
2675    #[serde(default = "default_p2p_payment_correction_rate")]
2676    pub payment_correction_rate: f64,
2677}
2678
2679fn default_p2p_late_payment_rate() -> f64 {
2680    0.15
2681}
2682
2683fn default_p2p_partial_payment_rate() -> f64 {
2684    0.05
2685}
2686
2687fn default_p2p_payment_correction_rate() -> f64 {
2688    0.02
2689}
2690
2691impl Default for P2PPaymentBehaviorConfig {
2692    fn default() -> Self {
2693        Self {
2694            late_payment_rate: default_p2p_late_payment_rate(),
2695            late_payment_days_distribution: LatePaymentDaysDistribution::default(),
2696            partial_payment_rate: default_p2p_partial_payment_rate(),
2697            payment_correction_rate: default_p2p_payment_correction_rate(),
2698        }
2699    }
2700}
2701
2702/// Distribution of late payment days for P2P.
2703#[derive(Debug, Clone, Serialize, Deserialize)]
2704pub struct LatePaymentDaysDistribution {
2705    /// 1-7 days late (slightly late)
2706    #[serde(default = "default_slightly_late")]
2707    pub slightly_late_1_to_7: f64,
2708    /// 8-14 days late
2709    #[serde(default = "default_late_8_14")]
2710    pub late_8_to_14: f64,
2711    /// 15-30 days late (very late)
2712    #[serde(default = "default_very_late")]
2713    pub very_late_15_to_30: f64,
2714    /// 31-60 days late (severely late)
2715    #[serde(default = "default_severely_late")]
2716    pub severely_late_31_to_60: f64,
2717    /// Over 60 days late (extremely late)
2718    #[serde(default = "default_extremely_late")]
2719    pub extremely_late_over_60: f64,
2720}
2721
2722fn default_slightly_late() -> f64 {
2723    0.50
2724}
2725
2726fn default_late_8_14() -> f64 {
2727    0.25
2728}
2729
2730fn default_very_late() -> f64 {
2731    0.15
2732}
2733
2734fn default_severely_late() -> f64 {
2735    0.07
2736}
2737
2738fn default_extremely_late() -> f64 {
2739    0.03
2740}
2741
2742impl Default for LatePaymentDaysDistribution {
2743    fn default() -> Self {
2744        Self {
2745            slightly_late_1_to_7: default_slightly_late(),
2746            late_8_to_14: default_late_8_14(),
2747            very_late_15_to_30: default_very_late(),
2748            severely_late_31_to_60: default_severely_late(),
2749            extremely_late_over_60: default_extremely_late(),
2750        }
2751    }
2752}
2753
2754/// O2C (Order-to-Cash) flow configuration.
2755#[derive(Debug, Clone, Serialize, Deserialize)]
2756pub struct O2CFlowConfig {
2757    /// Enable O2C document flow generation
2758    #[serde(default = "default_true")]
2759    pub enabled: bool,
2760    /// Credit check failure rate
2761    #[serde(default = "default_credit_check_failure_rate")]
2762    pub credit_check_failure_rate: f64,
2763    /// Rate of partial shipments
2764    #[serde(default = "default_partial_shipment_rate")]
2765    pub partial_shipment_rate: f64,
2766    /// Rate of returns
2767    #[serde(default = "default_return_rate")]
2768    pub return_rate: f64,
2769    /// Bad debt write-off rate
2770    #[serde(default = "default_bad_debt_rate")]
2771    pub bad_debt_rate: f64,
2772    /// Average days from SO to delivery
2773    #[serde(default = "default_so_to_delivery_days")]
2774    pub average_so_to_delivery_days: u32,
2775    /// Average days from delivery to invoice
2776    #[serde(default = "default_delivery_to_invoice_days")]
2777    pub average_delivery_to_invoice_days: u32,
2778    /// Average days from invoice to receipt
2779    #[serde(default = "default_invoice_to_receipt_days")]
2780    pub average_invoice_to_receipt_days: u32,
2781    /// SO line count distribution
2782    #[serde(default)]
2783    pub line_count_distribution: DocumentLineCountDistribution,
2784    /// Cash discount configuration
2785    #[serde(default)]
2786    pub cash_discount: CashDiscountConfig,
2787    /// Payment behavior configuration
2788    #[serde(default)]
2789    pub payment_behavior: O2CPaymentBehaviorConfig,
2790}
2791
2792fn default_credit_check_failure_rate() -> f64 {
2793    0.02
2794}
2795
2796fn default_partial_shipment_rate() -> f64 {
2797    0.10
2798}
2799
2800fn default_return_rate() -> f64 {
2801    0.03
2802}
2803
2804fn default_bad_debt_rate() -> f64 {
2805    0.01
2806}
2807
2808fn default_so_to_delivery_days() -> u32 {
2809    7
2810}
2811
2812fn default_delivery_to_invoice_days() -> u32 {
2813    1
2814}
2815
2816fn default_invoice_to_receipt_days() -> u32 {
2817    45
2818}
2819
2820impl Default for O2CFlowConfig {
2821    fn default() -> Self {
2822        Self {
2823            enabled: true,
2824            credit_check_failure_rate: default_credit_check_failure_rate(),
2825            partial_shipment_rate: default_partial_shipment_rate(),
2826            return_rate: default_return_rate(),
2827            bad_debt_rate: default_bad_debt_rate(),
2828            average_so_to_delivery_days: default_so_to_delivery_days(),
2829            average_delivery_to_invoice_days: default_delivery_to_invoice_days(),
2830            average_invoice_to_receipt_days: default_invoice_to_receipt_days(),
2831            line_count_distribution: DocumentLineCountDistribution::default(),
2832            cash_discount: CashDiscountConfig::default(),
2833            payment_behavior: O2CPaymentBehaviorConfig::default(),
2834        }
2835    }
2836}
2837
2838// ============================================================================
2839// O2C Payment Behavior Configuration
2840// ============================================================================
2841
2842/// O2C payment behavior configuration.
2843#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2844pub struct O2CPaymentBehaviorConfig {
2845    /// Dunning (Mahnung) configuration
2846    #[serde(default)]
2847    pub dunning: DunningConfig,
2848    /// Partial payment configuration
2849    #[serde(default)]
2850    pub partial_payments: PartialPaymentConfig,
2851    /// Short payment configuration (unauthorized deductions)
2852    #[serde(default)]
2853    pub short_payments: ShortPaymentConfig,
2854    /// On-account payment configuration (unapplied payments)
2855    #[serde(default)]
2856    pub on_account_payments: OnAccountPaymentConfig,
2857    /// Payment correction configuration (NSF, chargebacks)
2858    #[serde(default)]
2859    pub payment_corrections: PaymentCorrectionConfig,
2860}
2861
2862/// Dunning (Mahnungen) configuration for AR collections.
2863#[derive(Debug, Clone, Serialize, Deserialize)]
2864pub struct DunningConfig {
2865    /// Enable dunning process
2866    #[serde(default)]
2867    pub enabled: bool,
2868    /// Days overdue for level 1 dunning (1st reminder)
2869    #[serde(default = "default_dunning_level_1_days")]
2870    pub level_1_days_overdue: u32,
2871    /// Days overdue for level 2 dunning (2nd reminder)
2872    #[serde(default = "default_dunning_level_2_days")]
2873    pub level_2_days_overdue: u32,
2874    /// Days overdue for level 3 dunning (final notice)
2875    #[serde(default = "default_dunning_level_3_days")]
2876    pub level_3_days_overdue: u32,
2877    /// Days overdue for collection handover
2878    #[serde(default = "default_collection_days")]
2879    pub collection_days_overdue: u32,
2880    /// Payment rates after each dunning level
2881    #[serde(default)]
2882    pub payment_after_dunning_rates: DunningPaymentRates,
2883    /// Rate of invoices blocked from dunning (disputes)
2884    #[serde(default = "default_dunning_block_rate")]
2885    pub dunning_block_rate: f64,
2886    /// Interest rate per year for overdue amounts
2887    #[serde(default = "default_dunning_interest_rate")]
2888    pub interest_rate_per_year: f64,
2889    /// Fixed dunning charge per letter
2890    #[serde(default = "default_dunning_charge")]
2891    pub dunning_charge: f64,
2892}
2893
2894fn default_dunning_level_1_days() -> u32 {
2895    14
2896}
2897
2898fn default_dunning_level_2_days() -> u32 {
2899    28
2900}
2901
2902fn default_dunning_level_3_days() -> u32 {
2903    42
2904}
2905
2906fn default_collection_days() -> u32 {
2907    60
2908}
2909
2910fn default_dunning_block_rate() -> f64 {
2911    0.05
2912}
2913
2914fn default_dunning_interest_rate() -> f64 {
2915    0.09
2916}
2917
2918fn default_dunning_charge() -> f64 {
2919    25.0
2920}
2921
2922impl Default for DunningConfig {
2923    fn default() -> Self {
2924        Self {
2925            enabled: false,
2926            level_1_days_overdue: default_dunning_level_1_days(),
2927            level_2_days_overdue: default_dunning_level_2_days(),
2928            level_3_days_overdue: default_dunning_level_3_days(),
2929            collection_days_overdue: default_collection_days(),
2930            payment_after_dunning_rates: DunningPaymentRates::default(),
2931            dunning_block_rate: default_dunning_block_rate(),
2932            interest_rate_per_year: default_dunning_interest_rate(),
2933            dunning_charge: default_dunning_charge(),
2934        }
2935    }
2936}
2937
2938/// Payment rates after each dunning level.
2939#[derive(Debug, Clone, Serialize, Deserialize)]
2940pub struct DunningPaymentRates {
2941    /// Rate that pays after level 1 reminder
2942    #[serde(default = "default_after_level_1")]
2943    pub after_level_1: f64,
2944    /// Rate that pays after level 2 reminder
2945    #[serde(default = "default_after_level_2")]
2946    pub after_level_2: f64,
2947    /// Rate that pays after level 3 final notice
2948    #[serde(default = "default_after_level_3")]
2949    pub after_level_3: f64,
2950    /// Rate that pays during collection
2951    #[serde(default = "default_during_collection")]
2952    pub during_collection: f64,
2953    /// Rate that never pays (becomes bad debt)
2954    #[serde(default = "default_never_pay")]
2955    pub never_pay: f64,
2956}
2957
2958fn default_after_level_1() -> f64 {
2959    0.40
2960}
2961
2962fn default_after_level_2() -> f64 {
2963    0.30
2964}
2965
2966fn default_after_level_3() -> f64 {
2967    0.15
2968}
2969
2970fn default_during_collection() -> f64 {
2971    0.05
2972}
2973
2974fn default_never_pay() -> f64 {
2975    0.10
2976}
2977
2978impl Default for DunningPaymentRates {
2979    fn default() -> Self {
2980        Self {
2981            after_level_1: default_after_level_1(),
2982            after_level_2: default_after_level_2(),
2983            after_level_3: default_after_level_3(),
2984            during_collection: default_during_collection(),
2985            never_pay: default_never_pay(),
2986        }
2987    }
2988}
2989
2990/// Partial payment configuration.
2991#[derive(Debug, Clone, Serialize, Deserialize)]
2992pub struct PartialPaymentConfig {
2993    /// Rate of invoices paid partially
2994    #[serde(default = "default_partial_payment_rate")]
2995    pub rate: f64,
2996    /// Distribution of partial payment percentages
2997    #[serde(default)]
2998    pub percentage_distribution: PartialPaymentPercentageDistribution,
2999    /// Average days until remainder is paid
3000    #[serde(default = "default_avg_days_until_remainder")]
3001    pub avg_days_until_remainder: u32,
3002}
3003
3004fn default_partial_payment_rate() -> f64 {
3005    0.08
3006}
3007
3008fn default_avg_days_until_remainder() -> u32 {
3009    30
3010}
3011
3012impl Default for PartialPaymentConfig {
3013    fn default() -> Self {
3014        Self {
3015            rate: default_partial_payment_rate(),
3016            percentage_distribution: PartialPaymentPercentageDistribution::default(),
3017            avg_days_until_remainder: default_avg_days_until_remainder(),
3018        }
3019    }
3020}
3021
3022/// Distribution of partial payment percentages.
3023#[derive(Debug, Clone, Serialize, Deserialize)]
3024pub struct PartialPaymentPercentageDistribution {
3025    /// Pay 25% of invoice
3026    #[serde(default = "default_partial_25")]
3027    pub pay_25_percent: f64,
3028    /// Pay 50% of invoice
3029    #[serde(default = "default_partial_50")]
3030    pub pay_50_percent: f64,
3031    /// Pay 75% of invoice
3032    #[serde(default = "default_partial_75")]
3033    pub pay_75_percent: f64,
3034    /// Pay random percentage
3035    #[serde(default = "default_partial_random")]
3036    pub pay_random_percent: f64,
3037}
3038
3039fn default_partial_25() -> f64 {
3040    0.15
3041}
3042
3043fn default_partial_50() -> f64 {
3044    0.50
3045}
3046
3047fn default_partial_75() -> f64 {
3048    0.25
3049}
3050
3051fn default_partial_random() -> f64 {
3052    0.10
3053}
3054
3055impl Default for PartialPaymentPercentageDistribution {
3056    fn default() -> Self {
3057        Self {
3058            pay_25_percent: default_partial_25(),
3059            pay_50_percent: default_partial_50(),
3060            pay_75_percent: default_partial_75(),
3061            pay_random_percent: default_partial_random(),
3062        }
3063    }
3064}
3065
3066/// Short payment configuration (unauthorized deductions).
3067#[derive(Debug, Clone, Serialize, Deserialize)]
3068pub struct ShortPaymentConfig {
3069    /// Rate of payments that are short
3070    #[serde(default = "default_short_payment_rate")]
3071    pub rate: f64,
3072    /// Distribution of short payment reasons
3073    #[serde(default)]
3074    pub reason_distribution: ShortPaymentReasonDistribution,
3075    /// Maximum percentage that can be short
3076    #[serde(default = "default_max_short_percent")]
3077    pub max_short_percent: f64,
3078}
3079
3080fn default_short_payment_rate() -> f64 {
3081    0.03
3082}
3083
3084fn default_max_short_percent() -> f64 {
3085    0.10
3086}
3087
3088impl Default for ShortPaymentConfig {
3089    fn default() -> Self {
3090        Self {
3091            rate: default_short_payment_rate(),
3092            reason_distribution: ShortPaymentReasonDistribution::default(),
3093            max_short_percent: default_max_short_percent(),
3094        }
3095    }
3096}
3097
3098/// Distribution of short payment reasons.
3099#[derive(Debug, Clone, Serialize, Deserialize)]
3100pub struct ShortPaymentReasonDistribution {
3101    /// Pricing dispute
3102    #[serde(default = "default_pricing_dispute")]
3103    pub pricing_dispute: f64,
3104    /// Quality issue
3105    #[serde(default = "default_quality_issue")]
3106    pub quality_issue: f64,
3107    /// Quantity discrepancy
3108    #[serde(default = "default_quantity_discrepancy")]
3109    pub quantity_discrepancy: f64,
3110    /// Unauthorized deduction
3111    #[serde(default = "default_unauthorized_deduction")]
3112    pub unauthorized_deduction: f64,
3113    /// Early payment discount taken incorrectly
3114    #[serde(default = "default_incorrect_discount")]
3115    pub incorrect_discount: f64,
3116}
3117
3118fn default_pricing_dispute() -> f64 {
3119    0.30
3120}
3121
3122fn default_quality_issue() -> f64 {
3123    0.20
3124}
3125
3126fn default_quantity_discrepancy() -> f64 {
3127    0.20
3128}
3129
3130fn default_unauthorized_deduction() -> f64 {
3131    0.15
3132}
3133
3134fn default_incorrect_discount() -> f64 {
3135    0.15
3136}
3137
3138impl Default for ShortPaymentReasonDistribution {
3139    fn default() -> Self {
3140        Self {
3141            pricing_dispute: default_pricing_dispute(),
3142            quality_issue: default_quality_issue(),
3143            quantity_discrepancy: default_quantity_discrepancy(),
3144            unauthorized_deduction: default_unauthorized_deduction(),
3145            incorrect_discount: default_incorrect_discount(),
3146        }
3147    }
3148}
3149
3150/// On-account payment configuration (unapplied payments).
3151#[derive(Debug, Clone, Serialize, Deserialize)]
3152pub struct OnAccountPaymentConfig {
3153    /// Rate of payments that are on-account (unapplied)
3154    #[serde(default = "default_on_account_rate")]
3155    pub rate: f64,
3156    /// Average days until on-account payments are applied
3157    #[serde(default = "default_avg_days_until_applied")]
3158    pub avg_days_until_applied: u32,
3159}
3160
3161fn default_on_account_rate() -> f64 {
3162    0.02
3163}
3164
3165fn default_avg_days_until_applied() -> u32 {
3166    14
3167}
3168
3169impl Default for OnAccountPaymentConfig {
3170    fn default() -> Self {
3171        Self {
3172            rate: default_on_account_rate(),
3173            avg_days_until_applied: default_avg_days_until_applied(),
3174        }
3175    }
3176}
3177
3178/// Payment correction configuration.
3179#[derive(Debug, Clone, Serialize, Deserialize)]
3180pub struct PaymentCorrectionConfig {
3181    /// Rate of payments requiring correction
3182    #[serde(default = "default_payment_correction_rate")]
3183    pub rate: f64,
3184    /// Distribution of correction types
3185    #[serde(default)]
3186    pub type_distribution: PaymentCorrectionTypeDistribution,
3187}
3188
3189fn default_payment_correction_rate() -> f64 {
3190    0.02
3191}
3192
3193impl Default for PaymentCorrectionConfig {
3194    fn default() -> Self {
3195        Self {
3196            rate: default_payment_correction_rate(),
3197            type_distribution: PaymentCorrectionTypeDistribution::default(),
3198        }
3199    }
3200}
3201
3202/// Distribution of payment correction types.
3203#[derive(Debug, Clone, Serialize, Deserialize)]
3204pub struct PaymentCorrectionTypeDistribution {
3205    /// NSF (Non-sufficient funds) / bounced check
3206    #[serde(default = "default_nsf_rate")]
3207    pub nsf: f64,
3208    /// Chargeback
3209    #[serde(default = "default_chargeback_rate")]
3210    pub chargeback: f64,
3211    /// Wrong amount applied
3212    #[serde(default = "default_wrong_amount_rate")]
3213    pub wrong_amount: f64,
3214    /// Wrong customer applied
3215    #[serde(default = "default_wrong_customer_rate")]
3216    pub wrong_customer: f64,
3217    /// Duplicate payment
3218    #[serde(default = "default_duplicate_payment_rate")]
3219    pub duplicate_payment: f64,
3220}
3221
3222fn default_nsf_rate() -> f64 {
3223    0.30
3224}
3225
3226fn default_chargeback_rate() -> f64 {
3227    0.20
3228}
3229
3230fn default_wrong_amount_rate() -> f64 {
3231    0.20
3232}
3233
3234fn default_wrong_customer_rate() -> f64 {
3235    0.15
3236}
3237
3238fn default_duplicate_payment_rate() -> f64 {
3239    0.15
3240}
3241
3242impl Default for PaymentCorrectionTypeDistribution {
3243    fn default() -> Self {
3244        Self {
3245            nsf: default_nsf_rate(),
3246            chargeback: default_chargeback_rate(),
3247            wrong_amount: default_wrong_amount_rate(),
3248            wrong_customer: default_wrong_customer_rate(),
3249            duplicate_payment: default_duplicate_payment_rate(),
3250        }
3251    }
3252}
3253
3254/// Document line count distribution.
3255#[derive(Debug, Clone, Serialize, Deserialize)]
3256pub struct DocumentLineCountDistribution {
3257    /// Minimum number of lines
3258    #[serde(default = "default_min_lines")]
3259    pub min_lines: u32,
3260    /// Maximum number of lines
3261    #[serde(default = "default_max_lines")]
3262    pub max_lines: u32,
3263    /// Most common line count (mode)
3264    #[serde(default = "default_mode_lines")]
3265    pub mode_lines: u32,
3266}
3267
3268fn default_min_lines() -> u32 {
3269    1
3270}
3271
3272fn default_max_lines() -> u32 {
3273    20
3274}
3275
3276fn default_mode_lines() -> u32 {
3277    3
3278}
3279
3280impl Default for DocumentLineCountDistribution {
3281    fn default() -> Self {
3282        Self {
3283            min_lines: default_min_lines(),
3284            max_lines: default_max_lines(),
3285            mode_lines: default_mode_lines(),
3286        }
3287    }
3288}
3289
3290/// Cash discount configuration.
3291#[derive(Debug, Clone, Serialize, Deserialize)]
3292pub struct CashDiscountConfig {
3293    /// Percentage of invoices eligible for cash discount
3294    #[serde(default = "default_discount_eligible_rate")]
3295    pub eligible_rate: f64,
3296    /// Rate at which customers take the discount
3297    #[serde(default = "default_discount_taken_rate")]
3298    pub taken_rate: f64,
3299    /// Standard discount percentage
3300    #[serde(default = "default_discount_percent")]
3301    pub discount_percent: f64,
3302    /// Days within which discount must be taken
3303    #[serde(default = "default_discount_days")]
3304    pub discount_days: u32,
3305}
3306
3307fn default_discount_eligible_rate() -> f64 {
3308    0.30
3309}
3310
3311fn default_discount_taken_rate() -> f64 {
3312    0.60
3313}
3314
3315fn default_discount_percent() -> f64 {
3316    0.02
3317}
3318
3319fn default_discount_days() -> u32 {
3320    10
3321}
3322
3323impl Default for CashDiscountConfig {
3324    fn default() -> Self {
3325        Self {
3326            eligible_rate: default_discount_eligible_rate(),
3327            taken_rate: default_discount_taken_rate(),
3328            discount_percent: default_discount_percent(),
3329            discount_days: default_discount_days(),
3330        }
3331    }
3332}
3333
3334// ============================================================================
3335// Intercompany Configuration
3336// ============================================================================
3337
3338/// Intercompany transaction configuration.
3339#[derive(Debug, Clone, Serialize, Deserialize)]
3340pub struct IntercompanyConfig {
3341    /// Enable intercompany transaction generation
3342    #[serde(default)]
3343    pub enabled: bool,
3344    /// Rate of transactions that are intercompany
3345    #[serde(default = "default_ic_transaction_rate")]
3346    pub ic_transaction_rate: f64,
3347    /// Transfer pricing method
3348    #[serde(default)]
3349    pub transfer_pricing_method: TransferPricingMethod,
3350    /// Transfer pricing markup percentage (for cost-plus)
3351    #[serde(default = "default_markup_percent")]
3352    pub markup_percent: f64,
3353    /// Generate matched IC pairs (offsetting entries)
3354    #[serde(default = "default_true")]
3355    pub generate_matched_pairs: bool,
3356    /// IC transaction type distribution
3357    #[serde(default)]
3358    pub transaction_type_distribution: ICTransactionTypeDistribution,
3359    /// Generate elimination entries for consolidation
3360    #[serde(default)]
3361    pub generate_eliminations: bool,
3362}
3363
3364fn default_ic_transaction_rate() -> f64 {
3365    0.15
3366}
3367
3368fn default_markup_percent() -> f64 {
3369    0.05
3370}
3371
3372impl Default for IntercompanyConfig {
3373    fn default() -> Self {
3374        Self {
3375            enabled: false,
3376            ic_transaction_rate: default_ic_transaction_rate(),
3377            transfer_pricing_method: TransferPricingMethod::default(),
3378            markup_percent: default_markup_percent(),
3379            generate_matched_pairs: true,
3380            transaction_type_distribution: ICTransactionTypeDistribution::default(),
3381            generate_eliminations: false,
3382        }
3383    }
3384}
3385
3386/// Transfer pricing method.
3387#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
3388#[serde(rename_all = "snake_case")]
3389pub enum TransferPricingMethod {
3390    /// Cost plus a markup
3391    #[default]
3392    CostPlus,
3393    /// Comparable uncontrolled price
3394    ComparableUncontrolled,
3395    /// Resale price method
3396    ResalePrice,
3397    /// Transactional net margin method
3398    TransactionalNetMargin,
3399    /// Profit split method
3400    ProfitSplit,
3401}
3402
3403/// IC transaction type distribution.
3404#[derive(Debug, Clone, Serialize, Deserialize)]
3405pub struct ICTransactionTypeDistribution {
3406    /// Goods sales between entities
3407    pub goods_sale: f64,
3408    /// Services provided
3409    pub service_provided: f64,
3410    /// Intercompany loans
3411    pub loan: f64,
3412    /// Dividends
3413    pub dividend: f64,
3414    /// Management fees
3415    pub management_fee: f64,
3416    /// Royalties
3417    pub royalty: f64,
3418    /// Cost sharing
3419    pub cost_sharing: f64,
3420}
3421
3422impl Default for ICTransactionTypeDistribution {
3423    fn default() -> Self {
3424        Self {
3425            goods_sale: 0.35,
3426            service_provided: 0.20,
3427            loan: 0.10,
3428            dividend: 0.05,
3429            management_fee: 0.15,
3430            royalty: 0.10,
3431            cost_sharing: 0.05,
3432        }
3433    }
3434}
3435
3436// ============================================================================
3437// Balance Configuration
3438// ============================================================================
3439
3440/// Balance and trial balance configuration.
3441#[derive(Debug, Clone, Serialize, Deserialize)]
3442pub struct BalanceConfig {
3443    /// Generate opening balances
3444    #[serde(default)]
3445    pub generate_opening_balances: bool,
3446    /// Generate trial balances
3447    #[serde(default = "default_true")]
3448    pub generate_trial_balances: bool,
3449    /// Target gross margin (for revenue/COGS coherence)
3450    #[serde(default = "default_gross_margin")]
3451    pub target_gross_margin: f64,
3452    /// Target DSO (Days Sales Outstanding)
3453    #[serde(default = "default_dso")]
3454    pub target_dso_days: u32,
3455    /// Target DPO (Days Payable Outstanding)
3456    #[serde(default = "default_dpo")]
3457    pub target_dpo_days: u32,
3458    /// Target current ratio
3459    #[serde(default = "default_current_ratio")]
3460    pub target_current_ratio: f64,
3461    /// Target debt-to-equity ratio
3462    #[serde(default = "default_debt_equity")]
3463    pub target_debt_to_equity: f64,
3464    /// Validate balance sheet equation (A = L + E)
3465    #[serde(default = "default_true")]
3466    pub validate_balance_equation: bool,
3467    /// Reconcile subledgers to GL control accounts
3468    #[serde(default = "default_true")]
3469    pub reconcile_subledgers: bool,
3470}
3471
3472fn default_gross_margin() -> f64 {
3473    0.35
3474}
3475
3476fn default_dso() -> u32 {
3477    45
3478}
3479
3480fn default_dpo() -> u32 {
3481    30
3482}
3483
3484fn default_current_ratio() -> f64 {
3485    1.5
3486}
3487
3488fn default_debt_equity() -> f64 {
3489    0.5
3490}
3491
3492impl Default for BalanceConfig {
3493    fn default() -> Self {
3494        Self {
3495            generate_opening_balances: false,
3496            generate_trial_balances: true,
3497            target_gross_margin: default_gross_margin(),
3498            target_dso_days: default_dso(),
3499            target_dpo_days: default_dpo(),
3500            target_current_ratio: default_current_ratio(),
3501            target_debt_to_equity: default_debt_equity(),
3502            validate_balance_equation: true,
3503            reconcile_subledgers: true,
3504        }
3505    }
3506}
3507
3508// ==========================================================================
3509// OCPM (Object-Centric Process Mining) Configuration
3510// ==========================================================================
3511
3512/// OCPM (Object-Centric Process Mining) configuration.
3513///
3514/// Controls generation of OCEL 2.0 compatible event logs with
3515/// many-to-many event-to-object relationships.
3516#[derive(Debug, Clone, Serialize, Deserialize)]
3517pub struct OcpmConfig {
3518    /// Enable OCPM event log generation
3519    #[serde(default)]
3520    pub enabled: bool,
3521
3522    /// Generate lifecycle events (Start/Complete pairs vs atomic events)
3523    #[serde(default = "default_true")]
3524    pub generate_lifecycle_events: bool,
3525
3526    /// Include object-to-object relationships in output
3527    #[serde(default = "default_true")]
3528    pub include_object_relationships: bool,
3529
3530    /// Compute and export process variants
3531    #[serde(default = "default_true")]
3532    pub compute_variants: bool,
3533
3534    /// Maximum variants to track (0 = unlimited)
3535    #[serde(default)]
3536    pub max_variants: usize,
3537
3538    /// P2P process configuration
3539    #[serde(default)]
3540    pub p2p_process: OcpmProcessConfig,
3541
3542    /// O2C process configuration
3543    #[serde(default)]
3544    pub o2c_process: OcpmProcessConfig,
3545
3546    /// Output format configuration
3547    #[serde(default)]
3548    pub output: OcpmOutputConfig,
3549}
3550
3551impl Default for OcpmConfig {
3552    fn default() -> Self {
3553        Self {
3554            enabled: false,
3555            generate_lifecycle_events: true,
3556            include_object_relationships: true,
3557            compute_variants: true,
3558            max_variants: 0,
3559            p2p_process: OcpmProcessConfig::default(),
3560            o2c_process: OcpmProcessConfig::default(),
3561            output: OcpmOutputConfig::default(),
3562        }
3563    }
3564}
3565
3566/// Process-specific OCPM configuration.
3567#[derive(Debug, Clone, Serialize, Deserialize)]
3568pub struct OcpmProcessConfig {
3569    /// Rework probability (0.0-1.0)
3570    #[serde(default = "default_rework_probability")]
3571    pub rework_probability: f64,
3572
3573    /// Skip step probability (0.0-1.0)
3574    #[serde(default = "default_skip_probability")]
3575    pub skip_step_probability: f64,
3576
3577    /// Out-of-order step probability (0.0-1.0)
3578    #[serde(default = "default_out_of_order_probability")]
3579    pub out_of_order_probability: f64,
3580}
3581
3582fn default_rework_probability() -> f64 {
3583    0.05
3584}
3585
3586fn default_skip_probability() -> f64 {
3587    0.02
3588}
3589
3590fn default_out_of_order_probability() -> f64 {
3591    0.03
3592}
3593
3594impl Default for OcpmProcessConfig {
3595    fn default() -> Self {
3596        Self {
3597            rework_probability: default_rework_probability(),
3598            skip_step_probability: default_skip_probability(),
3599            out_of_order_probability: default_out_of_order_probability(),
3600        }
3601    }
3602}
3603
3604/// OCPM output format configuration.
3605#[derive(Debug, Clone, Serialize, Deserialize)]
3606pub struct OcpmOutputConfig {
3607    /// Export OCEL 2.0 JSON format
3608    #[serde(default = "default_true")]
3609    pub ocel_json: bool,
3610
3611    /// Export OCEL 2.0 XML format
3612    #[serde(default)]
3613    pub ocel_xml: bool,
3614
3615    /// Export XES 2.0 XML format (IEEE standard for process mining tools)
3616    #[serde(default)]
3617    pub xes: bool,
3618
3619    /// Include lifecycle transitions in XES output (start/complete pairs)
3620    #[serde(default = "default_true")]
3621    pub xes_include_lifecycle: bool,
3622
3623    /// Include resource attributes in XES output
3624    #[serde(default = "default_true")]
3625    pub xes_include_resources: bool,
3626
3627    /// Export flattened CSV for each object type
3628    #[serde(default = "default_true")]
3629    pub flattened_csv: bool,
3630
3631    /// Export event-object relationship table
3632    #[serde(default = "default_true")]
3633    pub event_object_csv: bool,
3634
3635    /// Export object-object relationship table
3636    #[serde(default = "default_true")]
3637    pub object_relationship_csv: bool,
3638
3639    /// Export process variants summary
3640    #[serde(default = "default_true")]
3641    pub variants_csv: bool,
3642
3643    /// Export reference process models (canonical P2P, O2C, R2R)
3644    #[serde(default)]
3645    pub export_reference_models: bool,
3646}
3647
3648impl Default for OcpmOutputConfig {
3649    fn default() -> Self {
3650        Self {
3651            ocel_json: true,
3652            ocel_xml: false,
3653            xes: false,
3654            xes_include_lifecycle: true,
3655            xes_include_resources: true,
3656            flattened_csv: true,
3657            event_object_csv: true,
3658            object_relationship_csv: true,
3659            variants_csv: true,
3660            export_reference_models: false,
3661        }
3662    }
3663}
3664
3665/// Audit engagement and workpaper generation configuration.
3666#[derive(Debug, Clone, Serialize, Deserialize)]
3667pub struct AuditGenerationConfig {
3668    /// Enable audit engagement generation
3669    #[serde(default)]
3670    pub enabled: bool,
3671
3672    /// Generate engagement documents and workpapers
3673    #[serde(default = "default_true")]
3674    pub generate_workpapers: bool,
3675
3676    /// Default engagement type distribution
3677    #[serde(default)]
3678    pub engagement_types: AuditEngagementTypesConfig,
3679
3680    /// Workpaper configuration
3681    #[serde(default)]
3682    pub workpapers: WorkpaperConfig,
3683
3684    /// Team configuration
3685    #[serde(default)]
3686    pub team: AuditTeamConfig,
3687
3688    /// Review workflow configuration
3689    #[serde(default)]
3690    pub review: ReviewWorkflowConfig,
3691}
3692
3693impl Default for AuditGenerationConfig {
3694    fn default() -> Self {
3695        Self {
3696            enabled: false,
3697            generate_workpapers: true,
3698            engagement_types: AuditEngagementTypesConfig::default(),
3699            workpapers: WorkpaperConfig::default(),
3700            team: AuditTeamConfig::default(),
3701            review: ReviewWorkflowConfig::default(),
3702        }
3703    }
3704}
3705
3706/// Engagement type distribution configuration.
3707#[derive(Debug, Clone, Serialize, Deserialize)]
3708pub struct AuditEngagementTypesConfig {
3709    /// Financial statement audit probability
3710    #[serde(default = "default_financial_audit_prob")]
3711    pub financial_statement: f64,
3712    /// SOX/ICFR audit probability
3713    #[serde(default = "default_sox_audit_prob")]
3714    pub sox_icfr: f64,
3715    /// Integrated audit probability
3716    #[serde(default = "default_integrated_audit_prob")]
3717    pub integrated: f64,
3718    /// Review engagement probability
3719    #[serde(default = "default_review_prob")]
3720    pub review: f64,
3721    /// Agreed-upon procedures probability
3722    #[serde(default = "default_aup_prob")]
3723    pub agreed_upon_procedures: f64,
3724}
3725
3726fn default_financial_audit_prob() -> f64 {
3727    0.40
3728}
3729fn default_sox_audit_prob() -> f64 {
3730    0.20
3731}
3732fn default_integrated_audit_prob() -> f64 {
3733    0.25
3734}
3735fn default_review_prob() -> f64 {
3736    0.10
3737}
3738fn default_aup_prob() -> f64 {
3739    0.05
3740}
3741
3742impl Default for AuditEngagementTypesConfig {
3743    fn default() -> Self {
3744        Self {
3745            financial_statement: default_financial_audit_prob(),
3746            sox_icfr: default_sox_audit_prob(),
3747            integrated: default_integrated_audit_prob(),
3748            review: default_review_prob(),
3749            agreed_upon_procedures: default_aup_prob(),
3750        }
3751    }
3752}
3753
3754/// Workpaper generation configuration.
3755#[derive(Debug, Clone, Serialize, Deserialize)]
3756pub struct WorkpaperConfig {
3757    /// Average workpapers per engagement phase
3758    #[serde(default = "default_workpapers_per_phase")]
3759    pub average_per_phase: usize,
3760
3761    /// Include ISA compliance references
3762    #[serde(default = "default_true")]
3763    pub include_isa_references: bool,
3764
3765    /// Generate sample details
3766    #[serde(default = "default_true")]
3767    pub include_sample_details: bool,
3768
3769    /// Include cross-references between workpapers
3770    #[serde(default = "default_true")]
3771    pub include_cross_references: bool,
3772
3773    /// Sampling configuration
3774    #[serde(default)]
3775    pub sampling: SamplingConfig,
3776}
3777
3778fn default_workpapers_per_phase() -> usize {
3779    5
3780}
3781
3782impl Default for WorkpaperConfig {
3783    fn default() -> Self {
3784        Self {
3785            average_per_phase: default_workpapers_per_phase(),
3786            include_isa_references: true,
3787            include_sample_details: true,
3788            include_cross_references: true,
3789            sampling: SamplingConfig::default(),
3790        }
3791    }
3792}
3793
3794/// Sampling method configuration.
3795#[derive(Debug, Clone, Serialize, Deserialize)]
3796pub struct SamplingConfig {
3797    /// Statistical sampling rate (0.0-1.0)
3798    #[serde(default = "default_statistical_rate")]
3799    pub statistical_rate: f64,
3800    /// Judgmental sampling rate (0.0-1.0)
3801    #[serde(default = "default_judgmental_rate")]
3802    pub judgmental_rate: f64,
3803    /// Haphazard sampling rate (0.0-1.0)
3804    #[serde(default = "default_haphazard_rate")]
3805    pub haphazard_rate: f64,
3806    /// 100% examination rate (0.0-1.0)
3807    #[serde(default = "default_complete_examination_rate")]
3808    pub complete_examination_rate: f64,
3809}
3810
3811fn default_statistical_rate() -> f64 {
3812    0.40
3813}
3814fn default_judgmental_rate() -> f64 {
3815    0.30
3816}
3817fn default_haphazard_rate() -> f64 {
3818    0.20
3819}
3820fn default_complete_examination_rate() -> f64 {
3821    0.10
3822}
3823
3824impl Default for SamplingConfig {
3825    fn default() -> Self {
3826        Self {
3827            statistical_rate: default_statistical_rate(),
3828            judgmental_rate: default_judgmental_rate(),
3829            haphazard_rate: default_haphazard_rate(),
3830            complete_examination_rate: default_complete_examination_rate(),
3831        }
3832    }
3833}
3834
3835/// Audit team configuration.
3836#[derive(Debug, Clone, Serialize, Deserialize)]
3837pub struct AuditTeamConfig {
3838    /// Minimum team size
3839    #[serde(default = "default_min_team_size")]
3840    pub min_team_size: usize,
3841    /// Maximum team size
3842    #[serde(default = "default_max_team_size")]
3843    pub max_team_size: usize,
3844    /// Probability of having a specialist on the team
3845    #[serde(default = "default_specialist_probability")]
3846    pub specialist_probability: f64,
3847}
3848
3849fn default_min_team_size() -> usize {
3850    3
3851}
3852fn default_max_team_size() -> usize {
3853    8
3854}
3855fn default_specialist_probability() -> f64 {
3856    0.30
3857}
3858
3859impl Default for AuditTeamConfig {
3860    fn default() -> Self {
3861        Self {
3862            min_team_size: default_min_team_size(),
3863            max_team_size: default_max_team_size(),
3864            specialist_probability: default_specialist_probability(),
3865        }
3866    }
3867}
3868
3869/// Review workflow configuration.
3870#[derive(Debug, Clone, Serialize, Deserialize)]
3871pub struct ReviewWorkflowConfig {
3872    /// Average days between preparer completion and first review
3873    #[serde(default = "default_review_delay_days")]
3874    pub average_review_delay_days: u32,
3875    /// Probability of review notes requiring rework
3876    #[serde(default = "default_rework_probability_review")]
3877    pub rework_probability: f64,
3878    /// Require partner sign-off for all workpapers
3879    #[serde(default = "default_true")]
3880    pub require_partner_signoff: bool,
3881}
3882
3883fn default_review_delay_days() -> u32 {
3884    2
3885}
3886fn default_rework_probability_review() -> f64 {
3887    0.15
3888}
3889
3890impl Default for ReviewWorkflowConfig {
3891    fn default() -> Self {
3892        Self {
3893            average_review_delay_days: default_review_delay_days(),
3894            rework_probability: default_rework_probability_review(),
3895            require_partner_signoff: true,
3896        }
3897    }
3898}
3899
3900// =============================================================================
3901// Data Quality Configuration
3902// =============================================================================
3903
3904/// Data quality variation settings for realistic flakiness injection.
3905#[derive(Debug, Clone, Serialize, Deserialize)]
3906pub struct DataQualitySchemaConfig {
3907    /// Enable data quality variations
3908    #[serde(default)]
3909    pub enabled: bool,
3910    /// Preset to use (overrides individual settings if set)
3911    #[serde(default)]
3912    pub preset: DataQualityPreset,
3913    /// Missing value injection settings
3914    #[serde(default)]
3915    pub missing_values: MissingValuesSchemaConfig,
3916    /// Typo injection settings
3917    #[serde(default)]
3918    pub typos: TypoSchemaConfig,
3919    /// Format variation settings
3920    #[serde(default)]
3921    pub format_variations: FormatVariationSchemaConfig,
3922    /// Duplicate injection settings
3923    #[serde(default)]
3924    pub duplicates: DuplicateSchemaConfig,
3925    /// Encoding issue settings
3926    #[serde(default)]
3927    pub encoding_issues: EncodingIssueSchemaConfig,
3928    /// Generate quality issue labels for ML training
3929    #[serde(default)]
3930    pub generate_labels: bool,
3931    /// Per-sink quality profiles (different settings for CSV vs JSON etc.)
3932    #[serde(default)]
3933    pub sink_profiles: SinkQualityProfiles,
3934}
3935
3936impl Default for DataQualitySchemaConfig {
3937    fn default() -> Self {
3938        Self {
3939            enabled: false,
3940            preset: DataQualityPreset::None,
3941            missing_values: MissingValuesSchemaConfig::default(),
3942            typos: TypoSchemaConfig::default(),
3943            format_variations: FormatVariationSchemaConfig::default(),
3944            duplicates: DuplicateSchemaConfig::default(),
3945            encoding_issues: EncodingIssueSchemaConfig::default(),
3946            generate_labels: true,
3947            sink_profiles: SinkQualityProfiles::default(),
3948        }
3949    }
3950}
3951
3952impl DataQualitySchemaConfig {
3953    /// Creates a config for a specific preset profile.
3954    pub fn with_preset(preset: DataQualityPreset) -> Self {
3955        let mut config = Self {
3956            preset,
3957            ..Default::default()
3958        };
3959        config.apply_preset();
3960        config
3961    }
3962
3963    /// Applies the preset settings to the individual configuration fields.
3964    /// Call this after deserializing if preset is not Custom or None.
3965    pub fn apply_preset(&mut self) {
3966        if !self.preset.overrides_settings() {
3967            return;
3968        }
3969
3970        self.enabled = true;
3971
3972        // Missing values
3973        self.missing_values.enabled = self.preset.missing_rate() > 0.0;
3974        self.missing_values.rate = self.preset.missing_rate();
3975
3976        // Typos
3977        self.typos.enabled = self.preset.typo_rate() > 0.0;
3978        self.typos.char_error_rate = self.preset.typo_rate();
3979
3980        // Duplicates
3981        self.duplicates.enabled = self.preset.duplicate_rate() > 0.0;
3982        self.duplicates.exact_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
3983        self.duplicates.near_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
3984        self.duplicates.fuzzy_duplicate_ratio = self.preset.duplicate_rate() * 0.2;
3985
3986        // Format variations
3987        self.format_variations.enabled = self.preset.format_variations_enabled();
3988
3989        // Encoding issues
3990        self.encoding_issues.enabled = self.preset.encoding_issues_enabled();
3991        self.encoding_issues.rate = self.preset.encoding_issue_rate();
3992
3993        // OCR errors for typos in legacy preset
3994        if self.preset.ocr_errors_enabled() {
3995            self.typos.type_weights.ocr_errors = 0.3;
3996        }
3997    }
3998
3999    /// Returns the effective missing value rate (considering preset).
4000    pub fn effective_missing_rate(&self) -> f64 {
4001        if self.preset.overrides_settings() {
4002            self.preset.missing_rate()
4003        } else {
4004            self.missing_values.rate
4005        }
4006    }
4007
4008    /// Returns the effective typo rate (considering preset).
4009    pub fn effective_typo_rate(&self) -> f64 {
4010        if self.preset.overrides_settings() {
4011            self.preset.typo_rate()
4012        } else {
4013            self.typos.char_error_rate
4014        }
4015    }
4016
4017    /// Returns the effective duplicate rate (considering preset).
4018    pub fn effective_duplicate_rate(&self) -> f64 {
4019        if self.preset.overrides_settings() {
4020            self.preset.duplicate_rate()
4021        } else {
4022            self.duplicates.exact_duplicate_ratio
4023                + self.duplicates.near_duplicate_ratio
4024                + self.duplicates.fuzzy_duplicate_ratio
4025        }
4026    }
4027
4028    /// Creates a clean profile config.
4029    pub fn clean() -> Self {
4030        Self::with_preset(DataQualityPreset::Clean)
4031    }
4032
4033    /// Creates a noisy profile config.
4034    pub fn noisy() -> Self {
4035        Self::with_preset(DataQualityPreset::Noisy)
4036    }
4037
4038    /// Creates a legacy profile config.
4039    pub fn legacy() -> Self {
4040        Self::with_preset(DataQualityPreset::Legacy)
4041    }
4042}
4043
4044/// Preset configurations for common data quality scenarios.
4045#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4046#[serde(rename_all = "snake_case")]
4047pub enum DataQualityPreset {
4048    /// No data quality variations (clean data)
4049    #[default]
4050    None,
4051    /// Minimal variations (very clean data with rare issues)
4052    Minimal,
4053    /// Normal variations (realistic enterprise data quality)
4054    Normal,
4055    /// High variations (messy data for stress testing)
4056    High,
4057    /// Custom (use individual settings)
4058    Custom,
4059
4060    // ========================================
4061    // ML-Oriented Profiles (Phase 2.1)
4062    // ========================================
4063    /// Clean profile for ML training - minimal data quality issues
4064    /// Missing: 0.1%, Typos: 0.05%, Duplicates: 0%, Format: None
4065    Clean,
4066    /// Noisy profile simulating typical production data issues
4067    /// Missing: 5%, Typos: 2%, Duplicates: 1%, Format: Medium
4068    Noisy,
4069    /// Legacy profile simulating migrated/OCR'd historical data
4070    /// Missing: 10%, Typos: 5%, Duplicates: 3%, Format: Heavy + OCR
4071    Legacy,
4072}
4073
4074impl DataQualityPreset {
4075    /// Returns the missing value rate for this preset.
4076    pub fn missing_rate(&self) -> f64 {
4077        match self {
4078            DataQualityPreset::None => 0.0,
4079            DataQualityPreset::Minimal => 0.005,
4080            DataQualityPreset::Normal => 0.02,
4081            DataQualityPreset::High => 0.08,
4082            DataQualityPreset::Custom => 0.01, // Use config value
4083            DataQualityPreset::Clean => 0.001,
4084            DataQualityPreset::Noisy => 0.05,
4085            DataQualityPreset::Legacy => 0.10,
4086        }
4087    }
4088
4089    /// Returns the typo rate for this preset.
4090    pub fn typo_rate(&self) -> f64 {
4091        match self {
4092            DataQualityPreset::None => 0.0,
4093            DataQualityPreset::Minimal => 0.0005,
4094            DataQualityPreset::Normal => 0.002,
4095            DataQualityPreset::High => 0.01,
4096            DataQualityPreset::Custom => 0.001, // Use config value
4097            DataQualityPreset::Clean => 0.0005,
4098            DataQualityPreset::Noisy => 0.02,
4099            DataQualityPreset::Legacy => 0.05,
4100        }
4101    }
4102
4103    /// Returns the duplicate rate for this preset.
4104    pub fn duplicate_rate(&self) -> f64 {
4105        match self {
4106            DataQualityPreset::None => 0.0,
4107            DataQualityPreset::Minimal => 0.001,
4108            DataQualityPreset::Normal => 0.005,
4109            DataQualityPreset::High => 0.02,
4110            DataQualityPreset::Custom => 0.0, // Use config value
4111            DataQualityPreset::Clean => 0.0,
4112            DataQualityPreset::Noisy => 0.01,
4113            DataQualityPreset::Legacy => 0.03,
4114        }
4115    }
4116
4117    /// Returns whether format variations are enabled for this preset.
4118    pub fn format_variations_enabled(&self) -> bool {
4119        match self {
4120            DataQualityPreset::None | DataQualityPreset::Clean => false,
4121            DataQualityPreset::Minimal => true,
4122            DataQualityPreset::Normal => true,
4123            DataQualityPreset::High => true,
4124            DataQualityPreset::Custom => true,
4125            DataQualityPreset::Noisy => true,
4126            DataQualityPreset::Legacy => true,
4127        }
4128    }
4129
4130    /// Returns whether OCR-style errors are enabled for this preset.
4131    pub fn ocr_errors_enabled(&self) -> bool {
4132        matches!(self, DataQualityPreset::Legacy | DataQualityPreset::High)
4133    }
4134
4135    /// Returns whether encoding issues are enabled for this preset.
4136    pub fn encoding_issues_enabled(&self) -> bool {
4137        matches!(
4138            self,
4139            DataQualityPreset::Legacy | DataQualityPreset::High | DataQualityPreset::Noisy
4140        )
4141    }
4142
4143    /// Returns the encoding issue rate for this preset.
4144    pub fn encoding_issue_rate(&self) -> f64 {
4145        match self {
4146            DataQualityPreset::None | DataQualityPreset::Clean | DataQualityPreset::Minimal => 0.0,
4147            DataQualityPreset::Normal => 0.002,
4148            DataQualityPreset::High => 0.01,
4149            DataQualityPreset::Custom => 0.0,
4150            DataQualityPreset::Noisy => 0.005,
4151            DataQualityPreset::Legacy => 0.02,
4152        }
4153    }
4154
4155    /// Returns true if this preset overrides individual settings.
4156    pub fn overrides_settings(&self) -> bool {
4157        !matches!(self, DataQualityPreset::Custom | DataQualityPreset::None)
4158    }
4159
4160    /// Returns a human-readable description of this preset.
4161    pub fn description(&self) -> &'static str {
4162        match self {
4163            DataQualityPreset::None => "No data quality issues (pristine data)",
4164            DataQualityPreset::Minimal => "Very rare data quality issues",
4165            DataQualityPreset::Normal => "Realistic enterprise data quality",
4166            DataQualityPreset::High => "Messy data for stress testing",
4167            DataQualityPreset::Custom => "Custom settings from configuration",
4168            DataQualityPreset::Clean => "ML-ready clean data with minimal issues",
4169            DataQualityPreset::Noisy => "Typical production data with moderate issues",
4170            DataQualityPreset::Legacy => "Legacy/migrated data with heavy issues and OCR errors",
4171        }
4172    }
4173}
4174
4175/// Missing value injection configuration.
4176#[derive(Debug, Clone, Serialize, Deserialize)]
4177pub struct MissingValuesSchemaConfig {
4178    /// Enable missing value injection
4179    #[serde(default)]
4180    pub enabled: bool,
4181    /// Global missing rate (0.0 to 1.0)
4182    #[serde(default = "default_missing_rate")]
4183    pub rate: f64,
4184    /// Missing value strategy
4185    #[serde(default)]
4186    pub strategy: MissingValueStrategy,
4187    /// Field-specific rates (field name -> rate)
4188    #[serde(default)]
4189    pub field_rates: std::collections::HashMap<String, f64>,
4190    /// Fields that should never have missing values
4191    #[serde(default)]
4192    pub protected_fields: Vec<String>,
4193}
4194
4195fn default_missing_rate() -> f64 {
4196    0.01
4197}
4198
4199impl Default for MissingValuesSchemaConfig {
4200    fn default() -> Self {
4201        Self {
4202            enabled: false,
4203            rate: default_missing_rate(),
4204            strategy: MissingValueStrategy::Mcar,
4205            field_rates: std::collections::HashMap::new(),
4206            protected_fields: vec![
4207                "document_id".to_string(),
4208                "company_code".to_string(),
4209                "posting_date".to_string(),
4210            ],
4211        }
4212    }
4213}
4214
4215/// Missing value strategy types.
4216#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4217#[serde(rename_all = "snake_case")]
4218pub enum MissingValueStrategy {
4219    /// Missing Completely At Random - equal probability for all values
4220    #[default]
4221    Mcar,
4222    /// Missing At Random - depends on other observed values
4223    Mar,
4224    /// Missing Not At Random - depends on the value itself
4225    Mnar,
4226    /// Systematic - entire field groups missing together
4227    Systematic,
4228}
4229
4230/// Typo injection configuration.
4231#[derive(Debug, Clone, Serialize, Deserialize)]
4232pub struct TypoSchemaConfig {
4233    /// Enable typo injection
4234    #[serde(default)]
4235    pub enabled: bool,
4236    /// Character error rate (per character, not per field)
4237    #[serde(default = "default_typo_rate")]
4238    pub char_error_rate: f64,
4239    /// Typo type weights
4240    #[serde(default)]
4241    pub type_weights: TypoTypeWeights,
4242    /// Fields that should never have typos
4243    #[serde(default)]
4244    pub protected_fields: Vec<String>,
4245}
4246
4247fn default_typo_rate() -> f64 {
4248    0.001
4249}
4250
4251impl Default for TypoSchemaConfig {
4252    fn default() -> Self {
4253        Self {
4254            enabled: false,
4255            char_error_rate: default_typo_rate(),
4256            type_weights: TypoTypeWeights::default(),
4257            protected_fields: vec![
4258                "document_id".to_string(),
4259                "gl_account".to_string(),
4260                "company_code".to_string(),
4261            ],
4262        }
4263    }
4264}
4265
4266/// Weights for different typo types.
4267#[derive(Debug, Clone, Serialize, Deserialize)]
4268pub struct TypoTypeWeights {
4269    /// Keyboard-adjacent substitution (e.g., 'a' -> 's')
4270    #[serde(default = "default_substitution_weight")]
4271    pub substitution: f64,
4272    /// Adjacent character transposition (e.g., 'ab' -> 'ba')
4273    #[serde(default = "default_transposition_weight")]
4274    pub transposition: f64,
4275    /// Character insertion
4276    #[serde(default = "default_insertion_weight")]
4277    pub insertion: f64,
4278    /// Character deletion
4279    #[serde(default = "default_deletion_weight")]
4280    pub deletion: f64,
4281    /// OCR-style errors (e.g., '0' -> 'O')
4282    #[serde(default = "default_ocr_weight")]
4283    pub ocr_errors: f64,
4284    /// Homophone substitution (e.g., 'their' -> 'there')
4285    #[serde(default = "default_homophone_weight")]
4286    pub homophones: f64,
4287}
4288
4289fn default_substitution_weight() -> f64 {
4290    0.35
4291}
4292fn default_transposition_weight() -> f64 {
4293    0.25
4294}
4295fn default_insertion_weight() -> f64 {
4296    0.10
4297}
4298fn default_deletion_weight() -> f64 {
4299    0.15
4300}
4301fn default_ocr_weight() -> f64 {
4302    0.10
4303}
4304fn default_homophone_weight() -> f64 {
4305    0.05
4306}
4307
4308impl Default for TypoTypeWeights {
4309    fn default() -> Self {
4310        Self {
4311            substitution: default_substitution_weight(),
4312            transposition: default_transposition_weight(),
4313            insertion: default_insertion_weight(),
4314            deletion: default_deletion_weight(),
4315            ocr_errors: default_ocr_weight(),
4316            homophones: default_homophone_weight(),
4317        }
4318    }
4319}
4320
4321/// Format variation configuration.
4322#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4323pub struct FormatVariationSchemaConfig {
4324    /// Enable format variations
4325    #[serde(default)]
4326    pub enabled: bool,
4327    /// Date format variation settings
4328    #[serde(default)]
4329    pub dates: DateFormatVariationConfig,
4330    /// Amount format variation settings
4331    #[serde(default)]
4332    pub amounts: AmountFormatVariationConfig,
4333    /// Identifier format variation settings
4334    #[serde(default)]
4335    pub identifiers: IdentifierFormatVariationConfig,
4336}
4337
4338/// Date format variation configuration.
4339#[derive(Debug, Clone, Serialize, Deserialize)]
4340pub struct DateFormatVariationConfig {
4341    /// Enable date format variations
4342    #[serde(default)]
4343    pub enabled: bool,
4344    /// Overall variation rate
4345    #[serde(default = "default_date_variation_rate")]
4346    pub rate: f64,
4347    /// Include ISO format (2024-01-15)
4348    #[serde(default = "default_true")]
4349    pub iso_format: bool,
4350    /// Include US format (01/15/2024)
4351    #[serde(default)]
4352    pub us_format: bool,
4353    /// Include EU format (15.01.2024)
4354    #[serde(default)]
4355    pub eu_format: bool,
4356    /// Include long format (January 15, 2024)
4357    #[serde(default)]
4358    pub long_format: bool,
4359}
4360
4361fn default_date_variation_rate() -> f64 {
4362    0.05
4363}
4364
4365impl Default for DateFormatVariationConfig {
4366    fn default() -> Self {
4367        Self {
4368            enabled: false,
4369            rate: default_date_variation_rate(),
4370            iso_format: true,
4371            us_format: false,
4372            eu_format: false,
4373            long_format: false,
4374        }
4375    }
4376}
4377
4378/// Amount format variation configuration.
4379#[derive(Debug, Clone, Serialize, Deserialize)]
4380pub struct AmountFormatVariationConfig {
4381    /// Enable amount format variations
4382    #[serde(default)]
4383    pub enabled: bool,
4384    /// Overall variation rate
4385    #[serde(default = "default_amount_variation_rate")]
4386    pub rate: f64,
4387    /// Include US comma format (1,234.56)
4388    #[serde(default)]
4389    pub us_comma_format: bool,
4390    /// Include EU format (1.234,56)
4391    #[serde(default)]
4392    pub eu_format: bool,
4393    /// Include currency prefix ($1,234.56)
4394    #[serde(default)]
4395    pub currency_prefix: bool,
4396    /// Include accounting format with parentheses for negatives
4397    #[serde(default)]
4398    pub accounting_format: bool,
4399}
4400
4401fn default_amount_variation_rate() -> f64 {
4402    0.02
4403}
4404
4405impl Default for AmountFormatVariationConfig {
4406    fn default() -> Self {
4407        Self {
4408            enabled: false,
4409            rate: default_amount_variation_rate(),
4410            us_comma_format: false,
4411            eu_format: false,
4412            currency_prefix: false,
4413            accounting_format: false,
4414        }
4415    }
4416}
4417
4418/// Identifier format variation configuration.
4419#[derive(Debug, Clone, Serialize, Deserialize)]
4420pub struct IdentifierFormatVariationConfig {
4421    /// Enable identifier format variations
4422    #[serde(default)]
4423    pub enabled: bool,
4424    /// Overall variation rate
4425    #[serde(default = "default_identifier_variation_rate")]
4426    pub rate: f64,
4427    /// Case variations (uppercase, lowercase, mixed)
4428    #[serde(default)]
4429    pub case_variations: bool,
4430    /// Padding variations (leading zeros)
4431    #[serde(default)]
4432    pub padding_variations: bool,
4433    /// Separator variations (dash vs underscore)
4434    #[serde(default)]
4435    pub separator_variations: bool,
4436}
4437
4438fn default_identifier_variation_rate() -> f64 {
4439    0.02
4440}
4441
4442impl Default for IdentifierFormatVariationConfig {
4443    fn default() -> Self {
4444        Self {
4445            enabled: false,
4446            rate: default_identifier_variation_rate(),
4447            case_variations: false,
4448            padding_variations: false,
4449            separator_variations: false,
4450        }
4451    }
4452}
4453
4454/// Duplicate injection configuration.
4455#[derive(Debug, Clone, Serialize, Deserialize)]
4456pub struct DuplicateSchemaConfig {
4457    /// Enable duplicate injection
4458    #[serde(default)]
4459    pub enabled: bool,
4460    /// Overall duplicate rate
4461    #[serde(default = "default_duplicate_rate")]
4462    pub rate: f64,
4463    /// Exact duplicate proportion (out of duplicates)
4464    #[serde(default = "default_exact_duplicate_ratio")]
4465    pub exact_duplicate_ratio: f64,
4466    /// Near duplicate proportion (slight variations)
4467    #[serde(default = "default_near_duplicate_ratio")]
4468    pub near_duplicate_ratio: f64,
4469    /// Fuzzy duplicate proportion (typos in key fields)
4470    #[serde(default = "default_fuzzy_duplicate_ratio")]
4471    pub fuzzy_duplicate_ratio: f64,
4472    /// Maximum date offset for near/fuzzy duplicates (days)
4473    #[serde(default = "default_max_date_offset")]
4474    pub max_date_offset_days: u32,
4475    /// Maximum amount variance for near duplicates (fraction)
4476    #[serde(default = "default_max_amount_variance")]
4477    pub max_amount_variance: f64,
4478}
4479
4480fn default_duplicate_rate() -> f64 {
4481    0.005
4482}
4483fn default_exact_duplicate_ratio() -> f64 {
4484    0.4
4485}
4486fn default_near_duplicate_ratio() -> f64 {
4487    0.35
4488}
4489fn default_fuzzy_duplicate_ratio() -> f64 {
4490    0.25
4491}
4492fn default_max_date_offset() -> u32 {
4493    3
4494}
4495fn default_max_amount_variance() -> f64 {
4496    0.01
4497}
4498
4499impl Default for DuplicateSchemaConfig {
4500    fn default() -> Self {
4501        Self {
4502            enabled: false,
4503            rate: default_duplicate_rate(),
4504            exact_duplicate_ratio: default_exact_duplicate_ratio(),
4505            near_duplicate_ratio: default_near_duplicate_ratio(),
4506            fuzzy_duplicate_ratio: default_fuzzy_duplicate_ratio(),
4507            max_date_offset_days: default_max_date_offset(),
4508            max_amount_variance: default_max_amount_variance(),
4509        }
4510    }
4511}
4512
4513/// Encoding issue configuration.
4514#[derive(Debug, Clone, Serialize, Deserialize)]
4515pub struct EncodingIssueSchemaConfig {
4516    /// Enable encoding issue injection
4517    #[serde(default)]
4518    pub enabled: bool,
4519    /// Overall encoding issue rate
4520    #[serde(default = "default_encoding_rate")]
4521    pub rate: f64,
4522    /// Include mojibake (UTF-8/Latin-1 confusion)
4523    #[serde(default)]
4524    pub mojibake: bool,
4525    /// Include HTML entity corruption
4526    #[serde(default)]
4527    pub html_entities: bool,
4528    /// Include BOM issues
4529    #[serde(default)]
4530    pub bom_issues: bool,
4531}
4532
4533fn default_encoding_rate() -> f64 {
4534    0.001
4535}
4536
4537impl Default for EncodingIssueSchemaConfig {
4538    fn default() -> Self {
4539        Self {
4540            enabled: false,
4541            rate: default_encoding_rate(),
4542            mojibake: false,
4543            html_entities: false,
4544            bom_issues: false,
4545        }
4546    }
4547}
4548
4549/// Per-sink quality profiles for different output formats.
4550#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4551pub struct SinkQualityProfiles {
4552    /// CSV-specific quality settings
4553    #[serde(default)]
4554    pub csv: Option<SinkQualityOverride>,
4555    /// JSON-specific quality settings
4556    #[serde(default)]
4557    pub json: Option<SinkQualityOverride>,
4558    /// Parquet-specific quality settings
4559    #[serde(default)]
4560    pub parquet: Option<SinkQualityOverride>,
4561}
4562
4563/// Quality setting overrides for a specific sink type.
4564#[derive(Debug, Clone, Serialize, Deserialize)]
4565pub struct SinkQualityOverride {
4566    /// Override enabled state
4567    pub enabled: Option<bool>,
4568    /// Override missing value rate
4569    pub missing_rate: Option<f64>,
4570    /// Override typo rate
4571    pub typo_rate: Option<f64>,
4572    /// Override format variation rate
4573    pub format_variation_rate: Option<f64>,
4574    /// Override duplicate rate
4575    pub duplicate_rate: Option<f64>,
4576}
4577
4578// =============================================================================
4579// Accounting Standards Configuration
4580// =============================================================================
4581
4582/// Accounting standards framework configuration for generating standards-compliant data.
4583///
4584/// Supports US GAAP and IFRS frameworks with specific standards:
4585/// - ASC 606/IFRS 15: Revenue Recognition
4586/// - ASC 842/IFRS 16: Leases
4587/// - ASC 820/IFRS 13: Fair Value Measurement
4588/// - ASC 360/IAS 36: Impairment
4589#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4590pub struct AccountingStandardsConfig {
4591    /// Enable accounting standards generation
4592    #[serde(default)]
4593    pub enabled: bool,
4594
4595    /// Accounting framework to use
4596    #[serde(default)]
4597    pub framework: AccountingFrameworkConfig,
4598
4599    /// Revenue recognition configuration (ASC 606/IFRS 15)
4600    #[serde(default)]
4601    pub revenue_recognition: RevenueRecognitionConfig,
4602
4603    /// Lease accounting configuration (ASC 842/IFRS 16)
4604    #[serde(default)]
4605    pub leases: LeaseAccountingConfig,
4606
4607    /// Fair value measurement configuration (ASC 820/IFRS 13)
4608    #[serde(default)]
4609    pub fair_value: FairValueConfig,
4610
4611    /// Impairment testing configuration (ASC 360/IAS 36)
4612    #[serde(default)]
4613    pub impairment: ImpairmentConfig,
4614
4615    /// Generate framework differences for dual reporting
4616    #[serde(default)]
4617    pub generate_differences: bool,
4618}
4619
4620/// Accounting framework selection.
4621#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4622#[serde(rename_all = "snake_case")]
4623pub enum AccountingFrameworkConfig {
4624    /// US Generally Accepted Accounting Principles
4625    #[default]
4626    UsGaap,
4627    /// International Financial Reporting Standards
4628    Ifrs,
4629    /// Generate data for both frameworks with reconciliation
4630    DualReporting,
4631}
4632
4633/// Revenue recognition configuration (ASC 606/IFRS 15).
4634#[derive(Debug, Clone, Serialize, Deserialize)]
4635pub struct RevenueRecognitionConfig {
4636    /// Enable revenue recognition generation
4637    #[serde(default)]
4638    pub enabled: bool,
4639
4640    /// Generate customer contracts
4641    #[serde(default = "default_true")]
4642    pub generate_contracts: bool,
4643
4644    /// Average number of performance obligations per contract
4645    #[serde(default = "default_avg_obligations")]
4646    pub avg_obligations_per_contract: f64,
4647
4648    /// Rate of contracts with variable consideration
4649    #[serde(default = "default_variable_consideration_rate")]
4650    pub variable_consideration_rate: f64,
4651
4652    /// Rate of over-time revenue recognition (vs point-in-time)
4653    #[serde(default = "default_over_time_rate")]
4654    pub over_time_recognition_rate: f64,
4655
4656    /// Number of contracts to generate
4657    #[serde(default = "default_contract_count")]
4658    pub contract_count: usize,
4659}
4660
4661fn default_avg_obligations() -> f64 {
4662    2.0
4663}
4664
4665fn default_variable_consideration_rate() -> f64 {
4666    0.15
4667}
4668
4669fn default_over_time_rate() -> f64 {
4670    0.30
4671}
4672
4673fn default_contract_count() -> usize {
4674    100
4675}
4676
4677impl Default for RevenueRecognitionConfig {
4678    fn default() -> Self {
4679        Self {
4680            enabled: false,
4681            generate_contracts: true,
4682            avg_obligations_per_contract: default_avg_obligations(),
4683            variable_consideration_rate: default_variable_consideration_rate(),
4684            over_time_recognition_rate: default_over_time_rate(),
4685            contract_count: default_contract_count(),
4686        }
4687    }
4688}
4689
4690/// Lease accounting configuration (ASC 842/IFRS 16).
4691#[derive(Debug, Clone, Serialize, Deserialize)]
4692pub struct LeaseAccountingConfig {
4693    /// Enable lease accounting generation
4694    #[serde(default)]
4695    pub enabled: bool,
4696
4697    /// Number of leases to generate
4698    #[serde(default = "default_lease_count")]
4699    pub lease_count: usize,
4700
4701    /// Percentage of finance leases (vs operating)
4702    #[serde(default = "default_finance_lease_pct")]
4703    pub finance_lease_percent: f64,
4704
4705    /// Average lease term in months
4706    #[serde(default = "default_avg_lease_term")]
4707    pub avg_lease_term_months: u32,
4708
4709    /// Generate amortization schedules
4710    #[serde(default = "default_true")]
4711    pub generate_amortization: bool,
4712
4713    /// Real estate lease percentage
4714    #[serde(default = "default_real_estate_pct")]
4715    pub real_estate_percent: f64,
4716}
4717
4718fn default_lease_count() -> usize {
4719    50
4720}
4721
4722fn default_finance_lease_pct() -> f64 {
4723    0.30
4724}
4725
4726fn default_avg_lease_term() -> u32 {
4727    60
4728}
4729
4730fn default_real_estate_pct() -> f64 {
4731    0.40
4732}
4733
4734impl Default for LeaseAccountingConfig {
4735    fn default() -> Self {
4736        Self {
4737            enabled: false,
4738            lease_count: default_lease_count(),
4739            finance_lease_percent: default_finance_lease_pct(),
4740            avg_lease_term_months: default_avg_lease_term(),
4741            generate_amortization: true,
4742            real_estate_percent: default_real_estate_pct(),
4743        }
4744    }
4745}
4746
4747/// Fair value measurement configuration (ASC 820/IFRS 13).
4748#[derive(Debug, Clone, Serialize, Deserialize)]
4749pub struct FairValueConfig {
4750    /// Enable fair value measurement generation
4751    #[serde(default)]
4752    pub enabled: bool,
4753
4754    /// Number of fair value measurements to generate
4755    #[serde(default = "default_fv_count")]
4756    pub measurement_count: usize,
4757
4758    /// Level 1 (quoted prices) percentage
4759    #[serde(default = "default_level1_pct")]
4760    pub level1_percent: f64,
4761
4762    /// Level 2 (observable inputs) percentage
4763    #[serde(default = "default_level2_pct")]
4764    pub level2_percent: f64,
4765
4766    /// Level 3 (unobservable inputs) percentage
4767    #[serde(default = "default_level3_pct")]
4768    pub level3_percent: f64,
4769
4770    /// Include sensitivity analysis for Level 3
4771    #[serde(default)]
4772    pub include_sensitivity_analysis: bool,
4773}
4774
4775fn default_fv_count() -> usize {
4776    25
4777}
4778
4779fn default_level1_pct() -> f64 {
4780    0.40
4781}
4782
4783fn default_level2_pct() -> f64 {
4784    0.35
4785}
4786
4787fn default_level3_pct() -> f64 {
4788    0.25
4789}
4790
4791impl Default for FairValueConfig {
4792    fn default() -> Self {
4793        Self {
4794            enabled: false,
4795            measurement_count: default_fv_count(),
4796            level1_percent: default_level1_pct(),
4797            level2_percent: default_level2_pct(),
4798            level3_percent: default_level3_pct(),
4799            include_sensitivity_analysis: false,
4800        }
4801    }
4802}
4803
4804/// Impairment testing configuration (ASC 360/IAS 36).
4805#[derive(Debug, Clone, Serialize, Deserialize)]
4806pub struct ImpairmentConfig {
4807    /// Enable impairment testing generation
4808    #[serde(default)]
4809    pub enabled: bool,
4810
4811    /// Number of impairment tests to generate
4812    #[serde(default = "default_impairment_count")]
4813    pub test_count: usize,
4814
4815    /// Rate of tests resulting in impairment
4816    #[serde(default = "default_impairment_rate")]
4817    pub impairment_rate: f64,
4818
4819    /// Generate cash flow projections
4820    #[serde(default = "default_true")]
4821    pub generate_projections: bool,
4822
4823    /// Include goodwill impairment tests
4824    #[serde(default)]
4825    pub include_goodwill: bool,
4826}
4827
4828fn default_impairment_count() -> usize {
4829    15
4830}
4831
4832fn default_impairment_rate() -> f64 {
4833    0.10
4834}
4835
4836impl Default for ImpairmentConfig {
4837    fn default() -> Self {
4838        Self {
4839            enabled: false,
4840            test_count: default_impairment_count(),
4841            impairment_rate: default_impairment_rate(),
4842            generate_projections: true,
4843            include_goodwill: false,
4844        }
4845    }
4846}
4847
4848// =============================================================================
4849// Audit Standards Configuration
4850// =============================================================================
4851
4852/// Audit standards framework configuration for generating standards-compliant audit data.
4853///
4854/// Supports ISA (International Standards on Auditing) and PCAOB standards:
4855/// - ISA 200-720: Complete coverage of audit standards
4856/// - ISA 520: Analytical Procedures
4857/// - ISA 505: External Confirmations
4858/// - ISA 700/705/706/701: Audit Reports
4859/// - PCAOB AS 2201: ICFR Auditing
4860#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4861pub struct AuditStandardsConfig {
4862    /// Enable audit standards generation
4863    #[serde(default)]
4864    pub enabled: bool,
4865
4866    /// ISA compliance configuration
4867    #[serde(default)]
4868    pub isa_compliance: IsaComplianceConfig,
4869
4870    /// Analytical procedures configuration (ISA 520)
4871    #[serde(default)]
4872    pub analytical_procedures: AnalyticalProceduresConfig,
4873
4874    /// External confirmations configuration (ISA 505)
4875    #[serde(default)]
4876    pub confirmations: ConfirmationsConfig,
4877
4878    /// Audit opinion configuration (ISA 700/705/706/701)
4879    #[serde(default)]
4880    pub opinion: AuditOpinionConfig,
4881
4882    /// Generate complete audit trail with traceability
4883    #[serde(default)]
4884    pub generate_audit_trail: bool,
4885
4886    /// SOX 302/404 compliance configuration
4887    #[serde(default)]
4888    pub sox: SoxComplianceConfig,
4889
4890    /// PCAOB-specific configuration
4891    #[serde(default)]
4892    pub pcaob: PcaobConfig,
4893}
4894
4895/// ISA compliance level configuration.
4896#[derive(Debug, Clone, Serialize, Deserialize)]
4897pub struct IsaComplianceConfig {
4898    /// Enable ISA compliance tracking
4899    #[serde(default)]
4900    pub enabled: bool,
4901
4902    /// Compliance level: "basic", "standard", "comprehensive"
4903    #[serde(default = "default_compliance_level")]
4904    pub compliance_level: String,
4905
4906    /// Generate ISA requirement mappings
4907    #[serde(default = "default_true")]
4908    pub generate_isa_mappings: bool,
4909
4910    /// Generate ISA coverage summary
4911    #[serde(default = "default_true")]
4912    pub generate_coverage_summary: bool,
4913
4914    /// Include PCAOB standard mappings (for dual framework)
4915    #[serde(default)]
4916    pub include_pcaob: bool,
4917
4918    /// Framework to use: "isa", "pcaob", "dual"
4919    #[serde(default = "default_audit_framework")]
4920    pub framework: String,
4921}
4922
4923fn default_compliance_level() -> String {
4924    "standard".to_string()
4925}
4926
4927fn default_audit_framework() -> String {
4928    "isa".to_string()
4929}
4930
4931impl Default for IsaComplianceConfig {
4932    fn default() -> Self {
4933        Self {
4934            enabled: false,
4935            compliance_level: default_compliance_level(),
4936            generate_isa_mappings: true,
4937            generate_coverage_summary: true,
4938            include_pcaob: false,
4939            framework: default_audit_framework(),
4940        }
4941    }
4942}
4943
4944/// Analytical procedures configuration (ISA 520).
4945#[derive(Debug, Clone, Serialize, Deserialize)]
4946pub struct AnalyticalProceduresConfig {
4947    /// Enable analytical procedures generation
4948    #[serde(default)]
4949    pub enabled: bool,
4950
4951    /// Number of procedures per account/area
4952    #[serde(default = "default_procedures_per_account")]
4953    pub procedures_per_account: usize,
4954
4955    /// Probability of variance exceeding threshold
4956    #[serde(default = "default_variance_probability")]
4957    pub variance_probability: f64,
4958
4959    /// Include variance investigations
4960    #[serde(default = "default_true")]
4961    pub generate_investigations: bool,
4962
4963    /// Include financial ratio analysis
4964    #[serde(default = "default_true")]
4965    pub include_ratio_analysis: bool,
4966}
4967
4968fn default_procedures_per_account() -> usize {
4969    3
4970}
4971
4972fn default_variance_probability() -> f64 {
4973    0.20
4974}
4975
4976impl Default for AnalyticalProceduresConfig {
4977    fn default() -> Self {
4978        Self {
4979            enabled: false,
4980            procedures_per_account: default_procedures_per_account(),
4981            variance_probability: default_variance_probability(),
4982            generate_investigations: true,
4983            include_ratio_analysis: true,
4984        }
4985    }
4986}
4987
4988/// External confirmations configuration (ISA 505).
4989#[derive(Debug, Clone, Serialize, Deserialize)]
4990pub struct ConfirmationsConfig {
4991    /// Enable confirmation generation
4992    #[serde(default)]
4993    pub enabled: bool,
4994
4995    /// Number of confirmations to generate
4996    #[serde(default = "default_confirmation_count")]
4997    pub confirmation_count: usize,
4998
4999    /// Positive response rate
5000    #[serde(default = "default_positive_response_rate")]
5001    pub positive_response_rate: f64,
5002
5003    /// Exception rate (responses with differences)
5004    #[serde(default = "default_exception_rate_confirm")]
5005    pub exception_rate: f64,
5006
5007    /// Non-response rate
5008    #[serde(default = "default_non_response_rate")]
5009    pub non_response_rate: f64,
5010
5011    /// Generate alternative procedures for non-responses
5012    #[serde(default = "default_true")]
5013    pub generate_alternative_procedures: bool,
5014}
5015
5016fn default_confirmation_count() -> usize {
5017    50
5018}
5019
5020fn default_positive_response_rate() -> f64 {
5021    0.85
5022}
5023
5024fn default_exception_rate_confirm() -> f64 {
5025    0.10
5026}
5027
5028fn default_non_response_rate() -> f64 {
5029    0.05
5030}
5031
5032impl Default for ConfirmationsConfig {
5033    fn default() -> Self {
5034        Self {
5035            enabled: false,
5036            confirmation_count: default_confirmation_count(),
5037            positive_response_rate: default_positive_response_rate(),
5038            exception_rate: default_exception_rate_confirm(),
5039            non_response_rate: default_non_response_rate(),
5040            generate_alternative_procedures: true,
5041        }
5042    }
5043}
5044
5045/// Audit opinion configuration (ISA 700/705/706/701).
5046#[derive(Debug, Clone, Serialize, Deserialize)]
5047pub struct AuditOpinionConfig {
5048    /// Enable audit opinion generation
5049    #[serde(default)]
5050    pub enabled: bool,
5051
5052    /// Generate Key Audit Matters (KAM) / Critical Audit Matters (CAM)
5053    #[serde(default = "default_true")]
5054    pub generate_kam: bool,
5055
5056    /// Average number of KAMs/CAMs per opinion
5057    #[serde(default = "default_kam_count")]
5058    pub average_kam_count: usize,
5059
5060    /// Rate of modified opinions
5061    #[serde(default = "default_modified_opinion_rate")]
5062    pub modified_opinion_rate: f64,
5063
5064    /// Include emphasis of matter paragraphs
5065    #[serde(default)]
5066    pub include_emphasis_of_matter: bool,
5067
5068    /// Include going concern conclusions
5069    #[serde(default = "default_true")]
5070    pub include_going_concern: bool,
5071}
5072
5073fn default_kam_count() -> usize {
5074    3
5075}
5076
5077fn default_modified_opinion_rate() -> f64 {
5078    0.05
5079}
5080
5081impl Default for AuditOpinionConfig {
5082    fn default() -> Self {
5083        Self {
5084            enabled: false,
5085            generate_kam: true,
5086            average_kam_count: default_kam_count(),
5087            modified_opinion_rate: default_modified_opinion_rate(),
5088            include_emphasis_of_matter: false,
5089            include_going_concern: true,
5090        }
5091    }
5092}
5093
5094/// SOX compliance configuration (Sections 302/404).
5095#[derive(Debug, Clone, Serialize, Deserialize)]
5096pub struct SoxComplianceConfig {
5097    /// Enable SOX compliance generation
5098    #[serde(default)]
5099    pub enabled: bool,
5100
5101    /// Generate Section 302 CEO/CFO certifications
5102    #[serde(default = "default_true")]
5103    pub generate_302_certifications: bool,
5104
5105    /// Generate Section 404 ICFR assessments
5106    #[serde(default = "default_true")]
5107    pub generate_404_assessments: bool,
5108
5109    /// Materiality threshold for SOX testing
5110    #[serde(default = "default_sox_materiality_threshold")]
5111    pub materiality_threshold: f64,
5112
5113    /// Rate of material weaknesses
5114    #[serde(default = "default_material_weakness_rate")]
5115    pub material_weakness_rate: f64,
5116
5117    /// Rate of significant deficiencies
5118    #[serde(default = "default_significant_deficiency_rate")]
5119    pub significant_deficiency_rate: f64,
5120}
5121
5122fn default_material_weakness_rate() -> f64 {
5123    0.02
5124}
5125
5126fn default_significant_deficiency_rate() -> f64 {
5127    0.08
5128}
5129
5130impl Default for SoxComplianceConfig {
5131    fn default() -> Self {
5132        Self {
5133            enabled: false,
5134            generate_302_certifications: true,
5135            generate_404_assessments: true,
5136            materiality_threshold: default_sox_materiality_threshold(),
5137            material_weakness_rate: default_material_weakness_rate(),
5138            significant_deficiency_rate: default_significant_deficiency_rate(),
5139        }
5140    }
5141}
5142
5143/// PCAOB-specific configuration.
5144#[derive(Debug, Clone, Serialize, Deserialize)]
5145pub struct PcaobConfig {
5146    /// Enable PCAOB-specific elements
5147    #[serde(default)]
5148    pub enabled: bool,
5149
5150    /// Treat as PCAOB audit (vs ISA-only)
5151    #[serde(default)]
5152    pub is_pcaob_audit: bool,
5153
5154    /// Generate Critical Audit Matters (CAM)
5155    #[serde(default = "default_true")]
5156    pub generate_cam: bool,
5157
5158    /// Include ICFR opinion (for integrated audits)
5159    #[serde(default)]
5160    pub include_icfr_opinion: bool,
5161
5162    /// Generate PCAOB-ISA standard mappings
5163    #[serde(default)]
5164    pub generate_standard_mappings: bool,
5165}
5166
5167impl Default for PcaobConfig {
5168    fn default() -> Self {
5169        Self {
5170            enabled: false,
5171            is_pcaob_audit: false,
5172            generate_cam: true,
5173            include_icfr_opinion: false,
5174            generate_standard_mappings: false,
5175        }
5176    }
5177}
5178
5179// =============================================================================
5180// Advanced Distribution Configuration
5181// =============================================================================
5182
5183/// Advanced distribution configuration for realistic data generation.
5184///
5185/// This section enables sophisticated distribution models including:
5186/// - Mixture models (multi-modal distributions)
5187/// - Cross-field correlations
5188/// - Conditional distributions
5189/// - Regime changes and economic cycles
5190/// - Statistical validation
5191#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5192pub struct AdvancedDistributionConfig {
5193    /// Enable advanced distribution features.
5194    #[serde(default)]
5195    pub enabled: bool,
5196
5197    /// Mixture model configuration for amounts.
5198    #[serde(default)]
5199    pub amounts: MixtureDistributionSchemaConfig,
5200
5201    /// Cross-field correlation configuration.
5202    #[serde(default)]
5203    pub correlations: CorrelationSchemaConfig,
5204
5205    /// Conditional distribution configurations.
5206    #[serde(default)]
5207    pub conditional: Vec<ConditionalDistributionSchemaConfig>,
5208
5209    /// Regime change configuration.
5210    #[serde(default)]
5211    pub regime_changes: RegimeChangeSchemaConfig,
5212
5213    /// Industry-specific distribution profile.
5214    #[serde(default)]
5215    pub industry_profile: Option<IndustryProfileType>,
5216
5217    /// Statistical validation configuration.
5218    #[serde(default)]
5219    pub validation: StatisticalValidationSchemaConfig,
5220}
5221
5222/// Industry profile types for pre-configured distribution settings.
5223#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5224#[serde(rename_all = "snake_case")]
5225pub enum IndustryProfileType {
5226    /// Retail industry profile (POS sales, inventory, seasonal)
5227    Retail,
5228    /// Manufacturing industry profile (raw materials, maintenance, capital)
5229    Manufacturing,
5230    /// Financial services profile (wire transfers, ACH, fee income)
5231    FinancialServices,
5232    /// Healthcare profile (claims, procedures, supplies)
5233    Healthcare,
5234    /// Technology profile (subscriptions, services, R&D)
5235    Technology,
5236}
5237
5238/// Mixture model distribution configuration.
5239#[derive(Debug, Clone, Serialize, Deserialize)]
5240pub struct MixtureDistributionSchemaConfig {
5241    /// Enable mixture model for amount generation.
5242    #[serde(default)]
5243    pub enabled: bool,
5244
5245    /// Distribution type: "gaussian" or "lognormal".
5246    #[serde(default = "default_mixture_type")]
5247    pub distribution_type: MixtureDistributionType,
5248
5249    /// Mixture components with weights.
5250    #[serde(default)]
5251    pub components: Vec<MixtureComponentConfig>,
5252
5253    /// Minimum value constraint.
5254    #[serde(default = "default_min_amount")]
5255    pub min_value: f64,
5256
5257    /// Maximum value constraint (optional).
5258    #[serde(default)]
5259    pub max_value: Option<f64>,
5260
5261    /// Decimal places for rounding.
5262    #[serde(default = "default_decimal_places")]
5263    pub decimal_places: u8,
5264}
5265
5266fn default_mixture_type() -> MixtureDistributionType {
5267    MixtureDistributionType::LogNormal
5268}
5269
5270fn default_min_amount() -> f64 {
5271    0.01
5272}
5273
5274fn default_decimal_places() -> u8 {
5275    2
5276}
5277
5278impl Default for MixtureDistributionSchemaConfig {
5279    fn default() -> Self {
5280        Self {
5281            enabled: false,
5282            distribution_type: MixtureDistributionType::LogNormal,
5283            components: Vec::new(),
5284            min_value: 0.01,
5285            max_value: None,
5286            decimal_places: 2,
5287        }
5288    }
5289}
5290
5291/// Mixture distribution type.
5292#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5293#[serde(rename_all = "snake_case")]
5294pub enum MixtureDistributionType {
5295    /// Gaussian (normal) mixture
5296    Gaussian,
5297    /// Log-normal mixture (for positive amounts)
5298    #[default]
5299    LogNormal,
5300}
5301
5302/// Configuration for a single mixture component.
5303#[derive(Debug, Clone, Serialize, Deserialize)]
5304pub struct MixtureComponentConfig {
5305    /// Weight of this component (must sum to 1.0 across all components).
5306    pub weight: f64,
5307
5308    /// Location parameter (mean for Gaussian, mu for log-normal).
5309    pub mu: f64,
5310
5311    /// Scale parameter (std dev for Gaussian, sigma for log-normal).
5312    pub sigma: f64,
5313
5314    /// Optional label for this component (e.g., "routine", "significant", "major").
5315    #[serde(default)]
5316    pub label: Option<String>,
5317}
5318
5319/// Cross-field correlation configuration.
5320#[derive(Debug, Clone, Serialize, Deserialize)]
5321pub struct CorrelationSchemaConfig {
5322    /// Enable correlation modeling.
5323    #[serde(default)]
5324    pub enabled: bool,
5325
5326    /// Copula type for dependency modeling.
5327    #[serde(default)]
5328    pub copula_type: CopulaSchemaType,
5329
5330    /// Field definitions for correlation.
5331    #[serde(default)]
5332    pub fields: Vec<CorrelatedFieldConfig>,
5333
5334    /// Correlation matrix (upper triangular, row-major).
5335    /// For n fields, this should have n*(n-1)/2 values.
5336    #[serde(default)]
5337    pub matrix: Vec<f64>,
5338
5339    /// Expected correlations for validation.
5340    #[serde(default)]
5341    pub expected_correlations: Vec<ExpectedCorrelationConfig>,
5342}
5343
5344impl Default for CorrelationSchemaConfig {
5345    fn default() -> Self {
5346        Self {
5347            enabled: false,
5348            copula_type: CopulaSchemaType::Gaussian,
5349            fields: Vec::new(),
5350            matrix: Vec::new(),
5351            expected_correlations: Vec::new(),
5352        }
5353    }
5354}
5355
5356/// Copula type for dependency modeling.
5357#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5358#[serde(rename_all = "snake_case")]
5359pub enum CopulaSchemaType {
5360    /// Gaussian copula (symmetric, no tail dependence)
5361    #[default]
5362    Gaussian,
5363    /// Clayton copula (lower tail dependence)
5364    Clayton,
5365    /// Gumbel copula (upper tail dependence)
5366    Gumbel,
5367    /// Frank copula (symmetric, no tail dependence)
5368    Frank,
5369    /// Student-t copula (both tail dependencies)
5370    StudentT,
5371}
5372
5373/// Configuration for a correlated field.
5374#[derive(Debug, Clone, Serialize, Deserialize)]
5375pub struct CorrelatedFieldConfig {
5376    /// Field name.
5377    pub name: String,
5378
5379    /// Marginal distribution type.
5380    #[serde(default)]
5381    pub distribution: MarginalDistributionConfig,
5382}
5383
5384/// Marginal distribution configuration.
5385#[derive(Debug, Clone, Serialize, Deserialize)]
5386#[serde(tag = "type", rename_all = "snake_case")]
5387pub enum MarginalDistributionConfig {
5388    /// Normal distribution.
5389    Normal {
5390        /// Mean
5391        mu: f64,
5392        /// Standard deviation
5393        sigma: f64,
5394    },
5395    /// Log-normal distribution.
5396    LogNormal {
5397        /// Location parameter
5398        mu: f64,
5399        /// Scale parameter
5400        sigma: f64,
5401    },
5402    /// Uniform distribution.
5403    Uniform {
5404        /// Minimum value
5405        min: f64,
5406        /// Maximum value
5407        max: f64,
5408    },
5409    /// Discrete uniform distribution.
5410    DiscreteUniform {
5411        /// Minimum integer value
5412        min: i32,
5413        /// Maximum integer value
5414        max: i32,
5415    },
5416}
5417
5418impl Default for MarginalDistributionConfig {
5419    fn default() -> Self {
5420        Self::Normal {
5421            mu: 0.0,
5422            sigma: 1.0,
5423        }
5424    }
5425}
5426
5427/// Expected correlation for validation.
5428#[derive(Debug, Clone, Serialize, Deserialize)]
5429pub struct ExpectedCorrelationConfig {
5430    /// First field name.
5431    pub field1: String,
5432    /// Second field name.
5433    pub field2: String,
5434    /// Expected correlation coefficient.
5435    pub expected_r: f64,
5436    /// Acceptable tolerance.
5437    #[serde(default = "default_correlation_tolerance")]
5438    pub tolerance: f64,
5439}
5440
5441fn default_correlation_tolerance() -> f64 {
5442    0.10
5443}
5444
5445/// Conditional distribution configuration.
5446#[derive(Debug, Clone, Serialize, Deserialize)]
5447pub struct ConditionalDistributionSchemaConfig {
5448    /// Output field name to generate.
5449    pub output_field: String,
5450
5451    /// Input field name that conditions the distribution.
5452    pub input_field: String,
5453
5454    /// Breakpoints defining distribution changes.
5455    #[serde(default)]
5456    pub breakpoints: Vec<ConditionalBreakpointConfig>,
5457
5458    /// Default distribution when below all breakpoints.
5459    #[serde(default)]
5460    pub default_distribution: ConditionalDistributionParamsConfig,
5461
5462    /// Minimum output value constraint.
5463    #[serde(default)]
5464    pub min_value: Option<f64>,
5465
5466    /// Maximum output value constraint.
5467    #[serde(default)]
5468    pub max_value: Option<f64>,
5469
5470    /// Decimal places for output rounding.
5471    #[serde(default = "default_decimal_places")]
5472    pub decimal_places: u8,
5473}
5474
5475/// Breakpoint for conditional distribution.
5476#[derive(Debug, Clone, Serialize, Deserialize)]
5477pub struct ConditionalBreakpointConfig {
5478    /// Input value threshold.
5479    pub threshold: f64,
5480
5481    /// Distribution to use when input >= threshold.
5482    pub distribution: ConditionalDistributionParamsConfig,
5483}
5484
5485/// Distribution parameters for conditional distributions.
5486#[derive(Debug, Clone, Serialize, Deserialize)]
5487#[serde(tag = "type", rename_all = "snake_case")]
5488pub enum ConditionalDistributionParamsConfig {
5489    /// Fixed value.
5490    Fixed {
5491        /// The fixed value
5492        value: f64,
5493    },
5494    /// Normal distribution.
5495    Normal {
5496        /// Mean
5497        mu: f64,
5498        /// Standard deviation
5499        sigma: f64,
5500    },
5501    /// Log-normal distribution.
5502    LogNormal {
5503        /// Location parameter
5504        mu: f64,
5505        /// Scale parameter
5506        sigma: f64,
5507    },
5508    /// Uniform distribution.
5509    Uniform {
5510        /// Minimum
5511        min: f64,
5512        /// Maximum
5513        max: f64,
5514    },
5515    /// Beta distribution (scaled).
5516    Beta {
5517        /// Alpha parameter
5518        alpha: f64,
5519        /// Beta parameter
5520        beta: f64,
5521        /// Minimum output value
5522        min: f64,
5523        /// Maximum output value
5524        max: f64,
5525    },
5526    /// Discrete values with weights.
5527    Discrete {
5528        /// Possible values
5529        values: Vec<f64>,
5530        /// Weights (should sum to 1.0)
5531        weights: Vec<f64>,
5532    },
5533}
5534
5535impl Default for ConditionalDistributionParamsConfig {
5536    fn default() -> Self {
5537        Self::Normal {
5538            mu: 0.0,
5539            sigma: 1.0,
5540        }
5541    }
5542}
5543
5544/// Regime change configuration.
5545#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5546pub struct RegimeChangeSchemaConfig {
5547    /// Enable regime change modeling.
5548    #[serde(default)]
5549    pub enabled: bool,
5550
5551    /// List of regime changes.
5552    #[serde(default)]
5553    pub changes: Vec<RegimeChangeEventConfig>,
5554
5555    /// Economic cycle configuration.
5556    #[serde(default)]
5557    pub economic_cycle: Option<EconomicCycleSchemaConfig>,
5558
5559    /// Parameter drift configurations.
5560    #[serde(default)]
5561    pub parameter_drifts: Vec<ParameterDriftSchemaConfig>,
5562}
5563
5564/// A single regime change event.
5565#[derive(Debug, Clone, Serialize, Deserialize)]
5566pub struct RegimeChangeEventConfig {
5567    /// Date when the change occurs (ISO 8601 format).
5568    pub date: String,
5569
5570    /// Type of regime change.
5571    pub change_type: RegimeChangeTypeConfig,
5572
5573    /// Description of the change.
5574    #[serde(default)]
5575    pub description: Option<String>,
5576
5577    /// Effects of this regime change.
5578    #[serde(default)]
5579    pub effects: Vec<RegimeEffectConfig>,
5580}
5581
5582/// Type of regime change.
5583#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5584#[serde(rename_all = "snake_case")]
5585pub enum RegimeChangeTypeConfig {
5586    /// Acquisition - sudden volume and amount increase
5587    Acquisition,
5588    /// Divestiture - sudden volume and amount decrease
5589    Divestiture,
5590    /// Price increase - amounts increase
5591    PriceIncrease,
5592    /// Price decrease - amounts decrease
5593    PriceDecrease,
5594    /// New product launch - volume ramp-up
5595    ProductLaunch,
5596    /// Product discontinuation - volume ramp-down
5597    ProductDiscontinuation,
5598    /// Policy change - affects patterns
5599    PolicyChange,
5600    /// Competitor entry - market disruption
5601    CompetitorEntry,
5602    /// Custom effect
5603    Custom,
5604}
5605
5606/// Effect of a regime change on a specific field.
5607#[derive(Debug, Clone, Serialize, Deserialize)]
5608pub struct RegimeEffectConfig {
5609    /// Field being affected.
5610    pub field: String,
5611
5612    /// Multiplier to apply (1.0 = no change, 1.5 = 50% increase).
5613    pub multiplier: f64,
5614}
5615
5616/// Economic cycle configuration.
5617#[derive(Debug, Clone, Serialize, Deserialize)]
5618pub struct EconomicCycleSchemaConfig {
5619    /// Enable economic cycle modeling.
5620    #[serde(default)]
5621    pub enabled: bool,
5622
5623    /// Cycle period in months (e.g., 48 for 4-year business cycle).
5624    #[serde(default = "default_cycle_period")]
5625    pub period_months: u32,
5626
5627    /// Amplitude of cycle effect (0.0-1.0).
5628    #[serde(default = "default_cycle_amplitude")]
5629    pub amplitude: f64,
5630
5631    /// Phase offset in months.
5632    #[serde(default)]
5633    pub phase_offset: u32,
5634
5635    /// Recession periods (start_month, duration_months).
5636    #[serde(default)]
5637    pub recessions: Vec<RecessionPeriodConfig>,
5638}
5639
5640fn default_cycle_period() -> u32 {
5641    48
5642}
5643
5644fn default_cycle_amplitude() -> f64 {
5645    0.15
5646}
5647
5648impl Default for EconomicCycleSchemaConfig {
5649    fn default() -> Self {
5650        Self {
5651            enabled: false,
5652            period_months: 48,
5653            amplitude: 0.15,
5654            phase_offset: 0,
5655            recessions: Vec::new(),
5656        }
5657    }
5658}
5659
5660/// Recession period configuration.
5661#[derive(Debug, Clone, Serialize, Deserialize)]
5662pub struct RecessionPeriodConfig {
5663    /// Start month (0-indexed from generation start).
5664    pub start_month: u32,
5665
5666    /// Duration in months.
5667    pub duration_months: u32,
5668
5669    /// Severity (0.0-1.0, affects volume reduction).
5670    #[serde(default = "default_recession_severity")]
5671    pub severity: f64,
5672}
5673
5674fn default_recession_severity() -> f64 {
5675    0.20
5676}
5677
5678/// Parameter drift configuration.
5679#[derive(Debug, Clone, Serialize, Deserialize)]
5680pub struct ParameterDriftSchemaConfig {
5681    /// Parameter being drifted.
5682    pub parameter: String,
5683
5684    /// Drift type.
5685    pub drift_type: ParameterDriftTypeConfig,
5686
5687    /// Start value.
5688    pub start_value: f64,
5689
5690    /// End value.
5691    pub end_value: f64,
5692
5693    /// Start period (month, 0-indexed).
5694    #[serde(default)]
5695    pub start_period: u32,
5696
5697    /// End period (month, optional - defaults to end of generation).
5698    #[serde(default)]
5699    pub end_period: Option<u32>,
5700}
5701
5702/// Parameter drift type.
5703#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5704#[serde(rename_all = "snake_case")]
5705pub enum ParameterDriftTypeConfig {
5706    /// Linear interpolation
5707    #[default]
5708    Linear,
5709    /// Exponential growth/decay
5710    Exponential,
5711    /// S-curve (logistic)
5712    Logistic,
5713    /// Step function
5714    Step,
5715}
5716
5717/// Statistical validation configuration.
5718#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5719pub struct StatisticalValidationSchemaConfig {
5720    /// Enable statistical validation.
5721    #[serde(default)]
5722    pub enabled: bool,
5723
5724    /// Statistical tests to run.
5725    #[serde(default)]
5726    pub tests: Vec<StatisticalTestConfig>,
5727
5728    /// Validation reporting configuration.
5729    #[serde(default)]
5730    pub reporting: ValidationReportingConfig,
5731}
5732
5733/// Statistical test configuration.
5734#[derive(Debug, Clone, Serialize, Deserialize)]
5735#[serde(tag = "type", rename_all = "snake_case")]
5736pub enum StatisticalTestConfig {
5737    /// Benford's Law first digit test.
5738    BenfordFirstDigit {
5739        /// Threshold MAD for failure.
5740        #[serde(default = "default_benford_threshold")]
5741        threshold_mad: f64,
5742        /// Warning MAD threshold.
5743        #[serde(default = "default_benford_warning")]
5744        warning_mad: f64,
5745    },
5746    /// Distribution fit test.
5747    DistributionFit {
5748        /// Target distribution to test.
5749        target: TargetDistributionConfig,
5750        /// K-S test significance level.
5751        #[serde(default = "default_ks_significance")]
5752        ks_significance: f64,
5753        /// Test method (ks, anderson_darling, chi_squared).
5754        #[serde(default)]
5755        method: DistributionFitMethod,
5756    },
5757    /// Correlation check.
5758    CorrelationCheck {
5759        /// Expected correlations to validate.
5760        expected_correlations: Vec<ExpectedCorrelationConfig>,
5761    },
5762    /// Chi-squared test.
5763    ChiSquared {
5764        /// Number of bins.
5765        #[serde(default = "default_chi_squared_bins")]
5766        bins: usize,
5767        /// Significance level.
5768        #[serde(default = "default_chi_squared_significance")]
5769        significance: f64,
5770    },
5771    /// Anderson-Darling test.
5772    AndersonDarling {
5773        /// Target distribution.
5774        target: TargetDistributionConfig,
5775        /// Significance level.
5776        #[serde(default = "default_ad_significance")]
5777        significance: f64,
5778    },
5779}
5780
5781fn default_benford_threshold() -> f64 {
5782    0.015
5783}
5784
5785fn default_benford_warning() -> f64 {
5786    0.010
5787}
5788
5789fn default_ks_significance() -> f64 {
5790    0.05
5791}
5792
5793fn default_chi_squared_bins() -> usize {
5794    10
5795}
5796
5797fn default_chi_squared_significance() -> f64 {
5798    0.05
5799}
5800
5801fn default_ad_significance() -> f64 {
5802    0.05
5803}
5804
5805/// Target distribution for fit tests.
5806#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5807#[serde(rename_all = "snake_case")]
5808pub enum TargetDistributionConfig {
5809    /// Normal distribution
5810    Normal,
5811    /// Log-normal distribution
5812    #[default]
5813    LogNormal,
5814    /// Exponential distribution
5815    Exponential,
5816    /// Uniform distribution
5817    Uniform,
5818}
5819
5820/// Distribution fit test method.
5821#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5822#[serde(rename_all = "snake_case")]
5823pub enum DistributionFitMethod {
5824    /// Kolmogorov-Smirnov test
5825    #[default]
5826    KolmogorovSmirnov,
5827    /// Anderson-Darling test
5828    AndersonDarling,
5829    /// Chi-squared test
5830    ChiSquared,
5831}
5832
5833/// Validation reporting configuration.
5834#[derive(Debug, Clone, Serialize, Deserialize)]
5835pub struct ValidationReportingConfig {
5836    /// Output validation report to file.
5837    #[serde(default)]
5838    pub output_report: bool,
5839
5840    /// Report format.
5841    #[serde(default)]
5842    pub format: ValidationReportFormat,
5843
5844    /// Fail generation if validation fails.
5845    #[serde(default)]
5846    pub fail_on_error: bool,
5847
5848    /// Include detailed statistics in report.
5849    #[serde(default = "default_true")]
5850    pub include_details: bool,
5851}
5852
5853impl Default for ValidationReportingConfig {
5854    fn default() -> Self {
5855        Self {
5856            output_report: false,
5857            format: ValidationReportFormat::Json,
5858            fail_on_error: false,
5859            include_details: true,
5860        }
5861    }
5862}
5863
5864/// Validation report format.
5865#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5866#[serde(rename_all = "snake_case")]
5867pub enum ValidationReportFormat {
5868    /// JSON format
5869    #[default]
5870    Json,
5871    /// YAML format
5872    Yaml,
5873    /// HTML report
5874    Html,
5875}
5876
5877// =============================================================================
5878// Temporal Patterns Configuration
5879// =============================================================================
5880
5881/// Temporal patterns configuration for business days, period-end dynamics, and processing lags.
5882///
5883/// This section enables sophisticated temporal modeling including:
5884/// - Business day calculations and settlement dates
5885/// - Regional holiday calendars
5886/// - Period-end decay curves (non-flat volume spikes)
5887/// - Processing lag modeling (event-to-posting delays)
5888#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5889pub struct TemporalPatternsConfig {
5890    /// Enable temporal patterns features.
5891    #[serde(default)]
5892    pub enabled: bool,
5893
5894    /// Business day calculation configuration.
5895    #[serde(default)]
5896    pub business_days: BusinessDaySchemaConfig,
5897
5898    /// Regional calendar configuration.
5899    #[serde(default)]
5900    pub calendars: CalendarSchemaConfig,
5901
5902    /// Period-end dynamics configuration.
5903    #[serde(default)]
5904    pub period_end: PeriodEndSchemaConfig,
5905
5906    /// Processing lag configuration.
5907    #[serde(default)]
5908    pub processing_lags: ProcessingLagSchemaConfig,
5909
5910    /// Fiscal calendar configuration (custom year start, 4-4-5, 13-period).
5911    #[serde(default)]
5912    pub fiscal_calendar: FiscalCalendarSchemaConfig,
5913
5914    /// Intra-day patterns configuration (morning spike, lunch dip, EOD rush).
5915    #[serde(default)]
5916    pub intraday: IntraDaySchemaConfig,
5917
5918    /// Timezone handling configuration.
5919    #[serde(default)]
5920    pub timezones: TimezoneSchemaConfig,
5921}
5922
5923/// Business day calculation configuration.
5924#[derive(Debug, Clone, Serialize, Deserialize)]
5925pub struct BusinessDaySchemaConfig {
5926    /// Enable business day calculations.
5927    #[serde(default = "default_true")]
5928    pub enabled: bool,
5929
5930    /// Half-day policy: "full_day", "half_day", "non_business_day".
5931    #[serde(default = "default_half_day_policy")]
5932    pub half_day_policy: String,
5933
5934    /// Settlement rules configuration.
5935    #[serde(default)]
5936    pub settlement_rules: SettlementRulesSchemaConfig,
5937
5938    /// Month-end convention: "modified_following", "preceding", "following", "end_of_month".
5939    #[serde(default = "default_month_end_convention")]
5940    pub month_end_convention: String,
5941
5942    /// Weekend days (e.g., ["saturday", "sunday"] or ["friday", "saturday"] for Middle East).
5943    #[serde(default)]
5944    pub weekend_days: Option<Vec<String>>,
5945}
5946
5947fn default_half_day_policy() -> String {
5948    "half_day".to_string()
5949}
5950
5951fn default_month_end_convention() -> String {
5952    "modified_following".to_string()
5953}
5954
5955impl Default for BusinessDaySchemaConfig {
5956    fn default() -> Self {
5957        Self {
5958            enabled: true,
5959            half_day_policy: "half_day".to_string(),
5960            settlement_rules: SettlementRulesSchemaConfig::default(),
5961            month_end_convention: "modified_following".to_string(),
5962            weekend_days: None,
5963        }
5964    }
5965}
5966
5967/// Settlement rules configuration.
5968#[derive(Debug, Clone, Serialize, Deserialize)]
5969pub struct SettlementRulesSchemaConfig {
5970    /// Equity settlement days (T+N).
5971    #[serde(default = "default_settlement_2")]
5972    pub equity_days: i32,
5973
5974    /// Government bonds settlement days.
5975    #[serde(default = "default_settlement_1")]
5976    pub government_bonds_days: i32,
5977
5978    /// FX spot settlement days.
5979    #[serde(default = "default_settlement_2")]
5980    pub fx_spot_days: i32,
5981
5982    /// Corporate bonds settlement days.
5983    #[serde(default = "default_settlement_2")]
5984    pub corporate_bonds_days: i32,
5985
5986    /// Wire transfer cutoff time (HH:MM format).
5987    #[serde(default = "default_wire_cutoff")]
5988    pub wire_cutoff_time: String,
5989
5990    /// International wire settlement days.
5991    #[serde(default = "default_settlement_1")]
5992    pub wire_international_days: i32,
5993
5994    /// ACH settlement days.
5995    #[serde(default = "default_settlement_1")]
5996    pub ach_days: i32,
5997}
5998
5999fn default_settlement_1() -> i32 {
6000    1
6001}
6002
6003fn default_settlement_2() -> i32 {
6004    2
6005}
6006
6007fn default_wire_cutoff() -> String {
6008    "14:00".to_string()
6009}
6010
6011impl Default for SettlementRulesSchemaConfig {
6012    fn default() -> Self {
6013        Self {
6014            equity_days: 2,
6015            government_bonds_days: 1,
6016            fx_spot_days: 2,
6017            corporate_bonds_days: 2,
6018            wire_cutoff_time: "14:00".to_string(),
6019            wire_international_days: 1,
6020            ach_days: 1,
6021        }
6022    }
6023}
6024
6025/// Regional calendar configuration.
6026#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6027pub struct CalendarSchemaConfig {
6028    /// List of regions to include (e.g., ["US", "DE", "BR", "SG", "KR"]).
6029    #[serde(default)]
6030    pub regions: Vec<String>,
6031
6032    /// Custom holidays (in addition to regional calendars).
6033    #[serde(default)]
6034    pub custom_holidays: Vec<CustomHolidaySchemaConfig>,
6035}
6036
6037/// Custom holiday configuration.
6038#[derive(Debug, Clone, Serialize, Deserialize)]
6039pub struct CustomHolidaySchemaConfig {
6040    /// Holiday name.
6041    pub name: String,
6042    /// Month (1-12).
6043    pub month: u8,
6044    /// Day of month.
6045    pub day: u8,
6046    /// Activity multiplier (0.0-1.0, default 0.05).
6047    #[serde(default = "default_holiday_multiplier")]
6048    pub activity_multiplier: f64,
6049}
6050
6051fn default_holiday_multiplier() -> f64 {
6052    0.05
6053}
6054
6055/// Period-end dynamics configuration.
6056#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6057pub struct PeriodEndSchemaConfig {
6058    /// Model type: "flat", "exponential", "extended_crunch", "daily_profile".
6059    #[serde(default)]
6060    pub model: Option<String>,
6061
6062    /// Month-end configuration.
6063    #[serde(default)]
6064    pub month_end: Option<PeriodEndModelSchemaConfig>,
6065
6066    /// Quarter-end configuration.
6067    #[serde(default)]
6068    pub quarter_end: Option<PeriodEndModelSchemaConfig>,
6069
6070    /// Year-end configuration.
6071    #[serde(default)]
6072    pub year_end: Option<PeriodEndModelSchemaConfig>,
6073}
6074
6075/// Period-end model configuration.
6076#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6077pub struct PeriodEndModelSchemaConfig {
6078    /// Inherit configuration from another period (e.g., "month_end").
6079    #[serde(default)]
6080    pub inherit_from: Option<String>,
6081
6082    /// Additional multiplier on top of inherited/base model.
6083    #[serde(default)]
6084    pub additional_multiplier: Option<f64>,
6085
6086    /// Days before period end to start acceleration (negative, e.g., -10).
6087    #[serde(default)]
6088    pub start_day: Option<i32>,
6089
6090    /// Base multiplier at start of acceleration.
6091    #[serde(default)]
6092    pub base_multiplier: Option<f64>,
6093
6094    /// Peak multiplier on last day.
6095    #[serde(default)]
6096    pub peak_multiplier: Option<f64>,
6097
6098    /// Decay rate for exponential model (0.1-0.5 typical).
6099    #[serde(default)]
6100    pub decay_rate: Option<f64>,
6101
6102    /// Sustained high days for crunch model.
6103    #[serde(default)]
6104    pub sustained_high_days: Option<i32>,
6105}
6106
6107/// Processing lag configuration.
6108#[derive(Debug, Clone, Serialize, Deserialize)]
6109pub struct ProcessingLagSchemaConfig {
6110    /// Enable processing lag calculations.
6111    #[serde(default = "default_true")]
6112    pub enabled: bool,
6113
6114    /// Sales order lag configuration (log-normal mu, sigma).
6115    #[serde(default)]
6116    pub sales_order_lag: Option<LagDistributionSchemaConfig>,
6117
6118    /// Purchase order lag configuration.
6119    #[serde(default)]
6120    pub purchase_order_lag: Option<LagDistributionSchemaConfig>,
6121
6122    /// Goods receipt lag configuration.
6123    #[serde(default)]
6124    pub goods_receipt_lag: Option<LagDistributionSchemaConfig>,
6125
6126    /// Invoice receipt lag configuration.
6127    #[serde(default)]
6128    pub invoice_receipt_lag: Option<LagDistributionSchemaConfig>,
6129
6130    /// Invoice issue lag configuration.
6131    #[serde(default)]
6132    pub invoice_issue_lag: Option<LagDistributionSchemaConfig>,
6133
6134    /// Payment lag configuration.
6135    #[serde(default)]
6136    pub payment_lag: Option<LagDistributionSchemaConfig>,
6137
6138    /// Journal entry lag configuration.
6139    #[serde(default)]
6140    pub journal_entry_lag: Option<LagDistributionSchemaConfig>,
6141
6142    /// Cross-day posting configuration.
6143    #[serde(default)]
6144    pub cross_day_posting: Option<CrossDayPostingSchemaConfig>,
6145}
6146
6147impl Default for ProcessingLagSchemaConfig {
6148    fn default() -> Self {
6149        Self {
6150            enabled: true,
6151            sales_order_lag: None,
6152            purchase_order_lag: None,
6153            goods_receipt_lag: None,
6154            invoice_receipt_lag: None,
6155            invoice_issue_lag: None,
6156            payment_lag: None,
6157            journal_entry_lag: None,
6158            cross_day_posting: None,
6159        }
6160    }
6161}
6162
6163/// Lag distribution configuration (log-normal parameters).
6164#[derive(Debug, Clone, Serialize, Deserialize)]
6165pub struct LagDistributionSchemaConfig {
6166    /// Log-scale mean (mu for log-normal).
6167    pub mu: f64,
6168    /// Log-scale standard deviation (sigma for log-normal).
6169    pub sigma: f64,
6170    /// Minimum lag in hours.
6171    #[serde(default)]
6172    pub min_hours: Option<f64>,
6173    /// Maximum lag in hours.
6174    #[serde(default)]
6175    pub max_hours: Option<f64>,
6176}
6177
6178/// Cross-day posting configuration.
6179#[derive(Debug, Clone, Serialize, Deserialize)]
6180pub struct CrossDayPostingSchemaConfig {
6181    /// Enable cross-day posting logic.
6182    #[serde(default = "default_true")]
6183    pub enabled: bool,
6184
6185    /// Probability of next-day posting by hour (map of hour -> probability).
6186    /// E.g., { 17: 0.7, 19: 0.9, 21: 0.99 }
6187    #[serde(default)]
6188    pub probability_by_hour: std::collections::HashMap<u8, f64>,
6189}
6190
6191impl Default for CrossDayPostingSchemaConfig {
6192    fn default() -> Self {
6193        let mut probability_by_hour = std::collections::HashMap::new();
6194        probability_by_hour.insert(17, 0.3);
6195        probability_by_hour.insert(18, 0.6);
6196        probability_by_hour.insert(19, 0.8);
6197        probability_by_hour.insert(20, 0.9);
6198        probability_by_hour.insert(21, 0.95);
6199        probability_by_hour.insert(22, 0.99);
6200
6201        Self {
6202            enabled: true,
6203            probability_by_hour,
6204        }
6205    }
6206}
6207
6208// =============================================================================
6209// Fiscal Calendar Configuration (P2)
6210// =============================================================================
6211
6212/// Fiscal calendar configuration.
6213///
6214/// Supports calendar year, custom year start, 4-4-5 retail calendar,
6215/// and 13-period calendars.
6216#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6217pub struct FiscalCalendarSchemaConfig {
6218    /// Enable non-standard fiscal calendar.
6219    #[serde(default)]
6220    pub enabled: bool,
6221
6222    /// Fiscal calendar type: "calendar_year", "custom", "four_four_five", "thirteen_period".
6223    #[serde(default = "default_fiscal_calendar_type")]
6224    pub calendar_type: String,
6225
6226    /// Month the fiscal year starts (1-12). Used for custom year start.
6227    #[serde(default)]
6228    pub year_start_month: Option<u8>,
6229
6230    /// Day the fiscal year starts (1-31). Used for custom year start.
6231    #[serde(default)]
6232    pub year_start_day: Option<u8>,
6233
6234    /// 4-4-5 calendar configuration (if calendar_type is "four_four_five").
6235    #[serde(default)]
6236    pub four_four_five: Option<FourFourFiveSchemaConfig>,
6237}
6238
6239fn default_fiscal_calendar_type() -> String {
6240    "calendar_year".to_string()
6241}
6242
6243/// 4-4-5 retail calendar configuration.
6244#[derive(Debug, Clone, Serialize, Deserialize)]
6245pub struct FourFourFiveSchemaConfig {
6246    /// Week pattern: "four_four_five", "four_five_four", "five_four_four".
6247    #[serde(default = "default_week_pattern")]
6248    pub pattern: String,
6249
6250    /// Anchor type: "first_sunday", "last_saturday", "nearest_saturday".
6251    #[serde(default = "default_anchor_type")]
6252    pub anchor_type: String,
6253
6254    /// Anchor month (1-12).
6255    #[serde(default = "default_anchor_month")]
6256    pub anchor_month: u8,
6257
6258    /// Where to place leap week: "q4_period3" or "q1_period1".
6259    #[serde(default = "default_leap_week_placement")]
6260    pub leap_week_placement: String,
6261}
6262
6263fn default_week_pattern() -> String {
6264    "four_four_five".to_string()
6265}
6266
6267fn default_anchor_type() -> String {
6268    "last_saturday".to_string()
6269}
6270
6271fn default_anchor_month() -> u8 {
6272    1 // January
6273}
6274
6275fn default_leap_week_placement() -> String {
6276    "q4_period3".to_string()
6277}
6278
6279impl Default for FourFourFiveSchemaConfig {
6280    fn default() -> Self {
6281        Self {
6282            pattern: "four_four_five".to_string(),
6283            anchor_type: "last_saturday".to_string(),
6284            anchor_month: 1,
6285            leap_week_placement: "q4_period3".to_string(),
6286        }
6287    }
6288}
6289
6290// =============================================================================
6291// Intra-Day Patterns Configuration (P2)
6292// =============================================================================
6293
6294/// Intra-day patterns configuration.
6295///
6296/// Defines time-of-day segments with different activity multipliers
6297/// for realistic modeling of morning spikes, lunch dips, and end-of-day rushes.
6298#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6299pub struct IntraDaySchemaConfig {
6300    /// Enable intra-day patterns.
6301    #[serde(default)]
6302    pub enabled: bool,
6303
6304    /// Custom intra-day segments.
6305    #[serde(default)]
6306    pub segments: Vec<IntraDaySegmentSchemaConfig>,
6307}
6308
6309/// Intra-day segment configuration.
6310#[derive(Debug, Clone, Serialize, Deserialize)]
6311pub struct IntraDaySegmentSchemaConfig {
6312    /// Name of the segment (e.g., "morning_spike", "lunch_dip").
6313    pub name: String,
6314
6315    /// Start time (HH:MM format).
6316    pub start: String,
6317
6318    /// End time (HH:MM format).
6319    pub end: String,
6320
6321    /// Activity multiplier (1.0 = normal).
6322    #[serde(default = "default_multiplier")]
6323    pub multiplier: f64,
6324
6325    /// Posting type: "human", "system", "both".
6326    #[serde(default = "default_posting_type")]
6327    pub posting_type: String,
6328}
6329
6330fn default_multiplier() -> f64 {
6331    1.0
6332}
6333
6334fn default_posting_type() -> String {
6335    "both".to_string()
6336}
6337
6338// =============================================================================
6339// Timezone Configuration
6340// =============================================================================
6341
6342/// Timezone handling configuration for multi-region entities.
6343#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6344pub struct TimezoneSchemaConfig {
6345    /// Enable timezone handling.
6346    #[serde(default)]
6347    pub enabled: bool,
6348
6349    /// Default timezone (IANA format, e.g., "America/New_York").
6350    #[serde(default = "default_timezone")]
6351    pub default_timezone: String,
6352
6353    /// Consolidation timezone for group reporting (IANA format).
6354    #[serde(default = "default_consolidation_timezone")]
6355    pub consolidation_timezone: String,
6356
6357    /// Entity-to-timezone mappings.
6358    /// Supports patterns like "EU_*" -> "Europe/London".
6359    #[serde(default)]
6360    pub entity_mappings: Vec<EntityTimezoneMapping>,
6361}
6362
6363fn default_timezone() -> String {
6364    "America/New_York".to_string()
6365}
6366
6367fn default_consolidation_timezone() -> String {
6368    "UTC".to_string()
6369}
6370
6371/// Mapping from entity pattern to timezone.
6372#[derive(Debug, Clone, Serialize, Deserialize)]
6373pub struct EntityTimezoneMapping {
6374    /// Entity code pattern (e.g., "EU_*", "*_APAC", "1000").
6375    pub pattern: String,
6376
6377    /// Timezone (IANA format, e.g., "Europe/London").
6378    pub timezone: String,
6379}
6380
6381// =============================================================================
6382// Vendor Network Configuration
6383// =============================================================================
6384
6385/// Configuration for multi-tier vendor network generation.
6386#[derive(Debug, Clone, Serialize, Deserialize)]
6387pub struct VendorNetworkSchemaConfig {
6388    /// Enable vendor network generation.
6389    #[serde(default)]
6390    pub enabled: bool,
6391
6392    /// Maximum depth of supply chain tiers (1-3).
6393    #[serde(default = "default_vendor_tier_depth")]
6394    pub depth: u8,
6395
6396    /// Tier 1 vendor count configuration.
6397    #[serde(default)]
6398    pub tier1: TierCountSchemaConfig,
6399
6400    /// Tier 2 vendors per Tier 1 parent.
6401    #[serde(default)]
6402    pub tier2_per_parent: TierCountSchemaConfig,
6403
6404    /// Tier 3 vendors per Tier 2 parent.
6405    #[serde(default)]
6406    pub tier3_per_parent: TierCountSchemaConfig,
6407
6408    /// Vendor cluster distribution.
6409    #[serde(default)]
6410    pub clusters: VendorClusterSchemaConfig,
6411
6412    /// Concentration limits.
6413    #[serde(default)]
6414    pub dependencies: DependencySchemaConfig,
6415}
6416
6417fn default_vendor_tier_depth() -> u8 {
6418    3
6419}
6420
6421impl Default for VendorNetworkSchemaConfig {
6422    fn default() -> Self {
6423        Self {
6424            enabled: false,
6425            depth: 3,
6426            tier1: TierCountSchemaConfig { min: 50, max: 100 },
6427            tier2_per_parent: TierCountSchemaConfig { min: 4, max: 10 },
6428            tier3_per_parent: TierCountSchemaConfig { min: 2, max: 5 },
6429            clusters: VendorClusterSchemaConfig::default(),
6430            dependencies: DependencySchemaConfig::default(),
6431        }
6432    }
6433}
6434
6435/// Tier count configuration.
6436#[derive(Debug, Clone, Serialize, Deserialize)]
6437pub struct TierCountSchemaConfig {
6438    /// Minimum count.
6439    #[serde(default = "default_tier_min")]
6440    pub min: usize,
6441
6442    /// Maximum count.
6443    #[serde(default = "default_tier_max")]
6444    pub max: usize,
6445}
6446
6447fn default_tier_min() -> usize {
6448    5
6449}
6450
6451fn default_tier_max() -> usize {
6452    20
6453}
6454
6455impl Default for TierCountSchemaConfig {
6456    fn default() -> Self {
6457        Self {
6458            min: default_tier_min(),
6459            max: default_tier_max(),
6460        }
6461    }
6462}
6463
6464/// Vendor cluster distribution configuration.
6465#[derive(Debug, Clone, Serialize, Deserialize)]
6466pub struct VendorClusterSchemaConfig {
6467    /// Reliable strategic vendors percentage (default: 0.20).
6468    #[serde(default = "default_reliable_strategic")]
6469    pub reliable_strategic: f64,
6470
6471    /// Standard operational vendors percentage (default: 0.50).
6472    #[serde(default = "default_standard_operational")]
6473    pub standard_operational: f64,
6474
6475    /// Transactional vendors percentage (default: 0.25).
6476    #[serde(default = "default_transactional")]
6477    pub transactional: f64,
6478
6479    /// Problematic vendors percentage (default: 0.05).
6480    #[serde(default = "default_problematic")]
6481    pub problematic: f64,
6482}
6483
6484fn default_reliable_strategic() -> f64 {
6485    0.20
6486}
6487
6488fn default_standard_operational() -> f64 {
6489    0.50
6490}
6491
6492fn default_transactional() -> f64 {
6493    0.25
6494}
6495
6496fn default_problematic() -> f64 {
6497    0.05
6498}
6499
6500impl Default for VendorClusterSchemaConfig {
6501    fn default() -> Self {
6502        Self {
6503            reliable_strategic: 0.20,
6504            standard_operational: 0.50,
6505            transactional: 0.25,
6506            problematic: 0.05,
6507        }
6508    }
6509}
6510
6511/// Dependency and concentration limits configuration.
6512#[derive(Debug, Clone, Serialize, Deserialize)]
6513pub struct DependencySchemaConfig {
6514    /// Maximum concentration for a single vendor (default: 0.15).
6515    #[serde(default = "default_max_single_vendor")]
6516    pub max_single_vendor_concentration: f64,
6517
6518    /// Maximum concentration for top 5 vendors (default: 0.45).
6519    #[serde(default = "default_max_top5")]
6520    pub top_5_concentration: f64,
6521
6522    /// Percentage of single-source vendors (default: 0.05).
6523    #[serde(default = "default_single_source_percent")]
6524    pub single_source_percent: f64,
6525}
6526
6527fn default_max_single_vendor() -> f64 {
6528    0.15
6529}
6530
6531fn default_max_top5() -> f64 {
6532    0.45
6533}
6534
6535fn default_single_source_percent() -> f64 {
6536    0.05
6537}
6538
6539impl Default for DependencySchemaConfig {
6540    fn default() -> Self {
6541        Self {
6542            max_single_vendor_concentration: 0.15,
6543            top_5_concentration: 0.45,
6544            single_source_percent: 0.05,
6545        }
6546    }
6547}
6548
6549// =============================================================================
6550// Customer Segmentation Configuration
6551// =============================================================================
6552
6553/// Configuration for customer segmentation generation.
6554#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6555pub struct CustomerSegmentationSchemaConfig {
6556    /// Enable customer segmentation generation.
6557    #[serde(default)]
6558    pub enabled: bool,
6559
6560    /// Value segment distribution.
6561    #[serde(default)]
6562    pub value_segments: ValueSegmentsSchemaConfig,
6563
6564    /// Lifecycle stage configuration.
6565    #[serde(default)]
6566    pub lifecycle: LifecycleSchemaConfig,
6567
6568    /// Network (referrals, hierarchies) configuration.
6569    #[serde(default)]
6570    pub networks: CustomerNetworksSchemaConfig,
6571}
6572
6573/// Customer value segments distribution configuration.
6574#[derive(Debug, Clone, Serialize, Deserialize)]
6575pub struct ValueSegmentsSchemaConfig {
6576    /// Enterprise segment configuration.
6577    #[serde(default)]
6578    pub enterprise: SegmentDetailSchemaConfig,
6579
6580    /// Mid-market segment configuration.
6581    #[serde(default)]
6582    pub mid_market: SegmentDetailSchemaConfig,
6583
6584    /// SMB segment configuration.
6585    #[serde(default)]
6586    pub smb: SegmentDetailSchemaConfig,
6587
6588    /// Consumer segment configuration.
6589    #[serde(default)]
6590    pub consumer: SegmentDetailSchemaConfig,
6591}
6592
6593impl Default for ValueSegmentsSchemaConfig {
6594    fn default() -> Self {
6595        Self {
6596            enterprise: SegmentDetailSchemaConfig {
6597                revenue_share: 0.40,
6598                customer_share: 0.05,
6599                avg_order_value_range: "50000+".to_string(),
6600            },
6601            mid_market: SegmentDetailSchemaConfig {
6602                revenue_share: 0.35,
6603                customer_share: 0.20,
6604                avg_order_value_range: "5000-50000".to_string(),
6605            },
6606            smb: SegmentDetailSchemaConfig {
6607                revenue_share: 0.20,
6608                customer_share: 0.50,
6609                avg_order_value_range: "500-5000".to_string(),
6610            },
6611            consumer: SegmentDetailSchemaConfig {
6612                revenue_share: 0.05,
6613                customer_share: 0.25,
6614                avg_order_value_range: "50-500".to_string(),
6615            },
6616        }
6617    }
6618}
6619
6620/// Individual segment detail configuration.
6621#[derive(Debug, Clone, Serialize, Deserialize)]
6622pub struct SegmentDetailSchemaConfig {
6623    /// Revenue share for this segment.
6624    #[serde(default)]
6625    pub revenue_share: f64,
6626
6627    /// Customer share for this segment.
6628    #[serde(default)]
6629    pub customer_share: f64,
6630
6631    /// Average order value range (e.g., "5000-50000" or "50000+").
6632    #[serde(default)]
6633    pub avg_order_value_range: String,
6634}
6635
6636impl Default for SegmentDetailSchemaConfig {
6637    fn default() -> Self {
6638        Self {
6639            revenue_share: 0.25,
6640            customer_share: 0.25,
6641            avg_order_value_range: "1000-10000".to_string(),
6642        }
6643    }
6644}
6645
6646/// Customer lifecycle stage configuration.
6647#[derive(Debug, Clone, Serialize, Deserialize)]
6648pub struct LifecycleSchemaConfig {
6649    /// Prospect stage rate.
6650    #[serde(default)]
6651    pub prospect_rate: f64,
6652
6653    /// New customer stage rate.
6654    #[serde(default = "default_new_rate")]
6655    pub new_rate: f64,
6656
6657    /// Growth stage rate.
6658    #[serde(default = "default_growth_rate")]
6659    pub growth_rate: f64,
6660
6661    /// Mature stage rate.
6662    #[serde(default = "default_mature_rate")]
6663    pub mature_rate: f64,
6664
6665    /// At-risk stage rate.
6666    #[serde(default = "default_at_risk_rate")]
6667    pub at_risk_rate: f64,
6668
6669    /// Churned stage rate.
6670    #[serde(default = "default_churned_rate")]
6671    pub churned_rate: f64,
6672}
6673
6674fn default_new_rate() -> f64 {
6675    0.10
6676}
6677
6678fn default_growth_rate() -> f64 {
6679    0.15
6680}
6681
6682fn default_mature_rate() -> f64 {
6683    0.60
6684}
6685
6686fn default_at_risk_rate() -> f64 {
6687    0.10
6688}
6689
6690fn default_churned_rate() -> f64 {
6691    0.05
6692}
6693
6694impl Default for LifecycleSchemaConfig {
6695    fn default() -> Self {
6696        Self {
6697            prospect_rate: 0.0,
6698            new_rate: 0.10,
6699            growth_rate: 0.15,
6700            mature_rate: 0.60,
6701            at_risk_rate: 0.10,
6702            churned_rate: 0.05,
6703        }
6704    }
6705}
6706
6707/// Customer networks configuration (referrals, hierarchies).
6708#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6709pub struct CustomerNetworksSchemaConfig {
6710    /// Referral network configuration.
6711    #[serde(default)]
6712    pub referrals: ReferralSchemaConfig,
6713
6714    /// Corporate hierarchy configuration.
6715    #[serde(default)]
6716    pub corporate_hierarchies: HierarchySchemaConfig,
6717}
6718
6719/// Referral network configuration.
6720#[derive(Debug, Clone, Serialize, Deserialize)]
6721pub struct ReferralSchemaConfig {
6722    /// Enable referral generation.
6723    #[serde(default = "default_true")]
6724    pub enabled: bool,
6725
6726    /// Rate of customers acquired via referral.
6727    #[serde(default = "default_referral_rate")]
6728    pub referral_rate: f64,
6729}
6730
6731fn default_referral_rate() -> f64 {
6732    0.15
6733}
6734
6735impl Default for ReferralSchemaConfig {
6736    fn default() -> Self {
6737        Self {
6738            enabled: true,
6739            referral_rate: 0.15,
6740        }
6741    }
6742}
6743
6744/// Corporate hierarchy configuration.
6745#[derive(Debug, Clone, Serialize, Deserialize)]
6746pub struct HierarchySchemaConfig {
6747    /// Enable corporate hierarchy generation.
6748    #[serde(default = "default_true")]
6749    pub enabled: bool,
6750
6751    /// Rate of customers in hierarchies.
6752    #[serde(default = "default_hierarchy_rate")]
6753    pub probability: f64,
6754}
6755
6756fn default_hierarchy_rate() -> f64 {
6757    0.30
6758}
6759
6760impl Default for HierarchySchemaConfig {
6761    fn default() -> Self {
6762        Self {
6763            enabled: true,
6764            probability: 0.30,
6765        }
6766    }
6767}
6768
6769// =============================================================================
6770// Relationship Strength Configuration
6771// =============================================================================
6772
6773/// Configuration for relationship strength calculation.
6774#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6775pub struct RelationshipStrengthSchemaConfig {
6776    /// Enable relationship strength calculation.
6777    #[serde(default)]
6778    pub enabled: bool,
6779
6780    /// Calculation weights.
6781    #[serde(default)]
6782    pub calculation: StrengthCalculationSchemaConfig,
6783
6784    /// Strength thresholds for classification.
6785    #[serde(default)]
6786    pub thresholds: StrengthThresholdsSchemaConfig,
6787}
6788
6789/// Strength calculation weights configuration.
6790#[derive(Debug, Clone, Serialize, Deserialize)]
6791pub struct StrengthCalculationSchemaConfig {
6792    /// Weight for transaction volume (default: 0.30).
6793    #[serde(default = "default_volume_weight")]
6794    pub transaction_volume_weight: f64,
6795
6796    /// Weight for transaction count (default: 0.25).
6797    #[serde(default = "default_count_weight")]
6798    pub transaction_count_weight: f64,
6799
6800    /// Weight for relationship duration (default: 0.20).
6801    #[serde(default = "default_duration_weight")]
6802    pub relationship_duration_weight: f64,
6803
6804    /// Weight for recency (default: 0.15).
6805    #[serde(default = "default_recency_weight")]
6806    pub recency_weight: f64,
6807
6808    /// Weight for mutual connections (default: 0.10).
6809    #[serde(default = "default_mutual_weight")]
6810    pub mutual_connections_weight: f64,
6811
6812    /// Recency half-life in days (default: 90).
6813    #[serde(default = "default_recency_half_life")]
6814    pub recency_half_life_days: u32,
6815}
6816
6817fn default_volume_weight() -> f64 {
6818    0.30
6819}
6820
6821fn default_count_weight() -> f64 {
6822    0.25
6823}
6824
6825fn default_duration_weight() -> f64 {
6826    0.20
6827}
6828
6829fn default_recency_weight() -> f64 {
6830    0.15
6831}
6832
6833fn default_mutual_weight() -> f64 {
6834    0.10
6835}
6836
6837fn default_recency_half_life() -> u32 {
6838    90
6839}
6840
6841impl Default for StrengthCalculationSchemaConfig {
6842    fn default() -> Self {
6843        Self {
6844            transaction_volume_weight: 0.30,
6845            transaction_count_weight: 0.25,
6846            relationship_duration_weight: 0.20,
6847            recency_weight: 0.15,
6848            mutual_connections_weight: 0.10,
6849            recency_half_life_days: 90,
6850        }
6851    }
6852}
6853
6854/// Strength thresholds for relationship classification.
6855#[derive(Debug, Clone, Serialize, Deserialize)]
6856pub struct StrengthThresholdsSchemaConfig {
6857    /// Threshold for strong relationships (default: 0.7).
6858    #[serde(default = "default_strong_threshold")]
6859    pub strong: f64,
6860
6861    /// Threshold for moderate relationships (default: 0.4).
6862    #[serde(default = "default_moderate_threshold")]
6863    pub moderate: f64,
6864
6865    /// Threshold for weak relationships (default: 0.1).
6866    #[serde(default = "default_weak_threshold")]
6867    pub weak: f64,
6868}
6869
6870fn default_strong_threshold() -> f64 {
6871    0.7
6872}
6873
6874fn default_moderate_threshold() -> f64 {
6875    0.4
6876}
6877
6878fn default_weak_threshold() -> f64 {
6879    0.1
6880}
6881
6882impl Default for StrengthThresholdsSchemaConfig {
6883    fn default() -> Self {
6884        Self {
6885            strong: 0.7,
6886            moderate: 0.4,
6887            weak: 0.1,
6888        }
6889    }
6890}
6891
6892// =============================================================================
6893// Cross-Process Links Configuration
6894// =============================================================================
6895
6896/// Configuration for cross-process linkages.
6897#[derive(Debug, Clone, Serialize, Deserialize)]
6898pub struct CrossProcessLinksSchemaConfig {
6899    /// Enable cross-process link generation.
6900    #[serde(default)]
6901    pub enabled: bool,
6902
6903    /// Enable inventory links between P2P and O2C.
6904    #[serde(default = "default_true")]
6905    pub inventory_p2p_o2c: bool,
6906
6907    /// Enable payment to bank reconciliation links.
6908    #[serde(default = "default_true")]
6909    pub payment_bank_reconciliation: bool,
6910
6911    /// Enable intercompany bilateral matching.
6912    #[serde(default = "default_true")]
6913    pub intercompany_bilateral: bool,
6914
6915    /// Percentage of GR/Deliveries to link via inventory (0.0 - 1.0).
6916    #[serde(default = "default_inventory_link_rate")]
6917    pub inventory_link_rate: f64,
6918}
6919
6920fn default_inventory_link_rate() -> f64 {
6921    0.30
6922}
6923
6924impl Default for CrossProcessLinksSchemaConfig {
6925    fn default() -> Self {
6926        Self {
6927            enabled: false,
6928            inventory_p2p_o2c: true,
6929            payment_bank_reconciliation: true,
6930            intercompany_bilateral: true,
6931            inventory_link_rate: 0.30,
6932        }
6933    }
6934}
6935
6936// =============================================================================
6937// Organizational Events Configuration
6938// =============================================================================
6939
6940/// Configuration for organizational events (acquisitions, divestitures, etc.).
6941#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6942pub struct OrganizationalEventsSchemaConfig {
6943    /// Enable organizational events.
6944    #[serde(default)]
6945    pub enabled: bool,
6946
6947    /// Effect blending mode (multiplicative, additive, maximum, minimum).
6948    #[serde(default)]
6949    pub effect_blending: EffectBlendingModeConfig,
6950
6951    /// Organizational events (acquisitions, divestitures, reorganizations, etc.).
6952    #[serde(default)]
6953    pub events: Vec<OrganizationalEventSchemaConfig>,
6954
6955    /// Process evolution events.
6956    #[serde(default)]
6957    pub process_evolution: Vec<ProcessEvolutionSchemaConfig>,
6958
6959    /// Technology transition events.
6960    #[serde(default)]
6961    pub technology_transitions: Vec<TechnologyTransitionSchemaConfig>,
6962}
6963
6964/// Effect blending mode for combining multiple event effects.
6965#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6966#[serde(rename_all = "snake_case")]
6967pub enum EffectBlendingModeConfig {
6968    /// Multiply effects together.
6969    #[default]
6970    Multiplicative,
6971    /// Add effects together.
6972    Additive,
6973    /// Take the maximum effect.
6974    Maximum,
6975    /// Take the minimum effect.
6976    Minimum,
6977}
6978
6979/// Configuration for a single organizational event.
6980#[derive(Debug, Clone, Serialize, Deserialize)]
6981pub struct OrganizationalEventSchemaConfig {
6982    /// Event ID.
6983    pub id: String,
6984
6985    /// Event type and configuration.
6986    pub event_type: OrganizationalEventTypeSchemaConfig,
6987
6988    /// Effective date.
6989    pub effective_date: String,
6990
6991    /// Transition duration in months.
6992    #[serde(default = "default_org_transition_months")]
6993    pub transition_months: u32,
6994
6995    /// Description.
6996    #[serde(default)]
6997    pub description: Option<String>,
6998}
6999
7000fn default_org_transition_months() -> u32 {
7001    6
7002}
7003
7004/// Organizational event type configuration.
7005#[derive(Debug, Clone, Serialize, Deserialize)]
7006#[serde(tag = "type", rename_all = "snake_case")]
7007pub enum OrganizationalEventTypeSchemaConfig {
7008    /// Acquisition event.
7009    Acquisition {
7010        /// Acquired entity code.
7011        acquired_entity: String,
7012        /// Volume increase multiplier.
7013        #[serde(default = "default_acquisition_volume")]
7014        volume_increase: f64,
7015        /// Integration error rate.
7016        #[serde(default = "default_acquisition_error")]
7017        integration_error_rate: f64,
7018        /// Parallel posting days.
7019        #[serde(default = "default_parallel_days")]
7020        parallel_posting_days: u32,
7021    },
7022    /// Divestiture event.
7023    Divestiture {
7024        /// Divested entity code.
7025        divested_entity: String,
7026        /// Volume reduction factor.
7027        #[serde(default = "default_divestiture_volume")]
7028        volume_reduction: f64,
7029        /// Remove entity from generation.
7030        #[serde(default = "default_true_val")]
7031        remove_entity: bool,
7032    },
7033    /// Reorganization event.
7034    Reorganization {
7035        /// Cost center remapping.
7036        #[serde(default)]
7037        cost_center_remapping: std::collections::HashMap<String, String>,
7038        /// Transition error rate.
7039        #[serde(default = "default_reorg_error")]
7040        transition_error_rate: f64,
7041    },
7042    /// Leadership change event.
7043    LeadershipChange {
7044        /// Role that changed.
7045        role: String,
7046        /// Policy changes.
7047        #[serde(default)]
7048        policy_changes: Vec<String>,
7049    },
7050    /// Workforce reduction event.
7051    WorkforceReduction {
7052        /// Reduction percentage.
7053        #[serde(default = "default_workforce_reduction")]
7054        reduction_percent: f64,
7055        /// Error rate increase.
7056        #[serde(default = "default_workforce_error")]
7057        error_rate_increase: f64,
7058    },
7059    /// Merger event.
7060    Merger {
7061        /// Merged entity code.
7062        merged_entity: String,
7063        /// Volume increase multiplier.
7064        #[serde(default = "default_merger_volume")]
7065        volume_increase: f64,
7066    },
7067}
7068
7069fn default_acquisition_volume() -> f64 {
7070    1.35
7071}
7072
7073fn default_acquisition_error() -> f64 {
7074    0.05
7075}
7076
7077fn default_parallel_days() -> u32 {
7078    30
7079}
7080
7081fn default_divestiture_volume() -> f64 {
7082    0.70
7083}
7084
7085fn default_true_val() -> bool {
7086    true
7087}
7088
7089fn default_reorg_error() -> f64 {
7090    0.04
7091}
7092
7093fn default_workforce_reduction() -> f64 {
7094    0.10
7095}
7096
7097fn default_workforce_error() -> f64 {
7098    0.05
7099}
7100
7101fn default_merger_volume() -> f64 {
7102    1.80
7103}
7104
7105/// Configuration for a process evolution event.
7106#[derive(Debug, Clone, Serialize, Deserialize)]
7107pub struct ProcessEvolutionSchemaConfig {
7108    /// Event ID.
7109    pub id: String,
7110
7111    /// Event type.
7112    pub event_type: ProcessEvolutionTypeSchemaConfig,
7113
7114    /// Effective date.
7115    pub effective_date: String,
7116
7117    /// Description.
7118    #[serde(default)]
7119    pub description: Option<String>,
7120}
7121
7122/// Process evolution type configuration.
7123#[derive(Debug, Clone, Serialize, Deserialize)]
7124#[serde(tag = "type", rename_all = "snake_case")]
7125pub enum ProcessEvolutionTypeSchemaConfig {
7126    /// Process automation.
7127    ProcessAutomation {
7128        /// Process name.
7129        process_name: String,
7130        /// Manual rate before.
7131        #[serde(default = "default_manual_before")]
7132        manual_rate_before: f64,
7133        /// Manual rate after.
7134        #[serde(default = "default_manual_after")]
7135        manual_rate_after: f64,
7136    },
7137    /// Approval workflow change.
7138    ApprovalWorkflowChange {
7139        /// Description.
7140        description: String,
7141    },
7142    /// Control enhancement.
7143    ControlEnhancement {
7144        /// Control ID.
7145        control_id: String,
7146        /// Error reduction.
7147        #[serde(default = "default_error_reduction")]
7148        error_reduction: f64,
7149    },
7150}
7151
7152fn default_manual_before() -> f64 {
7153    0.80
7154}
7155
7156fn default_manual_after() -> f64 {
7157    0.15
7158}
7159
7160fn default_error_reduction() -> f64 {
7161    0.02
7162}
7163
7164/// Configuration for a technology transition event.
7165#[derive(Debug, Clone, Serialize, Deserialize)]
7166pub struct TechnologyTransitionSchemaConfig {
7167    /// Event ID.
7168    pub id: String,
7169
7170    /// Event type.
7171    pub event_type: TechnologyTransitionTypeSchemaConfig,
7172
7173    /// Description.
7174    #[serde(default)]
7175    pub description: Option<String>,
7176}
7177
7178/// Technology transition type configuration.
7179#[derive(Debug, Clone, Serialize, Deserialize)]
7180#[serde(tag = "type", rename_all = "snake_case")]
7181pub enum TechnologyTransitionTypeSchemaConfig {
7182    /// ERP migration.
7183    ErpMigration {
7184        /// Source system.
7185        source_system: String,
7186        /// Target system.
7187        target_system: String,
7188        /// Cutover date.
7189        cutover_date: String,
7190        /// Stabilization end date.
7191        stabilization_end: String,
7192        /// Duplicate rate during migration.
7193        #[serde(default = "default_erp_duplicate_rate")]
7194        duplicate_rate: f64,
7195        /// Format mismatch rate.
7196        #[serde(default = "default_format_mismatch")]
7197        format_mismatch_rate: f64,
7198    },
7199    /// Module implementation.
7200    ModuleImplementation {
7201        /// Module name.
7202        module_name: String,
7203        /// Go-live date.
7204        go_live_date: String,
7205    },
7206}
7207
7208fn default_erp_duplicate_rate() -> f64 {
7209    0.02
7210}
7211
7212fn default_format_mismatch() -> f64 {
7213    0.03
7214}
7215
7216// =============================================================================
7217// Behavioral Drift Configuration
7218// =============================================================================
7219
7220/// Configuration for behavioral drift (vendor, customer, employee behavior).
7221#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7222pub struct BehavioralDriftSchemaConfig {
7223    /// Enable behavioral drift.
7224    #[serde(default)]
7225    pub enabled: bool,
7226
7227    /// Vendor behavior drift.
7228    #[serde(default)]
7229    pub vendor_behavior: VendorBehaviorSchemaConfig,
7230
7231    /// Customer behavior drift.
7232    #[serde(default)]
7233    pub customer_behavior: CustomerBehaviorSchemaConfig,
7234
7235    /// Employee behavior drift.
7236    #[serde(default)]
7237    pub employee_behavior: EmployeeBehaviorSchemaConfig,
7238
7239    /// Collective behavior drift.
7240    #[serde(default)]
7241    pub collective: CollectiveBehaviorSchemaConfig,
7242}
7243
7244/// Vendor behavior drift configuration.
7245#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7246pub struct VendorBehaviorSchemaConfig {
7247    /// Payment terms drift.
7248    #[serde(default)]
7249    pub payment_terms_drift: PaymentTermsDriftSchemaConfig,
7250
7251    /// Quality drift.
7252    #[serde(default)]
7253    pub quality_drift: QualityDriftSchemaConfig,
7254}
7255
7256/// Payment terms drift configuration.
7257#[derive(Debug, Clone, Serialize, Deserialize)]
7258pub struct PaymentTermsDriftSchemaConfig {
7259    /// Extension rate per year (days).
7260    #[serde(default = "default_extension_rate")]
7261    pub extension_rate_per_year: f64,
7262
7263    /// Economic sensitivity.
7264    #[serde(default = "default_economic_sensitivity")]
7265    pub economic_sensitivity: f64,
7266}
7267
7268fn default_extension_rate() -> f64 {
7269    2.5
7270}
7271
7272fn default_economic_sensitivity() -> f64 {
7273    1.0
7274}
7275
7276impl Default for PaymentTermsDriftSchemaConfig {
7277    fn default() -> Self {
7278        Self {
7279            extension_rate_per_year: 2.5,
7280            economic_sensitivity: 1.0,
7281        }
7282    }
7283}
7284
7285/// Quality drift configuration.
7286#[derive(Debug, Clone, Serialize, Deserialize)]
7287pub struct QualityDriftSchemaConfig {
7288    /// New vendor improvement rate (per year).
7289    #[serde(default = "default_improvement_rate")]
7290    pub new_vendor_improvement_rate: f64,
7291
7292    /// Complacency decline rate (per year after first year).
7293    #[serde(default = "default_decline_rate")]
7294    pub complacency_decline_rate: f64,
7295}
7296
7297fn default_improvement_rate() -> f64 {
7298    0.02
7299}
7300
7301fn default_decline_rate() -> f64 {
7302    0.01
7303}
7304
7305impl Default for QualityDriftSchemaConfig {
7306    fn default() -> Self {
7307        Self {
7308            new_vendor_improvement_rate: 0.02,
7309            complacency_decline_rate: 0.01,
7310        }
7311    }
7312}
7313
7314/// Customer behavior drift configuration.
7315#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7316pub struct CustomerBehaviorSchemaConfig {
7317    /// Payment drift.
7318    #[serde(default)]
7319    pub payment_drift: CustomerPaymentDriftSchemaConfig,
7320
7321    /// Order drift.
7322    #[serde(default)]
7323    pub order_drift: OrderDriftSchemaConfig,
7324}
7325
7326/// Customer payment drift configuration.
7327#[derive(Debug, Clone, Serialize, Deserialize)]
7328pub struct CustomerPaymentDriftSchemaConfig {
7329    /// Days extension during downturn (min, max).
7330    #[serde(default = "default_downturn_extension")]
7331    pub downturn_days_extension: (u32, u32),
7332
7333    /// Bad debt increase during downturn.
7334    #[serde(default = "default_bad_debt_increase")]
7335    pub downturn_bad_debt_increase: f64,
7336}
7337
7338fn default_downturn_extension() -> (u32, u32) {
7339    (5, 15)
7340}
7341
7342fn default_bad_debt_increase() -> f64 {
7343    0.02
7344}
7345
7346impl Default for CustomerPaymentDriftSchemaConfig {
7347    fn default() -> Self {
7348        Self {
7349            downturn_days_extension: (5, 15),
7350            downturn_bad_debt_increase: 0.02,
7351        }
7352    }
7353}
7354
7355/// Order drift configuration.
7356#[derive(Debug, Clone, Serialize, Deserialize)]
7357pub struct OrderDriftSchemaConfig {
7358    /// Digital shift rate (per year).
7359    #[serde(default = "default_digital_shift")]
7360    pub digital_shift_rate: f64,
7361}
7362
7363fn default_digital_shift() -> f64 {
7364    0.05
7365}
7366
7367impl Default for OrderDriftSchemaConfig {
7368    fn default() -> Self {
7369        Self {
7370            digital_shift_rate: 0.05,
7371        }
7372    }
7373}
7374
7375/// Employee behavior drift configuration.
7376#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7377pub struct EmployeeBehaviorSchemaConfig {
7378    /// Approval drift.
7379    #[serde(default)]
7380    pub approval_drift: ApprovalDriftSchemaConfig,
7381
7382    /// Error drift.
7383    #[serde(default)]
7384    pub error_drift: ErrorDriftSchemaConfig,
7385}
7386
7387/// Approval drift configuration.
7388#[derive(Debug, Clone, Serialize, Deserialize)]
7389pub struct ApprovalDriftSchemaConfig {
7390    /// EOM intensity increase per year.
7391    #[serde(default = "default_eom_intensity")]
7392    pub eom_intensity_increase_per_year: f64,
7393
7394    /// Rubber stamp volume threshold.
7395    #[serde(default = "default_rubber_stamp")]
7396    pub rubber_stamp_volume_threshold: u32,
7397}
7398
7399fn default_eom_intensity() -> f64 {
7400    0.05
7401}
7402
7403fn default_rubber_stamp() -> u32 {
7404    50
7405}
7406
7407impl Default for ApprovalDriftSchemaConfig {
7408    fn default() -> Self {
7409        Self {
7410            eom_intensity_increase_per_year: 0.05,
7411            rubber_stamp_volume_threshold: 50,
7412        }
7413    }
7414}
7415
7416/// Error drift configuration.
7417#[derive(Debug, Clone, Serialize, Deserialize)]
7418pub struct ErrorDriftSchemaConfig {
7419    /// New employee error rate.
7420    #[serde(default = "default_new_error")]
7421    pub new_employee_error_rate: f64,
7422
7423    /// Learning curve months.
7424    #[serde(default = "default_learning_months")]
7425    pub learning_curve_months: u32,
7426}
7427
7428fn default_new_error() -> f64 {
7429    0.08
7430}
7431
7432fn default_learning_months() -> u32 {
7433    6
7434}
7435
7436impl Default for ErrorDriftSchemaConfig {
7437    fn default() -> Self {
7438        Self {
7439            new_employee_error_rate: 0.08,
7440            learning_curve_months: 6,
7441        }
7442    }
7443}
7444
7445/// Collective behavior drift configuration.
7446#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7447pub struct CollectiveBehaviorSchemaConfig {
7448    /// Automation adoption configuration.
7449    #[serde(default)]
7450    pub automation_adoption: AutomationAdoptionSchemaConfig,
7451}
7452
7453/// Automation adoption configuration.
7454#[derive(Debug, Clone, Serialize, Deserialize)]
7455pub struct AutomationAdoptionSchemaConfig {
7456    /// Enable S-curve adoption model.
7457    #[serde(default)]
7458    pub s_curve_enabled: bool,
7459
7460    /// Adoption midpoint in months.
7461    #[serde(default = "default_midpoint")]
7462    pub adoption_midpoint_months: u32,
7463
7464    /// Steepness of adoption curve.
7465    #[serde(default = "default_steepness")]
7466    pub steepness: f64,
7467}
7468
7469fn default_midpoint() -> u32 {
7470    24
7471}
7472
7473fn default_steepness() -> f64 {
7474    0.15
7475}
7476
7477impl Default for AutomationAdoptionSchemaConfig {
7478    fn default() -> Self {
7479        Self {
7480            s_curve_enabled: false,
7481            adoption_midpoint_months: 24,
7482            steepness: 0.15,
7483        }
7484    }
7485}
7486
7487// =============================================================================
7488// Market Drift Configuration
7489// =============================================================================
7490
7491/// Configuration for market drift (economic cycles, commodities, price shocks).
7492#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7493pub struct MarketDriftSchemaConfig {
7494    /// Enable market drift.
7495    #[serde(default)]
7496    pub enabled: bool,
7497
7498    /// Economic cycle configuration.
7499    #[serde(default)]
7500    pub economic_cycle: MarketEconomicCycleSchemaConfig,
7501
7502    /// Industry-specific cycles.
7503    #[serde(default)]
7504    pub industry_cycles: std::collections::HashMap<String, IndustryCycleSchemaConfig>,
7505
7506    /// Commodity drift configuration.
7507    #[serde(default)]
7508    pub commodities: CommoditiesSchemaConfig,
7509}
7510
7511/// Market economic cycle configuration.
7512#[derive(Debug, Clone, Serialize, Deserialize)]
7513pub struct MarketEconomicCycleSchemaConfig {
7514    /// Enable economic cycle.
7515    #[serde(default)]
7516    pub enabled: bool,
7517
7518    /// Cycle type.
7519    #[serde(default)]
7520    pub cycle_type: CycleTypeSchemaConfig,
7521
7522    /// Cycle period in months.
7523    #[serde(default = "default_market_cycle_period")]
7524    pub period_months: u32,
7525
7526    /// Amplitude.
7527    #[serde(default = "default_market_amplitude")]
7528    pub amplitude: f64,
7529
7530    /// Recession configuration.
7531    #[serde(default)]
7532    pub recession: RecessionSchemaConfig,
7533}
7534
7535fn default_market_cycle_period() -> u32 {
7536    48
7537}
7538
7539fn default_market_amplitude() -> f64 {
7540    0.15
7541}
7542
7543impl Default for MarketEconomicCycleSchemaConfig {
7544    fn default() -> Self {
7545        Self {
7546            enabled: false,
7547            cycle_type: CycleTypeSchemaConfig::Sinusoidal,
7548            period_months: 48,
7549            amplitude: 0.15,
7550            recession: RecessionSchemaConfig::default(),
7551        }
7552    }
7553}
7554
7555/// Cycle type configuration.
7556#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7557#[serde(rename_all = "snake_case")]
7558pub enum CycleTypeSchemaConfig {
7559    /// Sinusoidal cycle.
7560    #[default]
7561    Sinusoidal,
7562    /// Asymmetric cycle.
7563    Asymmetric,
7564    /// Mean-reverting cycle.
7565    MeanReverting,
7566}
7567
7568/// Recession configuration.
7569#[derive(Debug, Clone, Serialize, Deserialize)]
7570pub struct RecessionSchemaConfig {
7571    /// Enable recession simulation.
7572    #[serde(default)]
7573    pub enabled: bool,
7574
7575    /// Probability per year.
7576    #[serde(default = "default_recession_prob")]
7577    pub probability_per_year: f64,
7578
7579    /// Severity.
7580    #[serde(default)]
7581    pub severity: RecessionSeveritySchemaConfig,
7582
7583    /// Specific recession periods.
7584    #[serde(default)]
7585    pub recession_periods: Vec<RecessionPeriodSchemaConfig>,
7586}
7587
7588fn default_recession_prob() -> f64 {
7589    0.10
7590}
7591
7592impl Default for RecessionSchemaConfig {
7593    fn default() -> Self {
7594        Self {
7595            enabled: false,
7596            probability_per_year: 0.10,
7597            severity: RecessionSeveritySchemaConfig::Moderate,
7598            recession_periods: Vec::new(),
7599        }
7600    }
7601}
7602
7603/// Recession severity configuration.
7604#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7605#[serde(rename_all = "snake_case")]
7606pub enum RecessionSeveritySchemaConfig {
7607    /// Mild recession.
7608    Mild,
7609    /// Moderate recession.
7610    #[default]
7611    Moderate,
7612    /// Severe recession.
7613    Severe,
7614}
7615
7616/// Recession period configuration.
7617#[derive(Debug, Clone, Serialize, Deserialize)]
7618pub struct RecessionPeriodSchemaConfig {
7619    /// Start month.
7620    pub start_month: u32,
7621    /// Duration in months.
7622    pub duration_months: u32,
7623}
7624
7625/// Industry cycle configuration.
7626#[derive(Debug, Clone, Serialize, Deserialize)]
7627pub struct IndustryCycleSchemaConfig {
7628    /// Period in months.
7629    #[serde(default = "default_industry_period")]
7630    pub period_months: u32,
7631
7632    /// Amplitude.
7633    #[serde(default = "default_industry_amp")]
7634    pub amplitude: f64,
7635}
7636
7637fn default_industry_period() -> u32 {
7638    36
7639}
7640
7641fn default_industry_amp() -> f64 {
7642    0.20
7643}
7644
7645/// Commodities drift configuration.
7646#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7647pub struct CommoditiesSchemaConfig {
7648    /// Enable commodity drift.
7649    #[serde(default)]
7650    pub enabled: bool,
7651
7652    /// Commodity items.
7653    #[serde(default)]
7654    pub items: Vec<CommodityItemSchemaConfig>,
7655}
7656
7657/// Commodity item configuration.
7658#[derive(Debug, Clone, Serialize, Deserialize)]
7659pub struct CommodityItemSchemaConfig {
7660    /// Commodity name.
7661    pub name: String,
7662
7663    /// Volatility.
7664    #[serde(default = "default_volatility")]
7665    pub volatility: f64,
7666
7667    /// COGS pass-through.
7668    #[serde(default)]
7669    pub cogs_pass_through: f64,
7670
7671    /// Overhead pass-through.
7672    #[serde(default)]
7673    pub overhead_pass_through: f64,
7674}
7675
7676fn default_volatility() -> f64 {
7677    0.20
7678}
7679
7680// =============================================================================
7681// Drift Labeling Configuration
7682// =============================================================================
7683
7684/// Configuration for drift ground truth labeling.
7685#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7686pub struct DriftLabelingSchemaConfig {
7687    /// Enable drift labeling.
7688    #[serde(default)]
7689    pub enabled: bool,
7690
7691    /// Statistical drift labeling.
7692    #[serde(default)]
7693    pub statistical: StatisticalDriftLabelingSchemaConfig,
7694
7695    /// Categorical drift labeling.
7696    #[serde(default)]
7697    pub categorical: CategoricalDriftLabelingSchemaConfig,
7698
7699    /// Temporal drift labeling.
7700    #[serde(default)]
7701    pub temporal: TemporalDriftLabelingSchemaConfig,
7702
7703    /// Regulatory calendar preset.
7704    #[serde(default)]
7705    pub regulatory_calendar_preset: Option<String>,
7706}
7707
7708/// Statistical drift labeling configuration.
7709#[derive(Debug, Clone, Serialize, Deserialize)]
7710pub struct StatisticalDriftLabelingSchemaConfig {
7711    /// Enable statistical drift labeling.
7712    #[serde(default = "default_true_val")]
7713    pub enabled: bool,
7714
7715    /// Minimum magnitude threshold.
7716    #[serde(default = "default_min_magnitude")]
7717    pub min_magnitude_threshold: f64,
7718}
7719
7720fn default_min_magnitude() -> f64 {
7721    0.05
7722}
7723
7724impl Default for StatisticalDriftLabelingSchemaConfig {
7725    fn default() -> Self {
7726        Self {
7727            enabled: true,
7728            min_magnitude_threshold: 0.05,
7729        }
7730    }
7731}
7732
7733/// Categorical drift labeling configuration.
7734#[derive(Debug, Clone, Serialize, Deserialize)]
7735pub struct CategoricalDriftLabelingSchemaConfig {
7736    /// Enable categorical drift labeling.
7737    #[serde(default = "default_true_val")]
7738    pub enabled: bool,
7739}
7740
7741impl Default for CategoricalDriftLabelingSchemaConfig {
7742    fn default() -> Self {
7743        Self { enabled: true }
7744    }
7745}
7746
7747/// Temporal drift labeling configuration.
7748#[derive(Debug, Clone, Serialize, Deserialize)]
7749pub struct TemporalDriftLabelingSchemaConfig {
7750    /// Enable temporal drift labeling.
7751    #[serde(default = "default_true_val")]
7752    pub enabled: bool,
7753}
7754
7755impl Default for TemporalDriftLabelingSchemaConfig {
7756    fn default() -> Self {
7757        Self { enabled: true }
7758    }
7759}
7760
7761// =============================================================================
7762// Enhanced Anomaly Injection Configuration
7763// =============================================================================
7764
7765/// Enhanced anomaly injection configuration.
7766///
7767/// Provides comprehensive anomaly injection capabilities including:
7768/// - Multi-stage fraud schemes (embezzlement, revenue manipulation, kickbacks)
7769/// - Correlated anomaly injection (co-occurrence patterns, error cascades)
7770/// - Near-miss generation for false positive reduction
7771/// - Detection difficulty classification
7772/// - Context-aware injection based on entity behavior
7773#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7774pub struct EnhancedAnomalyConfig {
7775    /// Enable enhanced anomaly injection.
7776    #[serde(default)]
7777    pub enabled: bool,
7778
7779    /// Base anomaly rates.
7780    #[serde(default)]
7781    pub rates: AnomalyRateConfig,
7782
7783    /// Multi-stage fraud scheme configuration.
7784    #[serde(default)]
7785    pub multi_stage_schemes: MultiStageSchemeConfig,
7786
7787    /// Correlated anomaly injection configuration.
7788    #[serde(default)]
7789    pub correlated_injection: CorrelatedInjectionConfig,
7790
7791    /// Near-miss generation configuration.
7792    #[serde(default)]
7793    pub near_miss: NearMissConfig,
7794
7795    /// Detection difficulty classification configuration.
7796    #[serde(default)]
7797    pub difficulty_classification: DifficultyClassificationConfig,
7798
7799    /// Context-aware injection configuration.
7800    #[serde(default)]
7801    pub context_aware: ContextAwareConfig,
7802
7803    /// Enhanced labeling configuration.
7804    #[serde(default)]
7805    pub labeling: EnhancedLabelingConfig,
7806}
7807
7808/// Base anomaly rate configuration.
7809#[derive(Debug, Clone, Serialize, Deserialize)]
7810pub struct AnomalyRateConfig {
7811    /// Total anomaly rate (0.0 to 1.0).
7812    #[serde(default = "default_total_anomaly_rate")]
7813    pub total_rate: f64,
7814
7815    /// Fraud anomaly rate.
7816    #[serde(default = "default_fraud_anomaly_rate")]
7817    pub fraud_rate: f64,
7818
7819    /// Error anomaly rate.
7820    #[serde(default = "default_error_anomaly_rate")]
7821    pub error_rate: f64,
7822
7823    /// Process issue rate.
7824    #[serde(default = "default_process_anomaly_rate")]
7825    pub process_rate: f64,
7826}
7827
7828fn default_total_anomaly_rate() -> f64 {
7829    0.03
7830}
7831fn default_fraud_anomaly_rate() -> f64 {
7832    0.01
7833}
7834fn default_error_anomaly_rate() -> f64 {
7835    0.015
7836}
7837fn default_process_anomaly_rate() -> f64 {
7838    0.005
7839}
7840
7841impl Default for AnomalyRateConfig {
7842    fn default() -> Self {
7843        Self {
7844            total_rate: default_total_anomaly_rate(),
7845            fraud_rate: default_fraud_anomaly_rate(),
7846            error_rate: default_error_anomaly_rate(),
7847            process_rate: default_process_anomaly_rate(),
7848        }
7849    }
7850}
7851
7852/// Multi-stage fraud scheme configuration.
7853#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7854pub struct MultiStageSchemeConfig {
7855    /// Enable multi-stage fraud schemes.
7856    #[serde(default)]
7857    pub enabled: bool,
7858
7859    /// Embezzlement scheme configuration.
7860    #[serde(default)]
7861    pub embezzlement: EmbezzlementSchemeConfig,
7862
7863    /// Revenue manipulation scheme configuration.
7864    #[serde(default)]
7865    pub revenue_manipulation: RevenueManipulationSchemeConfig,
7866
7867    /// Vendor kickback scheme configuration.
7868    #[serde(default)]
7869    pub kickback: KickbackSchemeConfig,
7870}
7871
7872/// Embezzlement scheme configuration.
7873#[derive(Debug, Clone, Serialize, Deserialize)]
7874pub struct EmbezzlementSchemeConfig {
7875    /// Probability of starting an embezzlement scheme per perpetrator per year.
7876    #[serde(default = "default_embezzlement_probability")]
7877    pub probability: f64,
7878
7879    /// Testing stage configuration.
7880    #[serde(default)]
7881    pub testing_stage: SchemeStageConfig,
7882
7883    /// Escalation stage configuration.
7884    #[serde(default)]
7885    pub escalation_stage: SchemeStageConfig,
7886
7887    /// Acceleration stage configuration.
7888    #[serde(default)]
7889    pub acceleration_stage: SchemeStageConfig,
7890
7891    /// Desperation stage configuration.
7892    #[serde(default)]
7893    pub desperation_stage: SchemeStageConfig,
7894}
7895
7896fn default_embezzlement_probability() -> f64 {
7897    0.02
7898}
7899
7900impl Default for EmbezzlementSchemeConfig {
7901    fn default() -> Self {
7902        Self {
7903            probability: default_embezzlement_probability(),
7904            testing_stage: SchemeStageConfig {
7905                duration_months: 2,
7906                amount_min: 100.0,
7907                amount_max: 500.0,
7908                transaction_count_min: 2,
7909                transaction_count_max: 5,
7910                difficulty: "hard".to_string(),
7911            },
7912            escalation_stage: SchemeStageConfig {
7913                duration_months: 6,
7914                amount_min: 500.0,
7915                amount_max: 2000.0,
7916                transaction_count_min: 3,
7917                transaction_count_max: 8,
7918                difficulty: "moderate".to_string(),
7919            },
7920            acceleration_stage: SchemeStageConfig {
7921                duration_months: 3,
7922                amount_min: 2000.0,
7923                amount_max: 10000.0,
7924                transaction_count_min: 5,
7925                transaction_count_max: 12,
7926                difficulty: "easy".to_string(),
7927            },
7928            desperation_stage: SchemeStageConfig {
7929                duration_months: 1,
7930                amount_min: 10000.0,
7931                amount_max: 50000.0,
7932                transaction_count_min: 3,
7933                transaction_count_max: 6,
7934                difficulty: "trivial".to_string(),
7935            },
7936        }
7937    }
7938}
7939
7940/// Revenue manipulation scheme configuration.
7941#[derive(Debug, Clone, Serialize, Deserialize)]
7942pub struct RevenueManipulationSchemeConfig {
7943    /// Probability of starting a revenue manipulation scheme per period.
7944    #[serde(default = "default_revenue_manipulation_probability")]
7945    pub probability: f64,
7946
7947    /// Early revenue recognition inflation target (Q4).
7948    #[serde(default = "default_early_recognition_target")]
7949    pub early_recognition_target: f64,
7950
7951    /// Expense deferral inflation target (Q1).
7952    #[serde(default = "default_expense_deferral_target")]
7953    pub expense_deferral_target: f64,
7954
7955    /// Reserve release inflation target (Q2).
7956    #[serde(default = "default_reserve_release_target")]
7957    pub reserve_release_target: f64,
7958
7959    /// Channel stuffing inflation target (Q4).
7960    #[serde(default = "default_channel_stuffing_target")]
7961    pub channel_stuffing_target: f64,
7962}
7963
7964fn default_revenue_manipulation_probability() -> f64 {
7965    0.01
7966}
7967fn default_early_recognition_target() -> f64 {
7968    0.02
7969}
7970fn default_expense_deferral_target() -> f64 {
7971    0.03
7972}
7973fn default_reserve_release_target() -> f64 {
7974    0.02
7975}
7976fn default_channel_stuffing_target() -> f64 {
7977    0.05
7978}
7979
7980impl Default for RevenueManipulationSchemeConfig {
7981    fn default() -> Self {
7982        Self {
7983            probability: default_revenue_manipulation_probability(),
7984            early_recognition_target: default_early_recognition_target(),
7985            expense_deferral_target: default_expense_deferral_target(),
7986            reserve_release_target: default_reserve_release_target(),
7987            channel_stuffing_target: default_channel_stuffing_target(),
7988        }
7989    }
7990}
7991
7992/// Vendor kickback scheme configuration.
7993#[derive(Debug, Clone, Serialize, Deserialize)]
7994pub struct KickbackSchemeConfig {
7995    /// Probability of starting a kickback scheme.
7996    #[serde(default = "default_kickback_probability")]
7997    pub probability: f64,
7998
7999    /// Minimum price inflation percentage.
8000    #[serde(default = "default_kickback_inflation_min")]
8001    pub inflation_min: f64,
8002
8003    /// Maximum price inflation percentage.
8004    #[serde(default = "default_kickback_inflation_max")]
8005    pub inflation_max: f64,
8006
8007    /// Kickback percentage (of inflation).
8008    #[serde(default = "default_kickback_percent")]
8009    pub kickback_percent: f64,
8010
8011    /// Setup duration in months.
8012    #[serde(default = "default_kickback_setup_months")]
8013    pub setup_months: u32,
8014
8015    /// Main operation duration in months.
8016    #[serde(default = "default_kickback_operation_months")]
8017    pub operation_months: u32,
8018}
8019
8020fn default_kickback_probability() -> f64 {
8021    0.01
8022}
8023fn default_kickback_inflation_min() -> f64 {
8024    0.10
8025}
8026fn default_kickback_inflation_max() -> f64 {
8027    0.25
8028}
8029fn default_kickback_percent() -> f64 {
8030    0.50
8031}
8032fn default_kickback_setup_months() -> u32 {
8033    3
8034}
8035fn default_kickback_operation_months() -> u32 {
8036    12
8037}
8038
8039impl Default for KickbackSchemeConfig {
8040    fn default() -> Self {
8041        Self {
8042            probability: default_kickback_probability(),
8043            inflation_min: default_kickback_inflation_min(),
8044            inflation_max: default_kickback_inflation_max(),
8045            kickback_percent: default_kickback_percent(),
8046            setup_months: default_kickback_setup_months(),
8047            operation_months: default_kickback_operation_months(),
8048        }
8049    }
8050}
8051
8052/// Individual scheme stage configuration.
8053#[derive(Debug, Clone, Serialize, Deserialize)]
8054pub struct SchemeStageConfig {
8055    /// Duration in months.
8056    pub duration_months: u32,
8057
8058    /// Minimum transaction amount.
8059    pub amount_min: f64,
8060
8061    /// Maximum transaction amount.
8062    pub amount_max: f64,
8063
8064    /// Minimum number of transactions.
8065    pub transaction_count_min: u32,
8066
8067    /// Maximum number of transactions.
8068    pub transaction_count_max: u32,
8069
8070    /// Detection difficulty level (trivial, easy, moderate, hard, expert).
8071    pub difficulty: String,
8072}
8073
8074impl Default for SchemeStageConfig {
8075    fn default() -> Self {
8076        Self {
8077            duration_months: 3,
8078            amount_min: 100.0,
8079            amount_max: 1000.0,
8080            transaction_count_min: 2,
8081            transaction_count_max: 10,
8082            difficulty: "moderate".to_string(),
8083        }
8084    }
8085}
8086
8087/// Correlated anomaly injection configuration.
8088#[derive(Debug, Clone, Serialize, Deserialize)]
8089pub struct CorrelatedInjectionConfig {
8090    /// Enable correlated anomaly injection.
8091    #[serde(default)]
8092    pub enabled: bool,
8093
8094    /// Enable fraud concealment co-occurrence patterns.
8095    #[serde(default = "default_true_val")]
8096    pub fraud_concealment: bool,
8097
8098    /// Enable error cascade patterns.
8099    #[serde(default = "default_true_val")]
8100    pub error_cascade: bool,
8101
8102    /// Enable temporal clustering (period-end spikes).
8103    #[serde(default = "default_true_val")]
8104    pub temporal_clustering: bool,
8105
8106    /// Temporal clustering configuration.
8107    #[serde(default)]
8108    pub temporal_clustering_config: TemporalClusteringConfig,
8109
8110    /// Co-occurrence patterns.
8111    #[serde(default)]
8112    pub co_occurrence_patterns: Vec<CoOccurrencePatternConfig>,
8113}
8114
8115impl Default for CorrelatedInjectionConfig {
8116    fn default() -> Self {
8117        Self {
8118            enabled: false,
8119            fraud_concealment: true,
8120            error_cascade: true,
8121            temporal_clustering: true,
8122            temporal_clustering_config: TemporalClusteringConfig::default(),
8123            co_occurrence_patterns: Vec::new(),
8124        }
8125    }
8126}
8127
8128/// Temporal clustering configuration.
8129#[derive(Debug, Clone, Serialize, Deserialize)]
8130pub struct TemporalClusteringConfig {
8131    /// Period-end error multiplier.
8132    #[serde(default = "default_period_end_multiplier")]
8133    pub period_end_multiplier: f64,
8134
8135    /// Number of business days before period end to apply multiplier.
8136    #[serde(default = "default_period_end_days")]
8137    pub period_end_days: u32,
8138
8139    /// Quarter-end additional multiplier.
8140    #[serde(default = "default_quarter_end_multiplier")]
8141    pub quarter_end_multiplier: f64,
8142
8143    /// Year-end additional multiplier.
8144    #[serde(default = "default_year_end_multiplier")]
8145    pub year_end_multiplier: f64,
8146}
8147
8148fn default_period_end_multiplier() -> f64 {
8149    2.5
8150}
8151fn default_period_end_days() -> u32 {
8152    5
8153}
8154fn default_quarter_end_multiplier() -> f64 {
8155    1.5
8156}
8157fn default_year_end_multiplier() -> f64 {
8158    2.0
8159}
8160
8161impl Default for TemporalClusteringConfig {
8162    fn default() -> Self {
8163        Self {
8164            period_end_multiplier: default_period_end_multiplier(),
8165            period_end_days: default_period_end_days(),
8166            quarter_end_multiplier: default_quarter_end_multiplier(),
8167            year_end_multiplier: default_year_end_multiplier(),
8168        }
8169    }
8170}
8171
8172/// Co-occurrence pattern configuration.
8173#[derive(Debug, Clone, Serialize, Deserialize)]
8174pub struct CoOccurrencePatternConfig {
8175    /// Pattern name.
8176    pub name: String,
8177
8178    /// Primary anomaly type that triggers the pattern.
8179    pub primary_type: String,
8180
8181    /// Correlated anomalies.
8182    pub correlated: Vec<CorrelatedAnomalyConfig>,
8183}
8184
8185/// Correlated anomaly configuration.
8186#[derive(Debug, Clone, Serialize, Deserialize)]
8187pub struct CorrelatedAnomalyConfig {
8188    /// Anomaly type.
8189    pub anomaly_type: String,
8190
8191    /// Probability of occurrence (0.0 to 1.0).
8192    pub probability: f64,
8193
8194    /// Minimum lag in days.
8195    pub lag_days_min: i32,
8196
8197    /// Maximum lag in days.
8198    pub lag_days_max: i32,
8199}
8200
8201/// Near-miss generation configuration.
8202#[derive(Debug, Clone, Serialize, Deserialize)]
8203pub struct NearMissConfig {
8204    /// Enable near-miss generation.
8205    #[serde(default)]
8206    pub enabled: bool,
8207
8208    /// Proportion of "anomalies" that are actually near-misses (0.0 to 1.0).
8209    #[serde(default = "default_near_miss_proportion")]
8210    pub proportion: f64,
8211
8212    /// Enable near-duplicate pattern.
8213    #[serde(default = "default_true_val")]
8214    pub near_duplicate: bool,
8215
8216    /// Near-duplicate date difference range in days.
8217    #[serde(default)]
8218    pub near_duplicate_days: NearDuplicateDaysConfig,
8219
8220    /// Enable threshold proximity pattern.
8221    #[serde(default = "default_true_val")]
8222    pub threshold_proximity: bool,
8223
8224    /// Threshold proximity range (e.g., 0.90-0.99 of threshold).
8225    #[serde(default)]
8226    pub threshold_proximity_range: ThresholdProximityRangeConfig,
8227
8228    /// Enable unusual but legitimate patterns.
8229    #[serde(default = "default_true_val")]
8230    pub unusual_legitimate: bool,
8231
8232    /// Types of unusual legitimate patterns to generate.
8233    #[serde(default = "default_unusual_legitimate_types")]
8234    pub unusual_legitimate_types: Vec<String>,
8235
8236    /// Enable corrected error patterns.
8237    #[serde(default = "default_true_val")]
8238    pub corrected_errors: bool,
8239
8240    /// Corrected error correction lag range in days.
8241    #[serde(default)]
8242    pub corrected_error_lag: CorrectedErrorLagConfig,
8243}
8244
8245fn default_near_miss_proportion() -> f64 {
8246    0.30
8247}
8248
8249fn default_unusual_legitimate_types() -> Vec<String> {
8250    vec![
8251        "year_end_bonus".to_string(),
8252        "contract_prepayment".to_string(),
8253        "insurance_claim".to_string(),
8254        "settlement_payment".to_string(),
8255    ]
8256}
8257
8258impl Default for NearMissConfig {
8259    fn default() -> Self {
8260        Self {
8261            enabled: false,
8262            proportion: default_near_miss_proportion(),
8263            near_duplicate: true,
8264            near_duplicate_days: NearDuplicateDaysConfig::default(),
8265            threshold_proximity: true,
8266            threshold_proximity_range: ThresholdProximityRangeConfig::default(),
8267            unusual_legitimate: true,
8268            unusual_legitimate_types: default_unusual_legitimate_types(),
8269            corrected_errors: true,
8270            corrected_error_lag: CorrectedErrorLagConfig::default(),
8271        }
8272    }
8273}
8274
8275/// Near-duplicate days configuration.
8276#[derive(Debug, Clone, Serialize, Deserialize)]
8277pub struct NearDuplicateDaysConfig {
8278    /// Minimum days apart.
8279    #[serde(default = "default_near_duplicate_min")]
8280    pub min: u32,
8281
8282    /// Maximum days apart.
8283    #[serde(default = "default_near_duplicate_max")]
8284    pub max: u32,
8285}
8286
8287fn default_near_duplicate_min() -> u32 {
8288    1
8289}
8290fn default_near_duplicate_max() -> u32 {
8291    3
8292}
8293
8294impl Default for NearDuplicateDaysConfig {
8295    fn default() -> Self {
8296        Self {
8297            min: default_near_duplicate_min(),
8298            max: default_near_duplicate_max(),
8299        }
8300    }
8301}
8302
8303/// Threshold proximity range configuration.
8304#[derive(Debug, Clone, Serialize, Deserialize)]
8305pub struct ThresholdProximityRangeConfig {
8306    /// Minimum proximity (e.g., 0.90 = 90% of threshold).
8307    #[serde(default = "default_threshold_proximity_min")]
8308    pub min: f64,
8309
8310    /// Maximum proximity (e.g., 0.99 = 99% of threshold).
8311    #[serde(default = "default_threshold_proximity_max")]
8312    pub max: f64,
8313}
8314
8315fn default_threshold_proximity_min() -> f64 {
8316    0.90
8317}
8318fn default_threshold_proximity_max() -> f64 {
8319    0.99
8320}
8321
8322impl Default for ThresholdProximityRangeConfig {
8323    fn default() -> Self {
8324        Self {
8325            min: default_threshold_proximity_min(),
8326            max: default_threshold_proximity_max(),
8327        }
8328    }
8329}
8330
8331/// Corrected error lag configuration.
8332#[derive(Debug, Clone, Serialize, Deserialize)]
8333pub struct CorrectedErrorLagConfig {
8334    /// Minimum correction lag in days.
8335    #[serde(default = "default_corrected_error_lag_min")]
8336    pub min: u32,
8337
8338    /// Maximum correction lag in days.
8339    #[serde(default = "default_corrected_error_lag_max")]
8340    pub max: u32,
8341}
8342
8343fn default_corrected_error_lag_min() -> u32 {
8344    1
8345}
8346fn default_corrected_error_lag_max() -> u32 {
8347    5
8348}
8349
8350impl Default for CorrectedErrorLagConfig {
8351    fn default() -> Self {
8352        Self {
8353            min: default_corrected_error_lag_min(),
8354            max: default_corrected_error_lag_max(),
8355        }
8356    }
8357}
8358
8359/// Detection difficulty classification configuration.
8360#[derive(Debug, Clone, Serialize, Deserialize)]
8361pub struct DifficultyClassificationConfig {
8362    /// Enable detection difficulty classification.
8363    #[serde(default)]
8364    pub enabled: bool,
8365
8366    /// Target distribution of difficulty levels.
8367    #[serde(default)]
8368    pub target_distribution: DifficultyDistributionConfig,
8369}
8370
8371impl Default for DifficultyClassificationConfig {
8372    fn default() -> Self {
8373        Self {
8374            enabled: true,
8375            target_distribution: DifficultyDistributionConfig::default(),
8376        }
8377    }
8378}
8379
8380/// Target distribution of detection difficulty levels.
8381#[derive(Debug, Clone, Serialize, Deserialize)]
8382pub struct DifficultyDistributionConfig {
8383    /// Proportion of trivial anomalies (expected 99% detection).
8384    #[serde(default = "default_difficulty_trivial")]
8385    pub trivial: f64,
8386
8387    /// Proportion of easy anomalies (expected 90% detection).
8388    #[serde(default = "default_difficulty_easy")]
8389    pub easy: f64,
8390
8391    /// Proportion of moderate anomalies (expected 70% detection).
8392    #[serde(default = "default_difficulty_moderate")]
8393    pub moderate: f64,
8394
8395    /// Proportion of hard anomalies (expected 40% detection).
8396    #[serde(default = "default_difficulty_hard")]
8397    pub hard: f64,
8398
8399    /// Proportion of expert anomalies (expected 15% detection).
8400    #[serde(default = "default_difficulty_expert")]
8401    pub expert: f64,
8402}
8403
8404fn default_difficulty_trivial() -> f64 {
8405    0.15
8406}
8407fn default_difficulty_easy() -> f64 {
8408    0.25
8409}
8410fn default_difficulty_moderate() -> f64 {
8411    0.30
8412}
8413fn default_difficulty_hard() -> f64 {
8414    0.20
8415}
8416fn default_difficulty_expert() -> f64 {
8417    0.10
8418}
8419
8420impl Default for DifficultyDistributionConfig {
8421    fn default() -> Self {
8422        Self {
8423            trivial: default_difficulty_trivial(),
8424            easy: default_difficulty_easy(),
8425            moderate: default_difficulty_moderate(),
8426            hard: default_difficulty_hard(),
8427            expert: default_difficulty_expert(),
8428        }
8429    }
8430}
8431
8432/// Context-aware injection configuration.
8433#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8434pub struct ContextAwareConfig {
8435    /// Enable context-aware injection.
8436    #[serde(default)]
8437    pub enabled: bool,
8438
8439    /// Vendor-specific anomaly rules.
8440    #[serde(default)]
8441    pub vendor_rules: VendorAnomalyRulesConfig,
8442
8443    /// Employee-specific anomaly rules.
8444    #[serde(default)]
8445    pub employee_rules: EmployeeAnomalyRulesConfig,
8446
8447    /// Account-specific anomaly rules.
8448    #[serde(default)]
8449    pub account_rules: AccountAnomalyRulesConfig,
8450
8451    /// Behavioral baseline configuration.
8452    #[serde(default)]
8453    pub behavioral_baseline: BehavioralBaselineConfig,
8454}
8455
8456/// Vendor-specific anomaly rules configuration.
8457#[derive(Debug, Clone, Serialize, Deserialize)]
8458pub struct VendorAnomalyRulesConfig {
8459    /// Error rate multiplier for new vendors (< threshold days).
8460    #[serde(default = "default_new_vendor_multiplier")]
8461    pub new_vendor_error_multiplier: f64,
8462
8463    /// Days threshold for "new" vendor classification.
8464    #[serde(default = "default_new_vendor_threshold")]
8465    pub new_vendor_threshold_days: u32,
8466
8467    /// Error rate multiplier for international vendors.
8468    #[serde(default = "default_international_multiplier")]
8469    pub international_error_multiplier: f64,
8470
8471    /// Strategic vendor anomaly types (may differ from general vendors).
8472    #[serde(default = "default_strategic_vendor_types")]
8473    pub strategic_vendor_anomaly_types: Vec<String>,
8474}
8475
8476fn default_new_vendor_multiplier() -> f64 {
8477    2.5
8478}
8479fn default_new_vendor_threshold() -> u32 {
8480    90
8481}
8482fn default_international_multiplier() -> f64 {
8483    1.5
8484}
8485fn default_strategic_vendor_types() -> Vec<String> {
8486    vec![
8487        "pricing_dispute".to_string(),
8488        "contract_violation".to_string(),
8489    ]
8490}
8491
8492impl Default for VendorAnomalyRulesConfig {
8493    fn default() -> Self {
8494        Self {
8495            new_vendor_error_multiplier: default_new_vendor_multiplier(),
8496            new_vendor_threshold_days: default_new_vendor_threshold(),
8497            international_error_multiplier: default_international_multiplier(),
8498            strategic_vendor_anomaly_types: default_strategic_vendor_types(),
8499        }
8500    }
8501}
8502
8503/// Employee-specific anomaly rules configuration.
8504#[derive(Debug, Clone, Serialize, Deserialize)]
8505pub struct EmployeeAnomalyRulesConfig {
8506    /// Error rate for new employees (< threshold days).
8507    #[serde(default = "default_new_employee_rate")]
8508    pub new_employee_error_rate: f64,
8509
8510    /// Days threshold for "new" employee classification.
8511    #[serde(default = "default_new_employee_threshold")]
8512    pub new_employee_threshold_days: u32,
8513
8514    /// Transaction volume threshold for fatigue errors.
8515    #[serde(default = "default_volume_fatigue_threshold")]
8516    pub volume_fatigue_threshold: u32,
8517
8518    /// Error rate multiplier when primary approver is absent.
8519    #[serde(default = "default_coverage_multiplier")]
8520    pub coverage_error_multiplier: f64,
8521}
8522
8523fn default_new_employee_rate() -> f64 {
8524    0.05
8525}
8526fn default_new_employee_threshold() -> u32 {
8527    180
8528}
8529fn default_volume_fatigue_threshold() -> u32 {
8530    50
8531}
8532fn default_coverage_multiplier() -> f64 {
8533    1.8
8534}
8535
8536impl Default for EmployeeAnomalyRulesConfig {
8537    fn default() -> Self {
8538        Self {
8539            new_employee_error_rate: default_new_employee_rate(),
8540            new_employee_threshold_days: default_new_employee_threshold(),
8541            volume_fatigue_threshold: default_volume_fatigue_threshold(),
8542            coverage_error_multiplier: default_coverage_multiplier(),
8543        }
8544    }
8545}
8546
8547/// Account-specific anomaly rules configuration.
8548#[derive(Debug, Clone, Serialize, Deserialize)]
8549pub struct AccountAnomalyRulesConfig {
8550    /// Error rate multiplier for high-risk accounts.
8551    #[serde(default = "default_high_risk_multiplier")]
8552    pub high_risk_account_multiplier: f64,
8553
8554    /// Account codes considered high-risk.
8555    #[serde(default = "default_high_risk_accounts")]
8556    pub high_risk_accounts: Vec<String>,
8557
8558    /// Error rate multiplier for suspense accounts.
8559    #[serde(default = "default_suspense_multiplier")]
8560    pub suspense_account_multiplier: f64,
8561
8562    /// Account codes considered suspense accounts.
8563    #[serde(default = "default_suspense_accounts")]
8564    pub suspense_accounts: Vec<String>,
8565
8566    /// Error rate multiplier for intercompany accounts.
8567    #[serde(default = "default_intercompany_multiplier")]
8568    pub intercompany_account_multiplier: f64,
8569}
8570
8571fn default_high_risk_multiplier() -> f64 {
8572    2.0
8573}
8574fn default_high_risk_accounts() -> Vec<String> {
8575    vec![
8576        "1100".to_string(), // AR Control
8577        "2000".to_string(), // AP Control
8578        "3000".to_string(), // Cash
8579    ]
8580}
8581fn default_suspense_multiplier() -> f64 {
8582    3.0
8583}
8584fn default_suspense_accounts() -> Vec<String> {
8585    vec!["9999".to_string(), "9998".to_string()]
8586}
8587fn default_intercompany_multiplier() -> f64 {
8588    1.5
8589}
8590
8591impl Default for AccountAnomalyRulesConfig {
8592    fn default() -> Self {
8593        Self {
8594            high_risk_account_multiplier: default_high_risk_multiplier(),
8595            high_risk_accounts: default_high_risk_accounts(),
8596            suspense_account_multiplier: default_suspense_multiplier(),
8597            suspense_accounts: default_suspense_accounts(),
8598            intercompany_account_multiplier: default_intercompany_multiplier(),
8599        }
8600    }
8601}
8602
8603/// Behavioral baseline configuration.
8604#[derive(Debug, Clone, Serialize, Deserialize)]
8605pub struct BehavioralBaselineConfig {
8606    /// Enable behavioral baseline tracking.
8607    #[serde(default)]
8608    pub enabled: bool,
8609
8610    /// Number of days to build baseline from.
8611    #[serde(default = "default_baseline_period")]
8612    pub baseline_period_days: u32,
8613
8614    /// Standard deviation threshold for amount anomalies.
8615    #[serde(default = "default_deviation_threshold")]
8616    pub deviation_threshold_std: f64,
8617
8618    /// Standard deviation threshold for frequency anomalies.
8619    #[serde(default = "default_frequency_deviation")]
8620    pub frequency_deviation_threshold: f64,
8621}
8622
8623fn default_baseline_period() -> u32 {
8624    90
8625}
8626fn default_deviation_threshold() -> f64 {
8627    3.0
8628}
8629fn default_frequency_deviation() -> f64 {
8630    2.0
8631}
8632
8633impl Default for BehavioralBaselineConfig {
8634    fn default() -> Self {
8635        Self {
8636            enabled: false,
8637            baseline_period_days: default_baseline_period(),
8638            deviation_threshold_std: default_deviation_threshold(),
8639            frequency_deviation_threshold: default_frequency_deviation(),
8640        }
8641    }
8642}
8643
8644/// Enhanced labeling configuration.
8645#[derive(Debug, Clone, Serialize, Deserialize)]
8646pub struct EnhancedLabelingConfig {
8647    /// Enable severity scoring.
8648    #[serde(default = "default_true_val")]
8649    pub severity_scoring: bool,
8650
8651    /// Enable difficulty classification.
8652    #[serde(default = "default_true_val")]
8653    pub difficulty_classification: bool,
8654
8655    /// Materiality thresholds for severity classification.
8656    #[serde(default)]
8657    pub materiality_thresholds: MaterialityThresholdsConfig,
8658}
8659
8660impl Default for EnhancedLabelingConfig {
8661    fn default() -> Self {
8662        Self {
8663            severity_scoring: true,
8664            difficulty_classification: true,
8665            materiality_thresholds: MaterialityThresholdsConfig::default(),
8666        }
8667    }
8668}
8669
8670/// Materiality thresholds configuration.
8671#[derive(Debug, Clone, Serialize, Deserialize)]
8672pub struct MaterialityThresholdsConfig {
8673    /// Threshold for trivial impact (as percentage of total).
8674    #[serde(default = "default_materiality_trivial")]
8675    pub trivial: f64,
8676
8677    /// Threshold for immaterial impact.
8678    #[serde(default = "default_materiality_immaterial")]
8679    pub immaterial: f64,
8680
8681    /// Threshold for material impact.
8682    #[serde(default = "default_materiality_material")]
8683    pub material: f64,
8684
8685    /// Threshold for highly material impact.
8686    #[serde(default = "default_materiality_highly_material")]
8687    pub highly_material: f64,
8688}
8689
8690fn default_materiality_trivial() -> f64 {
8691    0.001
8692}
8693fn default_materiality_immaterial() -> f64 {
8694    0.01
8695}
8696fn default_materiality_material() -> f64 {
8697    0.05
8698}
8699fn default_materiality_highly_material() -> f64 {
8700    0.10
8701}
8702
8703impl Default for MaterialityThresholdsConfig {
8704    fn default() -> Self {
8705        Self {
8706            trivial: default_materiality_trivial(),
8707            immaterial: default_materiality_immaterial(),
8708            material: default_materiality_material(),
8709            highly_material: default_materiality_highly_material(),
8710        }
8711    }
8712}
8713
8714// =============================================================================
8715// Industry-Specific Configuration
8716// =============================================================================
8717
8718/// Industry-specific transaction and anomaly generation configuration.
8719///
8720/// This configuration enables generation of industry-authentic:
8721/// - Transaction types with appropriate terminology
8722/// - Master data (BOM, routings, clinical codes, etc.)
8723/// - Industry-specific anomaly patterns
8724/// - Regulatory framework compliance
8725#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8726pub struct IndustrySpecificConfig {
8727    /// Enable industry-specific generation.
8728    #[serde(default)]
8729    pub enabled: bool,
8730
8731    /// Manufacturing industry settings.
8732    #[serde(default)]
8733    pub manufacturing: ManufacturingConfig,
8734
8735    /// Retail industry settings.
8736    #[serde(default)]
8737    pub retail: RetailConfig,
8738
8739    /// Healthcare industry settings.
8740    #[serde(default)]
8741    pub healthcare: HealthcareConfig,
8742
8743    /// Technology industry settings.
8744    #[serde(default)]
8745    pub technology: TechnologyConfig,
8746
8747    /// Financial services industry settings.
8748    #[serde(default)]
8749    pub financial_services: FinancialServicesConfig,
8750
8751    /// Professional services industry settings.
8752    #[serde(default)]
8753    pub professional_services: ProfessionalServicesConfig,
8754}
8755
8756/// Manufacturing industry configuration.
8757#[derive(Debug, Clone, Serialize, Deserialize)]
8758pub struct ManufacturingConfig {
8759    /// Enable manufacturing-specific generation.
8760    #[serde(default)]
8761    pub enabled: bool,
8762
8763    /// Bill of Materials depth (typical: 3-7).
8764    #[serde(default = "default_bom_depth")]
8765    pub bom_depth: u32,
8766
8767    /// Whether to use just-in-time inventory.
8768    #[serde(default)]
8769    pub just_in_time: bool,
8770
8771    /// Production order types to generate.
8772    #[serde(default = "default_production_order_types")]
8773    pub production_order_types: Vec<String>,
8774
8775    /// Quality framework (ISO_9001, Six_Sigma, etc.).
8776    #[serde(default)]
8777    pub quality_framework: Option<String>,
8778
8779    /// Number of supplier tiers to model (1-3).
8780    #[serde(default = "default_supplier_tiers")]
8781    pub supplier_tiers: u32,
8782
8783    /// Standard cost update frequency.
8784    #[serde(default = "default_cost_frequency")]
8785    pub standard_cost_frequency: String,
8786
8787    /// Target yield rate (0.95-0.99 typical).
8788    #[serde(default = "default_yield_rate")]
8789    pub target_yield_rate: f64,
8790
8791    /// Scrap percentage threshold for alerts.
8792    #[serde(default = "default_scrap_threshold")]
8793    pub scrap_alert_threshold: f64,
8794
8795    /// Manufacturing anomaly injection rates.
8796    #[serde(default)]
8797    pub anomaly_rates: ManufacturingAnomalyRates,
8798}
8799
8800fn default_bom_depth() -> u32 {
8801    4
8802}
8803
8804fn default_production_order_types() -> Vec<String> {
8805    vec![
8806        "standard".to_string(),
8807        "rework".to_string(),
8808        "prototype".to_string(),
8809    ]
8810}
8811
8812fn default_supplier_tiers() -> u32 {
8813    2
8814}
8815
8816fn default_cost_frequency() -> String {
8817    "quarterly".to_string()
8818}
8819
8820fn default_yield_rate() -> f64 {
8821    0.97
8822}
8823
8824fn default_scrap_threshold() -> f64 {
8825    0.03
8826}
8827
8828impl Default for ManufacturingConfig {
8829    fn default() -> Self {
8830        Self {
8831            enabled: false,
8832            bom_depth: default_bom_depth(),
8833            just_in_time: false,
8834            production_order_types: default_production_order_types(),
8835            quality_framework: Some("ISO_9001".to_string()),
8836            supplier_tiers: default_supplier_tiers(),
8837            standard_cost_frequency: default_cost_frequency(),
8838            target_yield_rate: default_yield_rate(),
8839            scrap_alert_threshold: default_scrap_threshold(),
8840            anomaly_rates: ManufacturingAnomalyRates::default(),
8841        }
8842    }
8843}
8844
8845/// Manufacturing anomaly injection rates.
8846#[derive(Debug, Clone, Serialize, Deserialize)]
8847pub struct ManufacturingAnomalyRates {
8848    /// Yield manipulation rate.
8849    #[serde(default = "default_mfg_yield_rate")]
8850    pub yield_manipulation: f64,
8851
8852    /// Labor misallocation rate.
8853    #[serde(default = "default_mfg_labor_rate")]
8854    pub labor_misallocation: f64,
8855
8856    /// Phantom production rate.
8857    #[serde(default = "default_mfg_phantom_rate")]
8858    pub phantom_production: f64,
8859
8860    /// Standard cost manipulation rate.
8861    #[serde(default = "default_mfg_cost_rate")]
8862    pub standard_cost_manipulation: f64,
8863
8864    /// Inventory fraud rate.
8865    #[serde(default = "default_mfg_inventory_rate")]
8866    pub inventory_fraud: f64,
8867}
8868
8869fn default_mfg_yield_rate() -> f64 {
8870    0.015
8871}
8872
8873fn default_mfg_labor_rate() -> f64 {
8874    0.02
8875}
8876
8877fn default_mfg_phantom_rate() -> f64 {
8878    0.005
8879}
8880
8881fn default_mfg_cost_rate() -> f64 {
8882    0.01
8883}
8884
8885fn default_mfg_inventory_rate() -> f64 {
8886    0.008
8887}
8888
8889impl Default for ManufacturingAnomalyRates {
8890    fn default() -> Self {
8891        Self {
8892            yield_manipulation: default_mfg_yield_rate(),
8893            labor_misallocation: default_mfg_labor_rate(),
8894            phantom_production: default_mfg_phantom_rate(),
8895            standard_cost_manipulation: default_mfg_cost_rate(),
8896            inventory_fraud: default_mfg_inventory_rate(),
8897        }
8898    }
8899}
8900
8901/// Retail industry configuration.
8902#[derive(Debug, Clone, Serialize, Deserialize)]
8903pub struct RetailConfig {
8904    /// Enable retail-specific generation.
8905    #[serde(default)]
8906    pub enabled: bool,
8907
8908    /// Store type distribution.
8909    #[serde(default)]
8910    pub store_types: RetailStoreTypeConfig,
8911
8912    /// Average daily transactions per store.
8913    #[serde(default = "default_retail_daily_txns")]
8914    pub avg_daily_transactions: u32,
8915
8916    /// Enable loss prevention tracking.
8917    #[serde(default = "default_true")]
8918    pub loss_prevention: bool,
8919
8920    /// Shrinkage rate (0.01-0.03 typical).
8921    #[serde(default = "default_shrinkage_rate")]
8922    pub shrinkage_rate: f64,
8923
8924    /// Retail anomaly injection rates.
8925    #[serde(default)]
8926    pub anomaly_rates: RetailAnomalyRates,
8927}
8928
8929fn default_retail_daily_txns() -> u32 {
8930    500
8931}
8932
8933fn default_shrinkage_rate() -> f64 {
8934    0.015
8935}
8936
8937impl Default for RetailConfig {
8938    fn default() -> Self {
8939        Self {
8940            enabled: false,
8941            store_types: RetailStoreTypeConfig::default(),
8942            avg_daily_transactions: default_retail_daily_txns(),
8943            loss_prevention: true,
8944            shrinkage_rate: default_shrinkage_rate(),
8945            anomaly_rates: RetailAnomalyRates::default(),
8946        }
8947    }
8948}
8949
8950/// Retail store type distribution.
8951#[derive(Debug, Clone, Serialize, Deserialize)]
8952pub struct RetailStoreTypeConfig {
8953    /// Percentage of flagship stores.
8954    #[serde(default = "default_flagship_pct")]
8955    pub flagship: f64,
8956
8957    /// Percentage of regional stores.
8958    #[serde(default = "default_regional_pct")]
8959    pub regional: f64,
8960
8961    /// Percentage of outlet stores.
8962    #[serde(default = "default_outlet_pct")]
8963    pub outlet: f64,
8964
8965    /// Percentage of e-commerce.
8966    #[serde(default = "default_ecommerce_pct")]
8967    pub ecommerce: f64,
8968}
8969
8970fn default_flagship_pct() -> f64 {
8971    0.10
8972}
8973
8974fn default_regional_pct() -> f64 {
8975    0.50
8976}
8977
8978fn default_outlet_pct() -> f64 {
8979    0.25
8980}
8981
8982fn default_ecommerce_pct() -> f64 {
8983    0.15
8984}
8985
8986impl Default for RetailStoreTypeConfig {
8987    fn default() -> Self {
8988        Self {
8989            flagship: default_flagship_pct(),
8990            regional: default_regional_pct(),
8991            outlet: default_outlet_pct(),
8992            ecommerce: default_ecommerce_pct(),
8993        }
8994    }
8995}
8996
8997/// Retail anomaly injection rates.
8998#[derive(Debug, Clone, Serialize, Deserialize)]
8999pub struct RetailAnomalyRates {
9000    /// Sweethearting rate.
9001    #[serde(default = "default_sweethearting_rate")]
9002    pub sweethearting: f64,
9003
9004    /// Skimming rate.
9005    #[serde(default = "default_skimming_rate")]
9006    pub skimming: f64,
9007
9008    /// Refund fraud rate.
9009    #[serde(default = "default_refund_fraud_rate")]
9010    pub refund_fraud: f64,
9011
9012    /// Void abuse rate.
9013    #[serde(default = "default_void_abuse_rate")]
9014    pub void_abuse: f64,
9015
9016    /// Gift card fraud rate.
9017    #[serde(default = "default_gift_card_rate")]
9018    pub gift_card_fraud: f64,
9019
9020    /// Vendor kickback rate.
9021    #[serde(default = "default_retail_kickback_rate")]
9022    pub vendor_kickback: f64,
9023}
9024
9025fn default_sweethearting_rate() -> f64 {
9026    0.02
9027}
9028
9029fn default_skimming_rate() -> f64 {
9030    0.005
9031}
9032
9033fn default_refund_fraud_rate() -> f64 {
9034    0.015
9035}
9036
9037fn default_void_abuse_rate() -> f64 {
9038    0.01
9039}
9040
9041fn default_gift_card_rate() -> f64 {
9042    0.008
9043}
9044
9045fn default_retail_kickback_rate() -> f64 {
9046    0.003
9047}
9048
9049impl Default for RetailAnomalyRates {
9050    fn default() -> Self {
9051        Self {
9052            sweethearting: default_sweethearting_rate(),
9053            skimming: default_skimming_rate(),
9054            refund_fraud: default_refund_fraud_rate(),
9055            void_abuse: default_void_abuse_rate(),
9056            gift_card_fraud: default_gift_card_rate(),
9057            vendor_kickback: default_retail_kickback_rate(),
9058        }
9059    }
9060}
9061
9062/// Healthcare industry configuration.
9063#[derive(Debug, Clone, Serialize, Deserialize)]
9064pub struct HealthcareConfig {
9065    /// Enable healthcare-specific generation.
9066    #[serde(default)]
9067    pub enabled: bool,
9068
9069    /// Healthcare facility type.
9070    #[serde(default = "default_facility_type")]
9071    pub facility_type: String,
9072
9073    /// Payer mix distribution.
9074    #[serde(default)]
9075    pub payer_mix: HealthcarePayerMix,
9076
9077    /// Coding systems enabled.
9078    #[serde(default)]
9079    pub coding_systems: HealthcareCodingSystems,
9080
9081    /// Healthcare compliance settings.
9082    #[serde(default)]
9083    pub compliance: HealthcareComplianceConfig,
9084
9085    /// Average daily encounters.
9086    #[serde(default = "default_daily_encounters")]
9087    pub avg_daily_encounters: u32,
9088
9089    /// Average charges per encounter.
9090    #[serde(default = "default_charges_per_encounter")]
9091    pub avg_charges_per_encounter: u32,
9092
9093    /// Denial rate (0.0-1.0).
9094    #[serde(default = "default_hc_denial_rate")]
9095    pub denial_rate: f64,
9096
9097    /// Bad debt rate (0.0-1.0).
9098    #[serde(default = "default_hc_bad_debt_rate")]
9099    pub bad_debt_rate: f64,
9100
9101    /// Charity care rate (0.0-1.0).
9102    #[serde(default = "default_hc_charity_care_rate")]
9103    pub charity_care_rate: f64,
9104
9105    /// Healthcare anomaly injection rates.
9106    #[serde(default)]
9107    pub anomaly_rates: HealthcareAnomalyRates,
9108}
9109
9110fn default_facility_type() -> String {
9111    "hospital".to_string()
9112}
9113
9114fn default_daily_encounters() -> u32 {
9115    150
9116}
9117
9118fn default_charges_per_encounter() -> u32 {
9119    8
9120}
9121
9122fn default_hc_denial_rate() -> f64 {
9123    0.05
9124}
9125
9126fn default_hc_bad_debt_rate() -> f64 {
9127    0.03
9128}
9129
9130fn default_hc_charity_care_rate() -> f64 {
9131    0.02
9132}
9133
9134impl Default for HealthcareConfig {
9135    fn default() -> Self {
9136        Self {
9137            enabled: false,
9138            facility_type: default_facility_type(),
9139            payer_mix: HealthcarePayerMix::default(),
9140            coding_systems: HealthcareCodingSystems::default(),
9141            compliance: HealthcareComplianceConfig::default(),
9142            avg_daily_encounters: default_daily_encounters(),
9143            avg_charges_per_encounter: default_charges_per_encounter(),
9144            denial_rate: default_hc_denial_rate(),
9145            bad_debt_rate: default_hc_bad_debt_rate(),
9146            charity_care_rate: default_hc_charity_care_rate(),
9147            anomaly_rates: HealthcareAnomalyRates::default(),
9148        }
9149    }
9150}
9151
9152/// Healthcare payer mix distribution.
9153#[derive(Debug, Clone, Serialize, Deserialize)]
9154pub struct HealthcarePayerMix {
9155    /// Medicare percentage.
9156    #[serde(default = "default_medicare_pct")]
9157    pub medicare: f64,
9158
9159    /// Medicaid percentage.
9160    #[serde(default = "default_medicaid_pct")]
9161    pub medicaid: f64,
9162
9163    /// Commercial insurance percentage.
9164    #[serde(default = "default_commercial_pct")]
9165    pub commercial: f64,
9166
9167    /// Self-pay percentage.
9168    #[serde(default = "default_self_pay_pct")]
9169    pub self_pay: f64,
9170}
9171
9172fn default_medicare_pct() -> f64 {
9173    0.40
9174}
9175
9176fn default_medicaid_pct() -> f64 {
9177    0.20
9178}
9179
9180fn default_commercial_pct() -> f64 {
9181    0.30
9182}
9183
9184fn default_self_pay_pct() -> f64 {
9185    0.10
9186}
9187
9188impl Default for HealthcarePayerMix {
9189    fn default() -> Self {
9190        Self {
9191            medicare: default_medicare_pct(),
9192            medicaid: default_medicaid_pct(),
9193            commercial: default_commercial_pct(),
9194            self_pay: default_self_pay_pct(),
9195        }
9196    }
9197}
9198
9199/// Healthcare coding systems configuration.
9200#[derive(Debug, Clone, Serialize, Deserialize)]
9201pub struct HealthcareCodingSystems {
9202    /// Enable ICD-10 diagnosis coding.
9203    #[serde(default = "default_true")]
9204    pub icd10: bool,
9205
9206    /// Enable CPT procedure coding.
9207    #[serde(default = "default_true")]
9208    pub cpt: bool,
9209
9210    /// Enable DRG grouping.
9211    #[serde(default = "default_true")]
9212    pub drg: bool,
9213
9214    /// Enable HCPCS Level II coding.
9215    #[serde(default = "default_true")]
9216    pub hcpcs: bool,
9217
9218    /// Enable revenue codes.
9219    #[serde(default = "default_true")]
9220    pub revenue_codes: bool,
9221}
9222
9223impl Default for HealthcareCodingSystems {
9224    fn default() -> Self {
9225        Self {
9226            icd10: true,
9227            cpt: true,
9228            drg: true,
9229            hcpcs: true,
9230            revenue_codes: true,
9231        }
9232    }
9233}
9234
9235/// Healthcare compliance configuration.
9236#[derive(Debug, Clone, Serialize, Deserialize)]
9237pub struct HealthcareComplianceConfig {
9238    /// Enable HIPAA compliance.
9239    #[serde(default = "default_true")]
9240    pub hipaa: bool,
9241
9242    /// Enable Stark Law compliance.
9243    #[serde(default = "default_true")]
9244    pub stark_law: bool,
9245
9246    /// Enable Anti-Kickback Statute compliance.
9247    #[serde(default = "default_true")]
9248    pub anti_kickback: bool,
9249
9250    /// Enable False Claims Act compliance.
9251    #[serde(default = "default_true")]
9252    pub false_claims_act: bool,
9253
9254    /// Enable EMTALA compliance (for hospitals).
9255    #[serde(default = "default_true")]
9256    pub emtala: bool,
9257}
9258
9259impl Default for HealthcareComplianceConfig {
9260    fn default() -> Self {
9261        Self {
9262            hipaa: true,
9263            stark_law: true,
9264            anti_kickback: true,
9265            false_claims_act: true,
9266            emtala: true,
9267        }
9268    }
9269}
9270
9271/// Healthcare anomaly injection rates.
9272#[derive(Debug, Clone, Serialize, Deserialize)]
9273pub struct HealthcareAnomalyRates {
9274    /// Upcoding rate.
9275    #[serde(default = "default_upcoding_rate")]
9276    pub upcoding: f64,
9277
9278    /// Unbundling rate.
9279    #[serde(default = "default_unbundling_rate")]
9280    pub unbundling: f64,
9281
9282    /// Phantom billing rate.
9283    #[serde(default = "default_phantom_billing_rate")]
9284    pub phantom_billing: f64,
9285
9286    /// Kickback rate.
9287    #[serde(default = "default_healthcare_kickback_rate")]
9288    pub kickbacks: f64,
9289
9290    /// Duplicate billing rate.
9291    #[serde(default = "default_duplicate_billing_rate")]
9292    pub duplicate_billing: f64,
9293
9294    /// Medical necessity abuse rate.
9295    #[serde(default = "default_med_necessity_rate")]
9296    pub medical_necessity_abuse: f64,
9297}
9298
9299fn default_upcoding_rate() -> f64 {
9300    0.02
9301}
9302
9303fn default_unbundling_rate() -> f64 {
9304    0.015
9305}
9306
9307fn default_phantom_billing_rate() -> f64 {
9308    0.005
9309}
9310
9311fn default_healthcare_kickback_rate() -> f64 {
9312    0.003
9313}
9314
9315fn default_duplicate_billing_rate() -> f64 {
9316    0.008
9317}
9318
9319fn default_med_necessity_rate() -> f64 {
9320    0.01
9321}
9322
9323impl Default for HealthcareAnomalyRates {
9324    fn default() -> Self {
9325        Self {
9326            upcoding: default_upcoding_rate(),
9327            unbundling: default_unbundling_rate(),
9328            phantom_billing: default_phantom_billing_rate(),
9329            kickbacks: default_healthcare_kickback_rate(),
9330            duplicate_billing: default_duplicate_billing_rate(),
9331            medical_necessity_abuse: default_med_necessity_rate(),
9332        }
9333    }
9334}
9335
9336/// Technology industry configuration.
9337#[derive(Debug, Clone, Serialize, Deserialize)]
9338pub struct TechnologyConfig {
9339    /// Enable technology-specific generation.
9340    #[serde(default)]
9341    pub enabled: bool,
9342
9343    /// Revenue model type.
9344    #[serde(default = "default_revenue_model")]
9345    pub revenue_model: String,
9346
9347    /// Subscription revenue percentage (for SaaS).
9348    #[serde(default = "default_subscription_pct")]
9349    pub subscription_revenue_pct: f64,
9350
9351    /// License revenue percentage.
9352    #[serde(default = "default_license_pct")]
9353    pub license_revenue_pct: f64,
9354
9355    /// Services revenue percentage.
9356    #[serde(default = "default_services_pct")]
9357    pub services_revenue_pct: f64,
9358
9359    /// R&D capitalization settings.
9360    #[serde(default)]
9361    pub rd_capitalization: RdCapitalizationConfig,
9362
9363    /// Technology anomaly injection rates.
9364    #[serde(default)]
9365    pub anomaly_rates: TechnologyAnomalyRates,
9366}
9367
9368fn default_revenue_model() -> String {
9369    "saas".to_string()
9370}
9371
9372fn default_subscription_pct() -> f64 {
9373    0.60
9374}
9375
9376fn default_license_pct() -> f64 {
9377    0.25
9378}
9379
9380fn default_services_pct() -> f64 {
9381    0.15
9382}
9383
9384impl Default for TechnologyConfig {
9385    fn default() -> Self {
9386        Self {
9387            enabled: false,
9388            revenue_model: default_revenue_model(),
9389            subscription_revenue_pct: default_subscription_pct(),
9390            license_revenue_pct: default_license_pct(),
9391            services_revenue_pct: default_services_pct(),
9392            rd_capitalization: RdCapitalizationConfig::default(),
9393            anomaly_rates: TechnologyAnomalyRates::default(),
9394        }
9395    }
9396}
9397
9398/// R&D capitalization configuration.
9399#[derive(Debug, Clone, Serialize, Deserialize)]
9400pub struct RdCapitalizationConfig {
9401    /// Enable R&D capitalization.
9402    #[serde(default = "default_true")]
9403    pub enabled: bool,
9404
9405    /// Capitalization rate (0.0-1.0).
9406    #[serde(default = "default_cap_rate")]
9407    pub capitalization_rate: f64,
9408
9409    /// Useful life in years.
9410    #[serde(default = "default_useful_life")]
9411    pub useful_life_years: u32,
9412}
9413
9414fn default_cap_rate() -> f64 {
9415    0.30
9416}
9417
9418fn default_useful_life() -> u32 {
9419    3
9420}
9421
9422impl Default for RdCapitalizationConfig {
9423    fn default() -> Self {
9424        Self {
9425            enabled: true,
9426            capitalization_rate: default_cap_rate(),
9427            useful_life_years: default_useful_life(),
9428        }
9429    }
9430}
9431
9432/// Technology anomaly injection rates.
9433#[derive(Debug, Clone, Serialize, Deserialize)]
9434pub struct TechnologyAnomalyRates {
9435    /// Premature revenue recognition rate.
9436    #[serde(default = "default_premature_rev_rate")]
9437    pub premature_revenue: f64,
9438
9439    /// Side letter abuse rate.
9440    #[serde(default = "default_side_letter_rate")]
9441    pub side_letter_abuse: f64,
9442
9443    /// Channel stuffing rate.
9444    #[serde(default = "default_channel_stuffing_rate")]
9445    pub channel_stuffing: f64,
9446
9447    /// Improper capitalization rate.
9448    #[serde(default = "default_improper_cap_rate")]
9449    pub improper_capitalization: f64,
9450}
9451
9452fn default_premature_rev_rate() -> f64 {
9453    0.015
9454}
9455
9456fn default_side_letter_rate() -> f64 {
9457    0.008
9458}
9459
9460fn default_channel_stuffing_rate() -> f64 {
9461    0.01
9462}
9463
9464fn default_improper_cap_rate() -> f64 {
9465    0.012
9466}
9467
9468impl Default for TechnologyAnomalyRates {
9469    fn default() -> Self {
9470        Self {
9471            premature_revenue: default_premature_rev_rate(),
9472            side_letter_abuse: default_side_letter_rate(),
9473            channel_stuffing: default_channel_stuffing_rate(),
9474            improper_capitalization: default_improper_cap_rate(),
9475        }
9476    }
9477}
9478
9479/// Financial services industry configuration.
9480#[derive(Debug, Clone, Serialize, Deserialize)]
9481pub struct FinancialServicesConfig {
9482    /// Enable financial services-specific generation.
9483    #[serde(default)]
9484    pub enabled: bool,
9485
9486    /// Financial institution type.
9487    #[serde(default = "default_fi_type")]
9488    pub institution_type: String,
9489
9490    /// Regulatory framework.
9491    #[serde(default = "default_fi_regulatory")]
9492    pub regulatory_framework: String,
9493
9494    /// Financial services anomaly injection rates.
9495    #[serde(default)]
9496    pub anomaly_rates: FinancialServicesAnomalyRates,
9497}
9498
9499fn default_fi_type() -> String {
9500    "commercial_bank".to_string()
9501}
9502
9503fn default_fi_regulatory() -> String {
9504    "us_banking".to_string()
9505}
9506
9507impl Default for FinancialServicesConfig {
9508    fn default() -> Self {
9509        Self {
9510            enabled: false,
9511            institution_type: default_fi_type(),
9512            regulatory_framework: default_fi_regulatory(),
9513            anomaly_rates: FinancialServicesAnomalyRates::default(),
9514        }
9515    }
9516}
9517
9518/// Financial services anomaly injection rates.
9519#[derive(Debug, Clone, Serialize, Deserialize)]
9520pub struct FinancialServicesAnomalyRates {
9521    /// Loan fraud rate.
9522    #[serde(default = "default_loan_fraud_rate")]
9523    pub loan_fraud: f64,
9524
9525    /// Trading fraud rate.
9526    #[serde(default = "default_trading_fraud_rate")]
9527    pub trading_fraud: f64,
9528
9529    /// Insurance fraud rate.
9530    #[serde(default = "default_insurance_fraud_rate")]
9531    pub insurance_fraud: f64,
9532
9533    /// Account manipulation rate.
9534    #[serde(default = "default_account_manip_rate")]
9535    pub account_manipulation: f64,
9536}
9537
9538fn default_loan_fraud_rate() -> f64 {
9539    0.01
9540}
9541
9542fn default_trading_fraud_rate() -> f64 {
9543    0.008
9544}
9545
9546fn default_insurance_fraud_rate() -> f64 {
9547    0.012
9548}
9549
9550fn default_account_manip_rate() -> f64 {
9551    0.005
9552}
9553
9554impl Default for FinancialServicesAnomalyRates {
9555    fn default() -> Self {
9556        Self {
9557            loan_fraud: default_loan_fraud_rate(),
9558            trading_fraud: default_trading_fraud_rate(),
9559            insurance_fraud: default_insurance_fraud_rate(),
9560            account_manipulation: default_account_manip_rate(),
9561        }
9562    }
9563}
9564
9565/// Professional services industry configuration.
9566#[derive(Debug, Clone, Serialize, Deserialize)]
9567pub struct ProfessionalServicesConfig {
9568    /// Enable professional services-specific generation.
9569    #[serde(default)]
9570    pub enabled: bool,
9571
9572    /// Firm type.
9573    #[serde(default = "default_firm_type")]
9574    pub firm_type: String,
9575
9576    /// Billing model.
9577    #[serde(default = "default_billing_model")]
9578    pub billing_model: String,
9579
9580    /// Average hourly rate.
9581    #[serde(default = "default_hourly_rate")]
9582    pub avg_hourly_rate: f64,
9583
9584    /// Trust account settings (for law firms).
9585    #[serde(default)]
9586    pub trust_accounting: TrustAccountingConfig,
9587
9588    /// Professional services anomaly injection rates.
9589    #[serde(default)]
9590    pub anomaly_rates: ProfessionalServicesAnomalyRates,
9591}
9592
9593fn default_firm_type() -> String {
9594    "consulting".to_string()
9595}
9596
9597fn default_billing_model() -> String {
9598    "time_and_materials".to_string()
9599}
9600
9601fn default_hourly_rate() -> f64 {
9602    250.0
9603}
9604
9605impl Default for ProfessionalServicesConfig {
9606    fn default() -> Self {
9607        Self {
9608            enabled: false,
9609            firm_type: default_firm_type(),
9610            billing_model: default_billing_model(),
9611            avg_hourly_rate: default_hourly_rate(),
9612            trust_accounting: TrustAccountingConfig::default(),
9613            anomaly_rates: ProfessionalServicesAnomalyRates::default(),
9614        }
9615    }
9616}
9617
9618/// Trust accounting configuration for law firms.
9619#[derive(Debug, Clone, Serialize, Deserialize)]
9620pub struct TrustAccountingConfig {
9621    /// Enable trust accounting.
9622    #[serde(default)]
9623    pub enabled: bool,
9624
9625    /// Require three-way reconciliation.
9626    #[serde(default = "default_true")]
9627    pub require_three_way_reconciliation: bool,
9628}
9629
9630impl Default for TrustAccountingConfig {
9631    fn default() -> Self {
9632        Self {
9633            enabled: false,
9634            require_three_way_reconciliation: true,
9635        }
9636    }
9637}
9638
9639/// Professional services anomaly injection rates.
9640#[derive(Debug, Clone, Serialize, Deserialize)]
9641pub struct ProfessionalServicesAnomalyRates {
9642    /// Time billing fraud rate.
9643    #[serde(default = "default_time_fraud_rate")]
9644    pub time_billing_fraud: f64,
9645
9646    /// Expense report fraud rate.
9647    #[serde(default = "default_expense_fraud_rate")]
9648    pub expense_fraud: f64,
9649
9650    /// Trust misappropriation rate.
9651    #[serde(default = "default_trust_misappropriation_rate")]
9652    pub trust_misappropriation: f64,
9653}
9654
9655fn default_time_fraud_rate() -> f64 {
9656    0.02
9657}
9658
9659fn default_expense_fraud_rate() -> f64 {
9660    0.015
9661}
9662
9663fn default_trust_misappropriation_rate() -> f64 {
9664    0.003
9665}
9666
9667impl Default for ProfessionalServicesAnomalyRates {
9668    fn default() -> Self {
9669        Self {
9670            time_billing_fraud: default_time_fraud_rate(),
9671            expense_fraud: default_expense_fraud_rate(),
9672            trust_misappropriation: default_trust_misappropriation_rate(),
9673        }
9674    }
9675}
9676
9677/// Fingerprint privacy configuration for extraction and synthesis.
9678///
9679/// Controls the privacy parameters used when extracting fingerprints
9680/// from sensitive data. Supports predefined levels or custom (epsilon, delta) tuples.
9681///
9682/// ```yaml
9683/// fingerprint_privacy:
9684///   level: custom
9685///   epsilon: 0.5
9686///   delta: 1.0e-5
9687///   k_anonymity: 10
9688///   composition_method: renyi_dp
9689/// ```
9690#[derive(Debug, Clone, Serialize, Deserialize)]
9691pub struct FingerprintPrivacyConfig {
9692    /// Privacy level preset. Use "custom" for user-specified epsilon/delta.
9693    #[serde(default)]
9694    pub level: String,
9695    /// Custom epsilon value (only used when level = "custom").
9696    #[serde(default = "default_epsilon")]
9697    pub epsilon: f64,
9698    /// Custom delta value for (epsilon, delta)-DP (only used with RDP/zCDP).
9699    #[serde(default = "default_delta")]
9700    pub delta: f64,
9701    /// K-anonymity threshold.
9702    #[serde(default = "default_k_anonymity")]
9703    pub k_anonymity: u32,
9704    /// Composition method: "naive", "advanced", "renyi_dp", "zcdp".
9705    #[serde(default)]
9706    pub composition_method: String,
9707}
9708
9709fn default_epsilon() -> f64 {
9710    1.0
9711}
9712
9713fn default_delta() -> f64 {
9714    1e-5
9715}
9716
9717fn default_k_anonymity() -> u32 {
9718    5
9719}
9720
9721impl Default for FingerprintPrivacyConfig {
9722    fn default() -> Self {
9723        Self {
9724            level: "standard".to_string(),
9725            epsilon: default_epsilon(),
9726            delta: default_delta(),
9727            k_anonymity: default_k_anonymity(),
9728            composition_method: "naive".to_string(),
9729        }
9730    }
9731}
9732
9733/// Quality gates configuration for pass/fail thresholds on generation runs.
9734///
9735/// ```yaml
9736/// quality_gates:
9737///   enabled: true
9738///   profile: strict  # strict, default, lenient, custom
9739///   fail_on_violation: true
9740///   custom_gates:
9741///     - name: benford_compliance
9742///       metric: benford_mad
9743///       threshold: 0.015
9744///       comparison: lte
9745/// ```
9746#[derive(Debug, Clone, Serialize, Deserialize)]
9747pub struct QualityGatesSchemaConfig {
9748    /// Enable quality gate evaluation.
9749    #[serde(default)]
9750    pub enabled: bool,
9751    /// Gate profile: "strict", "default", "lenient", or "custom".
9752    #[serde(default = "default_gate_profile_name")]
9753    pub profile: String,
9754    /// Whether to fail the generation on gate violations.
9755    #[serde(default)]
9756    pub fail_on_violation: bool,
9757    /// Custom gate definitions (used when profile = "custom").
9758    #[serde(default)]
9759    pub custom_gates: Vec<QualityGateEntry>,
9760}
9761
9762fn default_gate_profile_name() -> String {
9763    "default".to_string()
9764}
9765
9766impl Default for QualityGatesSchemaConfig {
9767    fn default() -> Self {
9768        Self {
9769            enabled: false,
9770            profile: default_gate_profile_name(),
9771            fail_on_violation: false,
9772            custom_gates: Vec::new(),
9773        }
9774    }
9775}
9776
9777/// A single quality gate entry in configuration.
9778#[derive(Debug, Clone, Serialize, Deserialize)]
9779pub struct QualityGateEntry {
9780    /// Gate name.
9781    pub name: String,
9782    /// Metric to check: benford_mad, balance_coherence, document_chain_integrity,
9783    /// correlation_preservation, temporal_consistency, privacy_mia_auc,
9784    /// completion_rate, duplicate_rate, referential_integrity, ic_match_rate.
9785    pub metric: String,
9786    /// Threshold value.
9787    pub threshold: f64,
9788    /// Upper threshold for "between" comparison.
9789    #[serde(default)]
9790    pub upper_threshold: Option<f64>,
9791    /// Comparison operator: "gte", "lte", "eq", "between".
9792    #[serde(default = "default_gate_comparison")]
9793    pub comparison: String,
9794}
9795
9796fn default_gate_comparison() -> String {
9797    "gte".to_string()
9798}
9799
9800/// Compliance configuration for regulatory requirements.
9801///
9802/// ```yaml
9803/// compliance:
9804///   content_marking:
9805///     enabled: true
9806///     format: embedded  # embedded, sidecar, both
9807///   article10_report: true
9808/// ```
9809#[derive(Debug, Clone, Default, Serialize, Deserialize)]
9810pub struct ComplianceSchemaConfig {
9811    /// Synthetic content marking configuration (EU AI Act Article 50).
9812    #[serde(default)]
9813    pub content_marking: ContentMarkingSchemaConfig,
9814    /// Generate Article 10 data governance report.
9815    #[serde(default)]
9816    pub article10_report: bool,
9817    /// Certificate configuration for proving DP guarantees.
9818    #[serde(default)]
9819    pub certificates: CertificateSchemaConfig,
9820}
9821
9822/// Configuration for synthetic data certificates.
9823#[derive(Debug, Clone, Default, Serialize, Deserialize)]
9824pub struct CertificateSchemaConfig {
9825    /// Whether certificate generation is enabled.
9826    #[serde(default)]
9827    pub enabled: bool,
9828    /// Environment variable name for the signing key.
9829    #[serde(default)]
9830    pub signing_key_env: Option<String>,
9831    /// Whether to include quality metrics in the certificate.
9832    #[serde(default)]
9833    pub include_quality_metrics: bool,
9834}
9835
9836/// Content marking configuration for synthetic data output.
9837#[derive(Debug, Clone, Serialize, Deserialize)]
9838pub struct ContentMarkingSchemaConfig {
9839    /// Whether content marking is enabled.
9840    #[serde(default = "default_true")]
9841    pub enabled: bool,
9842    /// Marking format: "embedded", "sidecar", or "both".
9843    #[serde(default = "default_marking_format")]
9844    pub format: String,
9845}
9846
9847fn default_marking_format() -> String {
9848    "embedded".to_string()
9849}
9850
9851impl Default for ContentMarkingSchemaConfig {
9852    fn default() -> Self {
9853        Self {
9854            enabled: true,
9855            format: default_marking_format(),
9856        }
9857    }
9858}
9859
9860/// Webhook notification configuration.
9861#[derive(Debug, Clone, Default, Serialize, Deserialize)]
9862pub struct WebhookSchemaConfig {
9863    /// Whether webhooks are enabled.
9864    #[serde(default)]
9865    pub enabled: bool,
9866    /// Webhook endpoint configurations.
9867    #[serde(default)]
9868    pub endpoints: Vec<WebhookEndpointConfig>,
9869}
9870
9871/// Configuration for a single webhook endpoint.
9872#[derive(Debug, Clone, Serialize, Deserialize)]
9873pub struct WebhookEndpointConfig {
9874    /// Target URL for the webhook.
9875    pub url: String,
9876    /// Event types this endpoint subscribes to.
9877    #[serde(default)]
9878    pub events: Vec<String>,
9879    /// Optional secret for HMAC-SHA256 signature.
9880    #[serde(default)]
9881    pub secret: Option<String>,
9882    /// Maximum retry attempts (default: 3).
9883    #[serde(default = "default_webhook_retries")]
9884    pub max_retries: u32,
9885    /// Timeout in seconds (default: 10).
9886    #[serde(default = "default_webhook_timeout")]
9887    pub timeout_secs: u64,
9888}
9889
9890fn default_webhook_retries() -> u32 {
9891    3
9892}
9893fn default_webhook_timeout() -> u64 {
9894    10
9895}
9896
9897#[cfg(test)]
9898#[allow(clippy::unwrap_used)]
9899mod tests {
9900    use super::*;
9901    use crate::presets::demo_preset;
9902
9903    // ==========================================================================
9904    // Serialization/Deserialization Tests
9905    // ==========================================================================
9906
9907    #[test]
9908    fn test_config_yaml_roundtrip() {
9909        let config = demo_preset();
9910        let yaml = serde_yaml::to_string(&config).expect("Failed to serialize to YAML");
9911        let deserialized: GeneratorConfig =
9912            serde_yaml::from_str(&yaml).expect("Failed to deserialize from YAML");
9913
9914        assert_eq!(
9915            config.global.period_months,
9916            deserialized.global.period_months
9917        );
9918        assert_eq!(config.global.industry, deserialized.global.industry);
9919        assert_eq!(config.companies.len(), deserialized.companies.len());
9920        assert_eq!(config.companies[0].code, deserialized.companies[0].code);
9921    }
9922
9923    #[test]
9924    fn test_config_json_roundtrip() {
9925        // Create a config without infinity values (JSON can't serialize f64::INFINITY)
9926        let mut config = demo_preset();
9927        // Replace infinity with a large but finite value for JSON compatibility
9928        config.master_data.employees.approval_limits.executive = 1e12;
9929
9930        let json = serde_json::to_string(&config).expect("Failed to serialize to JSON");
9931        let deserialized: GeneratorConfig =
9932            serde_json::from_str(&json).expect("Failed to deserialize from JSON");
9933
9934        assert_eq!(
9935            config.global.period_months,
9936            deserialized.global.period_months
9937        );
9938        assert_eq!(config.global.industry, deserialized.global.industry);
9939        assert_eq!(config.companies.len(), deserialized.companies.len());
9940    }
9941
9942    #[test]
9943    fn test_transaction_volume_serialization() {
9944        // Test various transaction volumes serialize correctly
9945        let volumes = vec![
9946            (TransactionVolume::TenK, "ten_k"),
9947            (TransactionVolume::HundredK, "hundred_k"),
9948            (TransactionVolume::OneM, "one_m"),
9949            (TransactionVolume::TenM, "ten_m"),
9950            (TransactionVolume::HundredM, "hundred_m"),
9951        ];
9952
9953        for (volume, expected_key) in volumes {
9954            let json = serde_json::to_string(&volume).expect("Failed to serialize");
9955            assert!(
9956                json.contains(expected_key),
9957                "Expected {} in JSON: {}",
9958                expected_key,
9959                json
9960            );
9961        }
9962    }
9963
9964    #[test]
9965    fn test_transaction_volume_custom_serialization() {
9966        let volume = TransactionVolume::Custom(12345);
9967        let json = serde_json::to_string(&volume).expect("Failed to serialize");
9968        let deserialized: TransactionVolume =
9969            serde_json::from_str(&json).expect("Failed to deserialize");
9970        assert_eq!(deserialized.count(), 12345);
9971    }
9972
9973    #[test]
9974    fn test_output_mode_serialization() {
9975        let modes = vec![
9976            OutputMode::Streaming,
9977            OutputMode::FlatFile,
9978            OutputMode::Both,
9979        ];
9980
9981        for mode in modes {
9982            let json = serde_json::to_string(&mode).expect("Failed to serialize");
9983            let deserialized: OutputMode =
9984                serde_json::from_str(&json).expect("Failed to deserialize");
9985            assert!(format!("{:?}", mode) == format!("{:?}", deserialized));
9986        }
9987    }
9988
9989    #[test]
9990    fn test_file_format_serialization() {
9991        let formats = vec![
9992            FileFormat::Csv,
9993            FileFormat::Parquet,
9994            FileFormat::Json,
9995            FileFormat::JsonLines,
9996        ];
9997
9998        for format in formats {
9999            let json = serde_json::to_string(&format).expect("Failed to serialize");
10000            let deserialized: FileFormat =
10001                serde_json::from_str(&json).expect("Failed to deserialize");
10002            assert!(format!("{:?}", format) == format!("{:?}", deserialized));
10003        }
10004    }
10005
10006    #[test]
10007    fn test_compression_algorithm_serialization() {
10008        let algos = vec![
10009            CompressionAlgorithm::Gzip,
10010            CompressionAlgorithm::Zstd,
10011            CompressionAlgorithm::Lz4,
10012            CompressionAlgorithm::Snappy,
10013        ];
10014
10015        for algo in algos {
10016            let json = serde_json::to_string(&algo).expect("Failed to serialize");
10017            let deserialized: CompressionAlgorithm =
10018                serde_json::from_str(&json).expect("Failed to deserialize");
10019            assert!(format!("{:?}", algo) == format!("{:?}", deserialized));
10020        }
10021    }
10022
10023    #[test]
10024    fn test_transfer_pricing_method_serialization() {
10025        let methods = vec![
10026            TransferPricingMethod::CostPlus,
10027            TransferPricingMethod::ComparableUncontrolled,
10028            TransferPricingMethod::ResalePrice,
10029            TransferPricingMethod::TransactionalNetMargin,
10030            TransferPricingMethod::ProfitSplit,
10031        ];
10032
10033        for method in methods {
10034            let json = serde_json::to_string(&method).expect("Failed to serialize");
10035            let deserialized: TransferPricingMethod =
10036                serde_json::from_str(&json).expect("Failed to deserialize");
10037            assert!(format!("{:?}", method) == format!("{:?}", deserialized));
10038        }
10039    }
10040
10041    #[test]
10042    fn test_benford_exemption_serialization() {
10043        let exemptions = vec![
10044            BenfordExemption::Recurring,
10045            BenfordExemption::Payroll,
10046            BenfordExemption::FixedFees,
10047            BenfordExemption::RoundAmounts,
10048        ];
10049
10050        for exemption in exemptions {
10051            let json = serde_json::to_string(&exemption).expect("Failed to serialize");
10052            let deserialized: BenfordExemption =
10053                serde_json::from_str(&json).expect("Failed to deserialize");
10054            assert!(format!("{:?}", exemption) == format!("{:?}", deserialized));
10055        }
10056    }
10057
10058    // ==========================================================================
10059    // Default Value Tests
10060    // ==========================================================================
10061
10062    #[test]
10063    fn test_global_config_defaults() {
10064        let yaml = r#"
10065            industry: manufacturing
10066            start_date: "2024-01-01"
10067            period_months: 6
10068        "#;
10069        let config: GlobalConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10070        assert_eq!(config.group_currency, "USD");
10071        assert!(config.parallel);
10072        assert_eq!(config.worker_threads, 0);
10073        assert_eq!(config.memory_limit_mb, 0);
10074    }
10075
10076    #[test]
10077    fn test_fraud_config_defaults() {
10078        let config = FraudConfig::default();
10079        assert!(!config.enabled);
10080        assert_eq!(config.fraud_rate, 0.005);
10081        assert!(!config.clustering_enabled);
10082    }
10083
10084    #[test]
10085    fn test_internal_controls_config_defaults() {
10086        let config = InternalControlsConfig::default();
10087        assert!(!config.enabled);
10088        assert_eq!(config.exception_rate, 0.02);
10089        assert_eq!(config.sod_violation_rate, 0.01);
10090        assert!(config.export_control_master_data);
10091        assert_eq!(config.sox_materiality_threshold, 10000.0);
10092        // COSO fields
10093        assert!(config.coso_enabled);
10094        assert!(!config.include_entity_level_controls);
10095        assert_eq!(config.target_maturity_level, "mixed");
10096    }
10097
10098    #[test]
10099    fn test_output_config_defaults() {
10100        let config = OutputConfig::default();
10101        assert!(matches!(config.mode, OutputMode::FlatFile));
10102        assert_eq!(config.formats, vec![FileFormat::Parquet]);
10103        assert!(config.compression.enabled);
10104        assert!(matches!(
10105            config.compression.algorithm,
10106            CompressionAlgorithm::Zstd
10107        ));
10108        assert!(config.include_acdoca);
10109        assert!(!config.include_bseg);
10110        assert!(config.partition_by_period);
10111        assert!(!config.partition_by_company);
10112    }
10113
10114    #[test]
10115    fn test_approval_config_defaults() {
10116        let config = ApprovalConfig::default();
10117        assert!(!config.enabled);
10118        assert_eq!(config.auto_approve_threshold, 1000.0);
10119        assert_eq!(config.rejection_rate, 0.02);
10120        assert_eq!(config.revision_rate, 0.05);
10121        assert_eq!(config.average_approval_delay_hours, 4.0);
10122        assert_eq!(config.thresholds.len(), 4);
10123    }
10124
10125    #[test]
10126    fn test_p2p_flow_config_defaults() {
10127        let config = P2PFlowConfig::default();
10128        assert!(config.enabled);
10129        assert_eq!(config.three_way_match_rate, 0.95);
10130        assert_eq!(config.partial_delivery_rate, 0.15);
10131        assert_eq!(config.average_po_to_gr_days, 14);
10132    }
10133
10134    #[test]
10135    fn test_o2c_flow_config_defaults() {
10136        let config = O2CFlowConfig::default();
10137        assert!(config.enabled);
10138        assert_eq!(config.credit_check_failure_rate, 0.02);
10139        assert_eq!(config.return_rate, 0.03);
10140        assert_eq!(config.bad_debt_rate, 0.01);
10141    }
10142
10143    #[test]
10144    fn test_balance_config_defaults() {
10145        let config = BalanceConfig::default();
10146        assert!(!config.generate_opening_balances);
10147        assert!(config.generate_trial_balances);
10148        assert_eq!(config.target_gross_margin, 0.35);
10149        assert!(config.validate_balance_equation);
10150        assert!(config.reconcile_subledgers);
10151    }
10152
10153    // ==========================================================================
10154    // Partial Config Deserialization Tests
10155    // ==========================================================================
10156
10157    #[test]
10158    fn test_partial_config_with_defaults() {
10159        // Minimal config that should use all defaults
10160        let yaml = r#"
10161            global:
10162              industry: manufacturing
10163              start_date: "2024-01-01"
10164              period_months: 3
10165            companies:
10166              - code: "TEST"
10167                name: "Test Company"
10168                currency: "USD"
10169                country: "US"
10170                annual_transaction_volume: ten_k
10171            chart_of_accounts:
10172              complexity: small
10173            output:
10174              output_directory: "./output"
10175        "#;
10176
10177        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10178        assert_eq!(config.global.period_months, 3);
10179        assert_eq!(config.companies.len(), 1);
10180        assert!(!config.fraud.enabled); // Default
10181        assert!(!config.internal_controls.enabled); // Default
10182    }
10183
10184    #[test]
10185    fn test_config_with_fraud_enabled() {
10186        let yaml = r#"
10187            global:
10188              industry: retail
10189              start_date: "2024-01-01"
10190              period_months: 12
10191            companies:
10192              - code: "RETAIL"
10193                name: "Retail Co"
10194                currency: "USD"
10195                country: "US"
10196                annual_transaction_volume: hundred_k
10197            chart_of_accounts:
10198              complexity: medium
10199            output:
10200              output_directory: "./output"
10201            fraud:
10202              enabled: true
10203              fraud_rate: 0.05
10204              clustering_enabled: true
10205        "#;
10206
10207        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10208        assert!(config.fraud.enabled);
10209        assert_eq!(config.fraud.fraud_rate, 0.05);
10210        assert!(config.fraud.clustering_enabled);
10211    }
10212
10213    #[test]
10214    fn test_config_with_multiple_companies() {
10215        let yaml = r#"
10216            global:
10217              industry: manufacturing
10218              start_date: "2024-01-01"
10219              period_months: 6
10220            companies:
10221              - code: "HQ"
10222                name: "Headquarters"
10223                currency: "USD"
10224                country: "US"
10225                annual_transaction_volume: hundred_k
10226                volume_weight: 1.0
10227              - code: "EU"
10228                name: "European Subsidiary"
10229                currency: "EUR"
10230                country: "DE"
10231                annual_transaction_volume: hundred_k
10232                volume_weight: 0.5
10233              - code: "APAC"
10234                name: "Asia Pacific"
10235                currency: "JPY"
10236                country: "JP"
10237                annual_transaction_volume: ten_k
10238                volume_weight: 0.3
10239            chart_of_accounts:
10240              complexity: large
10241            output:
10242              output_directory: "./output"
10243        "#;
10244
10245        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10246        assert_eq!(config.companies.len(), 3);
10247        assert_eq!(config.companies[0].code, "HQ");
10248        assert_eq!(config.companies[1].currency, "EUR");
10249        assert_eq!(config.companies[2].volume_weight, 0.3);
10250    }
10251
10252    #[test]
10253    fn test_intercompany_config() {
10254        let yaml = r#"
10255            enabled: true
10256            ic_transaction_rate: 0.20
10257            transfer_pricing_method: cost_plus
10258            markup_percent: 0.08
10259            generate_matched_pairs: true
10260            generate_eliminations: true
10261        "#;
10262
10263        let config: IntercompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10264        assert!(config.enabled);
10265        assert_eq!(config.ic_transaction_rate, 0.20);
10266        assert!(matches!(
10267            config.transfer_pricing_method,
10268            TransferPricingMethod::CostPlus
10269        ));
10270        assert_eq!(config.markup_percent, 0.08);
10271        assert!(config.generate_eliminations);
10272    }
10273
10274    // ==========================================================================
10275    // Company Config Tests
10276    // ==========================================================================
10277
10278    #[test]
10279    fn test_company_config_defaults() {
10280        let yaml = r#"
10281            code: "TEST"
10282            name: "Test Company"
10283            currency: "USD"
10284            country: "US"
10285            annual_transaction_volume: ten_k
10286        "#;
10287
10288        let config: CompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10289        assert_eq!(config.fiscal_year_variant, "K4"); // Default
10290        assert_eq!(config.volume_weight, 1.0); // Default
10291    }
10292
10293    // ==========================================================================
10294    // Chart of Accounts Config Tests
10295    // ==========================================================================
10296
10297    #[test]
10298    fn test_coa_config_defaults() {
10299        let yaml = r#"
10300            complexity: medium
10301        "#;
10302
10303        let config: ChartOfAccountsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10304        assert!(config.industry_specific); // Default true
10305        assert!(config.custom_accounts.is_none());
10306        assert_eq!(config.min_hierarchy_depth, 2); // Default
10307        assert_eq!(config.max_hierarchy_depth, 5); // Default
10308    }
10309
10310    // ==========================================================================
10311    // Accounting Standards Config Tests
10312    // ==========================================================================
10313
10314    #[test]
10315    fn test_accounting_standards_config_defaults() {
10316        let config = AccountingStandardsConfig::default();
10317        assert!(!config.enabled);
10318        assert!(matches!(
10319            config.framework,
10320            AccountingFrameworkConfig::UsGaap
10321        ));
10322        assert!(!config.revenue_recognition.enabled);
10323        assert!(!config.leases.enabled);
10324        assert!(!config.fair_value.enabled);
10325        assert!(!config.impairment.enabled);
10326        assert!(!config.generate_differences);
10327    }
10328
10329    #[test]
10330    fn test_accounting_standards_config_yaml() {
10331        let yaml = r#"
10332            enabled: true
10333            framework: ifrs
10334            revenue_recognition:
10335              enabled: true
10336              generate_contracts: true
10337              avg_obligations_per_contract: 2.5
10338              variable_consideration_rate: 0.20
10339              over_time_recognition_rate: 0.35
10340              contract_count: 150
10341            leases:
10342              enabled: true
10343              lease_count: 75
10344              finance_lease_percent: 0.25
10345              avg_lease_term_months: 48
10346            generate_differences: true
10347        "#;
10348
10349        let config: AccountingStandardsConfig =
10350            serde_yaml::from_str(yaml).expect("Failed to parse");
10351        assert!(config.enabled);
10352        assert!(matches!(config.framework, AccountingFrameworkConfig::Ifrs));
10353        assert!(config.revenue_recognition.enabled);
10354        assert_eq!(config.revenue_recognition.contract_count, 150);
10355        assert_eq!(config.revenue_recognition.avg_obligations_per_contract, 2.5);
10356        assert!(config.leases.enabled);
10357        assert_eq!(config.leases.lease_count, 75);
10358        assert_eq!(config.leases.finance_lease_percent, 0.25);
10359        assert!(config.generate_differences);
10360    }
10361
10362    #[test]
10363    fn test_accounting_framework_serialization() {
10364        let frameworks = [
10365            AccountingFrameworkConfig::UsGaap,
10366            AccountingFrameworkConfig::Ifrs,
10367            AccountingFrameworkConfig::DualReporting,
10368        ];
10369
10370        for framework in frameworks {
10371            let json = serde_json::to_string(&framework).expect("Failed to serialize");
10372            let deserialized: AccountingFrameworkConfig =
10373                serde_json::from_str(&json).expect("Failed to deserialize");
10374            assert!(format!("{:?}", framework) == format!("{:?}", deserialized));
10375        }
10376    }
10377
10378    #[test]
10379    fn test_revenue_recognition_config_defaults() {
10380        let config = RevenueRecognitionConfig::default();
10381        assert!(!config.enabled);
10382        assert!(config.generate_contracts);
10383        assert_eq!(config.avg_obligations_per_contract, 2.0);
10384        assert_eq!(config.variable_consideration_rate, 0.15);
10385        assert_eq!(config.over_time_recognition_rate, 0.30);
10386        assert_eq!(config.contract_count, 100);
10387    }
10388
10389    #[test]
10390    fn test_lease_accounting_config_defaults() {
10391        let config = LeaseAccountingConfig::default();
10392        assert!(!config.enabled);
10393        assert_eq!(config.lease_count, 50);
10394        assert_eq!(config.finance_lease_percent, 0.30);
10395        assert_eq!(config.avg_lease_term_months, 60);
10396        assert!(config.generate_amortization);
10397        assert_eq!(config.real_estate_percent, 0.40);
10398    }
10399
10400    #[test]
10401    fn test_fair_value_config_defaults() {
10402        let config = FairValueConfig::default();
10403        assert!(!config.enabled);
10404        assert_eq!(config.measurement_count, 25);
10405        assert_eq!(config.level1_percent, 0.40);
10406        assert_eq!(config.level2_percent, 0.35);
10407        assert_eq!(config.level3_percent, 0.25);
10408        assert!(!config.include_sensitivity_analysis);
10409    }
10410
10411    #[test]
10412    fn test_impairment_config_defaults() {
10413        let config = ImpairmentConfig::default();
10414        assert!(!config.enabled);
10415        assert_eq!(config.test_count, 15);
10416        assert_eq!(config.impairment_rate, 0.10);
10417        assert!(config.generate_projections);
10418        assert!(!config.include_goodwill);
10419    }
10420
10421    // ==========================================================================
10422    // Audit Standards Config Tests
10423    // ==========================================================================
10424
10425    #[test]
10426    fn test_audit_standards_config_defaults() {
10427        let config = AuditStandardsConfig::default();
10428        assert!(!config.enabled);
10429        assert!(!config.isa_compliance.enabled);
10430        assert!(!config.analytical_procedures.enabled);
10431        assert!(!config.confirmations.enabled);
10432        assert!(!config.opinion.enabled);
10433        assert!(!config.generate_audit_trail);
10434        assert!(!config.sox.enabled);
10435        assert!(!config.pcaob.enabled);
10436    }
10437
10438    #[test]
10439    fn test_audit_standards_config_yaml() {
10440        let yaml = r#"
10441            enabled: true
10442            isa_compliance:
10443              enabled: true
10444              compliance_level: comprehensive
10445              generate_isa_mappings: true
10446              include_pcaob: true
10447              framework: dual
10448            analytical_procedures:
10449              enabled: true
10450              procedures_per_account: 5
10451              variance_probability: 0.25
10452            confirmations:
10453              enabled: true
10454              confirmation_count: 75
10455              positive_response_rate: 0.90
10456              exception_rate: 0.08
10457            opinion:
10458              enabled: true
10459              generate_kam: true
10460              average_kam_count: 4
10461            sox:
10462              enabled: true
10463              generate_302_certifications: true
10464              generate_404_assessments: true
10465              material_weakness_rate: 0.03
10466            pcaob:
10467              enabled: true
10468              is_pcaob_audit: true
10469              include_icfr_opinion: true
10470            generate_audit_trail: true
10471        "#;
10472
10473        let config: AuditStandardsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10474        assert!(config.enabled);
10475        assert!(config.isa_compliance.enabled);
10476        assert_eq!(config.isa_compliance.compliance_level, "comprehensive");
10477        assert!(config.isa_compliance.include_pcaob);
10478        assert_eq!(config.isa_compliance.framework, "dual");
10479        assert!(config.analytical_procedures.enabled);
10480        assert_eq!(config.analytical_procedures.procedures_per_account, 5);
10481        assert!(config.confirmations.enabled);
10482        assert_eq!(config.confirmations.confirmation_count, 75);
10483        assert!(config.opinion.enabled);
10484        assert_eq!(config.opinion.average_kam_count, 4);
10485        assert!(config.sox.enabled);
10486        assert!(config.sox.generate_302_certifications);
10487        assert_eq!(config.sox.material_weakness_rate, 0.03);
10488        assert!(config.pcaob.enabled);
10489        assert!(config.pcaob.is_pcaob_audit);
10490        assert!(config.pcaob.include_icfr_opinion);
10491        assert!(config.generate_audit_trail);
10492    }
10493
10494    #[test]
10495    fn test_isa_compliance_config_defaults() {
10496        let config = IsaComplianceConfig::default();
10497        assert!(!config.enabled);
10498        assert_eq!(config.compliance_level, "standard");
10499        assert!(config.generate_isa_mappings);
10500        assert!(config.generate_coverage_summary);
10501        assert!(!config.include_pcaob);
10502        assert_eq!(config.framework, "isa");
10503    }
10504
10505    #[test]
10506    fn test_sox_compliance_config_defaults() {
10507        let config = SoxComplianceConfig::default();
10508        assert!(!config.enabled);
10509        assert!(config.generate_302_certifications);
10510        assert!(config.generate_404_assessments);
10511        assert_eq!(config.materiality_threshold, 10000.0);
10512        assert_eq!(config.material_weakness_rate, 0.02);
10513        assert_eq!(config.significant_deficiency_rate, 0.08);
10514    }
10515
10516    #[test]
10517    fn test_pcaob_config_defaults() {
10518        let config = PcaobConfig::default();
10519        assert!(!config.enabled);
10520        assert!(!config.is_pcaob_audit);
10521        assert!(config.generate_cam);
10522        assert!(!config.include_icfr_opinion);
10523        assert!(!config.generate_standard_mappings);
10524    }
10525
10526    #[test]
10527    fn test_config_with_standards_enabled() {
10528        let yaml = r#"
10529            global:
10530              industry: financial_services
10531              start_date: "2024-01-01"
10532              period_months: 12
10533            companies:
10534              - code: "BANK"
10535                name: "Test Bank"
10536                currency: "USD"
10537                country: "US"
10538                annual_transaction_volume: hundred_k
10539            chart_of_accounts:
10540              complexity: large
10541            output:
10542              output_directory: "./output"
10543            accounting_standards:
10544              enabled: true
10545              framework: us_gaap
10546              revenue_recognition:
10547                enabled: true
10548              leases:
10549                enabled: true
10550            audit_standards:
10551              enabled: true
10552              isa_compliance:
10553                enabled: true
10554              sox:
10555                enabled: true
10556        "#;
10557
10558        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10559        assert!(config.accounting_standards.enabled);
10560        assert!(matches!(
10561            config.accounting_standards.framework,
10562            AccountingFrameworkConfig::UsGaap
10563        ));
10564        assert!(config.accounting_standards.revenue_recognition.enabled);
10565        assert!(config.accounting_standards.leases.enabled);
10566        assert!(config.audit_standards.enabled);
10567        assert!(config.audit_standards.isa_compliance.enabled);
10568        assert!(config.audit_standards.sox.enabled);
10569    }
10570
10571    // ==========================================================================
10572    // Industry-Specific Config Tests
10573    // ==========================================================================
10574
10575    #[test]
10576    fn test_industry_specific_config_defaults() {
10577        let config = IndustrySpecificConfig::default();
10578        assert!(!config.enabled);
10579        assert!(!config.manufacturing.enabled);
10580        assert!(!config.retail.enabled);
10581        assert!(!config.healthcare.enabled);
10582        assert!(!config.technology.enabled);
10583        assert!(!config.financial_services.enabled);
10584        assert!(!config.professional_services.enabled);
10585    }
10586
10587    #[test]
10588    fn test_manufacturing_config_defaults() {
10589        let config = ManufacturingConfig::default();
10590        assert!(!config.enabled);
10591        assert_eq!(config.bom_depth, 4);
10592        assert!(!config.just_in_time);
10593        assert_eq!(config.supplier_tiers, 2);
10594        assert_eq!(config.target_yield_rate, 0.97);
10595        assert_eq!(config.scrap_alert_threshold, 0.03);
10596    }
10597
10598    #[test]
10599    fn test_retail_config_defaults() {
10600        let config = RetailConfig::default();
10601        assert!(!config.enabled);
10602        assert_eq!(config.avg_daily_transactions, 500);
10603        assert!(config.loss_prevention);
10604        assert_eq!(config.shrinkage_rate, 0.015);
10605    }
10606
10607    #[test]
10608    fn test_healthcare_config_defaults() {
10609        let config = HealthcareConfig::default();
10610        assert!(!config.enabled);
10611        assert_eq!(config.facility_type, "hospital");
10612        assert_eq!(config.avg_daily_encounters, 150);
10613        assert!(config.compliance.hipaa);
10614        assert!(config.compliance.stark_law);
10615        assert!(config.coding_systems.icd10);
10616        assert!(config.coding_systems.cpt);
10617    }
10618
10619    #[test]
10620    fn test_technology_config_defaults() {
10621        let config = TechnologyConfig::default();
10622        assert!(!config.enabled);
10623        assert_eq!(config.revenue_model, "saas");
10624        assert_eq!(config.subscription_revenue_pct, 0.60);
10625        assert!(config.rd_capitalization.enabled);
10626    }
10627
10628    #[test]
10629    fn test_config_with_industry_specific() {
10630        let yaml = r#"
10631            global:
10632              industry: healthcare
10633              start_date: "2024-01-01"
10634              period_months: 12
10635            companies:
10636              - code: "HOSP"
10637                name: "Test Hospital"
10638                currency: "USD"
10639                country: "US"
10640                annual_transaction_volume: hundred_k
10641            chart_of_accounts:
10642              complexity: medium
10643            output:
10644              output_directory: "./output"
10645            industry_specific:
10646              enabled: true
10647              healthcare:
10648                enabled: true
10649                facility_type: hospital
10650                payer_mix:
10651                  medicare: 0.45
10652                  medicaid: 0.15
10653                  commercial: 0.35
10654                  self_pay: 0.05
10655                coding_systems:
10656                  icd10: true
10657                  cpt: true
10658                  drg: true
10659                compliance:
10660                  hipaa: true
10661                  stark_law: true
10662                anomaly_rates:
10663                  upcoding: 0.03
10664                  unbundling: 0.02
10665        "#;
10666
10667        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10668        assert!(config.industry_specific.enabled);
10669        assert!(config.industry_specific.healthcare.enabled);
10670        assert_eq!(
10671            config.industry_specific.healthcare.facility_type,
10672            "hospital"
10673        );
10674        assert_eq!(config.industry_specific.healthcare.payer_mix.medicare, 0.45);
10675        assert_eq!(config.industry_specific.healthcare.payer_mix.self_pay, 0.05);
10676        assert!(config.industry_specific.healthcare.coding_systems.icd10);
10677        assert!(config.industry_specific.healthcare.compliance.hipaa);
10678        assert_eq!(
10679            config.industry_specific.healthcare.anomaly_rates.upcoding,
10680            0.03
10681        );
10682    }
10683
10684    #[test]
10685    fn test_config_with_manufacturing_specific() {
10686        let yaml = r#"
10687            global:
10688              industry: manufacturing
10689              start_date: "2024-01-01"
10690              period_months: 12
10691            companies:
10692              - code: "MFG"
10693                name: "Test Manufacturing"
10694                currency: "USD"
10695                country: "US"
10696                annual_transaction_volume: hundred_k
10697            chart_of_accounts:
10698              complexity: medium
10699            output:
10700              output_directory: "./output"
10701            industry_specific:
10702              enabled: true
10703              manufacturing:
10704                enabled: true
10705                bom_depth: 5
10706                just_in_time: true
10707                supplier_tiers: 3
10708                target_yield_rate: 0.98
10709                anomaly_rates:
10710                  yield_manipulation: 0.02
10711                  phantom_production: 0.01
10712        "#;
10713
10714        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10715        assert!(config.industry_specific.enabled);
10716        assert!(config.industry_specific.manufacturing.enabled);
10717        assert_eq!(config.industry_specific.manufacturing.bom_depth, 5);
10718        assert!(config.industry_specific.manufacturing.just_in_time);
10719        assert_eq!(config.industry_specific.manufacturing.supplier_tiers, 3);
10720        assert_eq!(
10721            config.industry_specific.manufacturing.target_yield_rate,
10722            0.98
10723        );
10724        assert_eq!(
10725            config
10726                .industry_specific
10727                .manufacturing
10728                .anomaly_rates
10729                .yield_manipulation,
10730            0.02
10731        );
10732    }
10733}