Skip to main content

datasynth_config/
schema.rs

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