//! Compliance Repository Trait
//!
//! Provides a clean abstraction for compliance data persistence, eliminating direct database
//! coupling from compliance reporting components.

use async_trait::async_trait;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
use thiserror::Error;

use rust_decimal::Decimal;

/// Errors that can occur in compliance repository operations
#[derive(Debug, Error)]
/// Errors that can occur in compliance repository operations
///
/// Comprehensive error types for all compliance repository operations
/// including database errors, serialization issues, and validation failures.
pub enum ComplianceRepositoryError {
    #[error("Database connection error: {0}")]
    /// Database connection failure
    Connection(String),
    #[error("Serialization error: {0}")]
    /// Data serialization/deserialization error
    Serialization(String),
    #[error("Query execution error: {0}")]
    /// Database query execution failure
    QueryExecution(String),
    #[error("Report generation error: {0}")]
    /// Report generation failure
    ReportGeneration(String),
    #[error("Schema initialization error: {0}")]
    /// Database schema initialization error
    SchemaInit(String),
    #[error("Audit trail error: {0}")]
    /// Audit trail operation error
    AuditTrail(String),
    #[error("Compliance validation error: {0}")]
    /// Compliance rule validation error
    Validation(String),
}

/// ComplianceRepositoryResult
pub type ComplianceRepositoryResult<T> = Result<T, ComplianceRepositoryError>;

/// Compliance event types for audit trails
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
/// Types of compliance events for audit trails
///
/// Classification of compliance events for regulatory reporting,
/// audit trails, and compliance monitoring.
pub enum ComplianceEventType {
    /// Order submission to market
    OrderSubmission,
    /// Order execution/fill
    OrderExecution,
    /// Order cancellation
    OrderCancellation,
    /// Risk management violation
    RiskViolation,
    /// Market data access
    MarketDataAccess,
    /// System configuration change
    ConfigurationChange,
    /// User-initiated action
    UserAction,
    /// System-generated event
    SystemEvent,
    /// Regulatory report generation
    RegulatoryReport,
    /// Audit query execution
    AuditQuery,
}

/// Compliance event for audit trails
#[derive(Debug, Clone, Serialize, Deserialize)]
/// Compliance event for audit trails
///
/// Comprehensive event record for compliance monitoring and regulatory reporting
/// including all relevant context, metadata, and regulatory information.
pub struct ComplianceEvent {
    /// Unique event identifier
    pub id: String,
    /// Type of compliance event
    pub event_type: ComplianceEventType,
    /// Event occurrence timestamp
    pub timestamp: DateTime<Utc>,
    /// User identifier if applicable
    pub user_id: Option<String>,
    /// Session identifier for tracking
    pub session_id: Option<String>,
    /// Related order identifier
    pub order_id: Option<String>,
    /// Trading symbol if applicable
    pub symbol: Option<String>,
    /// Human-readable event description
    pub description: String,
    /// Additional event metadata
    pub metadata: HashMap<String, serde_json::Value>,
    /// Event severity level
    pub severity: ComplianceSeverity,
    /// Regulatory context or framework
    pub regulatory_context: Option<String>,
}

/// Compliance severity levels
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
/// Compliance event severity levels
///
/// Hierarchical severity classification for compliance events
/// to prioritize response and regulatory reporting.
pub enum ComplianceSeverity {
    /// Informational event for audit trail
    Info,
    /// Warning condition requiring attention
    Warning,
    /// Critical issue requiring immediate response
    Critical,
    /// Regulatory violation requiring reporting
    Violation,
}

/// Parameters for compliance report generation
#[derive(Debug, Clone, Serialize, Deserialize)]
/// Parameters for compliance report generation
///
/// Configuration parameters for generating compliance reports
/// including time range, filters, and output format.
pub struct ReportParameters {
    /// Type of report to generate
    pub report_type: ReportType,
    /// Report start date and time
    pub start_date: DateTime<Utc>,
    /// Report end date and time
    pub end_date: DateTime<Utc>,
    /// Filter events by trading symbol
    pub symbol_filter: Option<String>,
    /// Filter events by user identifier
    pub user_filter: Option<String>,
    /// Filter events by severity level
    pub severity_filter: Option<ComplianceSeverity>,
    /// Include event metadata in report
    pub include_metadata: bool,
    /// Output format for the report
    pub format: ReportFormat,
}

/// Types of compliance reports
#[derive(Debug, Clone, Serialize, Deserialize)]
/// Types of compliance reports
///
/// Classification of compliance reports for different regulatory
/// requirements and business purposes.
pub enum ReportType {
    /// Order activity and execution report
    OrderActivity,
    /// Risk violations and alerts report
    RiskViolations,
    /// Market data usage and access report
    MarketDataUsage,
    /// User activity and access report
    UserActivity,
    /// System events and operations report
    SystemEvents,
    /// Regulatory filing and submission report
    RegulatoryFiling,
    /// Best execution analysis report
    BestExecution,
    /// Transaction reporting for regulators
    TransactionReporting,
}

/// Report output formats
#[derive(Debug, Clone, Serialize, Deserialize)]
/// Report output formats
///
/// Supported output formats for compliance reports
/// for different consumption and regulatory requirements.
pub enum ReportFormat {
    /// JSON format for API consumption
    Json,
    /// CSV format for data analysis
    Csv,
    /// XML format for regulatory systems
    Xml,
    /// PDF format for formal reports
    Pdf,
}

/// Generated compliance report
#[derive(Debug, Clone, Serialize, Deserialize)]
/// Generated compliance report
///
/// Complete compliance report with data, metadata, and summary statistics
/// for regulatory submission or internal analysis.
pub struct ComplianceReport {
    /// Unique report identifier
    pub id: String,
    /// Type of report generated
    pub report_type: ReportType,
    /// Report generation timestamp
    pub generated_at: DateTime<Utc>,
    /// Generation parameters used
    pub parameters: ReportParameters,
    /// Report data content
    pub data: serde_json::Value,
    /// Report summary statistics
    pub summary: ReportSummary,
    /// File path if saved to disk
    pub file_path: Option<String>,
}

/// Report summary statistics
#[derive(Debug, Clone, Serialize, Deserialize)]
/// Report summary statistics
///
/// Summary statistics and metrics for compliance reports
/// providing key insights and violation counts.
pub struct ReportSummary {
    /// Total number of events in report
    pub total_events: u64,
    /// Number of compliance violations
    pub violations: u64,
    /// Number of warning events
    pub warnings: u64,
    /// Number of unique trading symbols
    pub unique_symbols: u64,
    /// Number of unique users
    pub unique_users: u64,
    /// Human-readable time range description
    pub time_range: String,
}

/// Best execution analysis data
#[derive(Debug, Clone, Serialize, Deserialize)]
/// Best execution analysis data
///
/// Data structure for best execution analysis including execution details,
/// benchmark comparison, and venue information for regulatory compliance.
pub struct BestExecutionData {
    /// Trading symbol
    pub symbol: String,
    /// Order execution timestamp
    pub execution_time: DateTime<Utc>,
    /// Actual execution price
    pub execution_price: Decimal,
    /// Benchmark price for comparison
    pub benchmark_price: Decimal,
    /// Price slippage from benchmark
    pub slippage: Decimal,
    /// Execution venue identifier
    pub venue: String,
    /// Liquidity provision flag
    pub liquidity_flag: String,
    /// Order size executed
    pub order_size: Decimal,
}

/// Transaction reporting data for regulatory compliance
#[derive(Debug, Clone, Serialize, Deserialize)]
/// Transaction reporting data for regulatory compliance
///
/// Comprehensive transaction data required for regulatory transaction
/// reporting including all `MiFID` II and similar regulatory requirements.
pub struct TransactionReportData {
    /// Unique transaction identifier
    pub transaction_id: String,
    /// Financial instrument identifier
    pub instrument_id: String,
    /// Transaction execution timestamp
    pub execution_timestamp: DateTime<Utc>,
    /// Transaction execution price
    pub price: Decimal,
    /// Transaction quantity
    pub quantity: Decimal,
    /// Transaction side (buy/sell)
    pub side: String,
    /// Execution venue identifier
    pub venue: String,
    /// Counterparty identifier if known
    pub counterparty: Option<String>,
    /// Additional regulatory-specific data
    pub regulatory_data: HashMap<String, serde_json::Value>,
}

/// Repository trait for compliance data operations
#[async_trait]
/// Repository trait for compliance data operations
///
/// Async trait defining the interface for compliance data persistence,
/// querying, reporting, and management operations.
pub trait ComplianceRepository: Send + Sync {
    /// Initialize compliance database schema
    async fn initialize_schema(&self) -> ComplianceRepositoryResult<()>;

    /// Store a compliance event
    async fn store_event(&self, event: ComplianceEvent) -> ComplianceRepositoryResult<()>;

    /// Store multiple compliance events in a batch
    async fn store_events(&self, events: Vec<ComplianceEvent>) -> ComplianceRepositoryResult<()>;

    /// Query compliance events
    async fn query_events(
        &self,
        start_time: DateTime<Utc>,
        end_time: DateTime<Utc>,
        event_type: Option<ComplianceEventType>,
        severity: Option<ComplianceSeverity>,
        limit: Option<u32>,
    ) -> ComplianceRepositoryResult<Vec<ComplianceEvent>>;

    /// Generate compliance report
    async fn generate_report(
        &self,
        parameters: ReportParameters,
    ) -> ComplianceRepositoryResult<ComplianceReport>;

    /// Store best execution data
    async fn store_best_execution_data(
        &self,
        data: Vec<BestExecutionData>,
    ) -> ComplianceRepositoryResult<()>;

    /// Store transaction reporting data
    async fn store_transaction_data(
        &self,
        data: Vec<TransactionReportData>,
    ) -> ComplianceRepositoryResult<()>;

    /// Get compliance statistics for a time period
    async fn get_compliance_stats(
        &self,
        start_time: DateTime<Utc>,
        end_time: DateTime<Utc>,
    ) -> ComplianceRepositoryResult<ComplianceStats>;

    /// Archive old compliance data
    async fn archive_old_data(&self, retention_days: u32) -> ComplianceRepositoryResult<u64>;

    /// Verify data integrity
    async fn verify_data_integrity(&self) -> ComplianceRepositoryResult<IntegrityReport>;

    /// Health check
    async fn health_check(&self) -> ComplianceRepositoryResult<()>;
}

/// Compliance statistics
#[derive(Debug, Clone, Serialize, Deserialize)]
/// Compliance statistics
///
/// Statistical summary of compliance data including event counts,
/// violations, and storage metrics for operational monitoring.
pub struct ComplianceStats {
    /// Total number of compliance events
    pub total_events: u64,
    /// Event count breakdown by type
    pub events_by_type: HashMap<String, u64>,
    /// Total number of violations
    pub violations_count: u64,
    /// Total number of warnings
    pub warnings_count: u64,
    /// Number of unique users
    pub unique_users: u64,
    /// Number of unique symbols
    pub unique_symbols: u64,
    /// Storage size in bytes
    pub storage_size_bytes: u64,
}

/// Data integrity report
#[derive(Debug, Clone, Serialize, Deserialize)]
/// Data integrity verification report
///
/// Comprehensive report on compliance data integrity including
/// validation results, violation details, and recommendations for resolution.
pub struct IntegrityReport {
    /// Timestamp when integrity check was performed
    pub checked_at: DateTime<Utc>,
    /// Total number of records checked
    pub total_records: u64,
    /// List of integrity violations found
    pub integrity_violations: Vec<String>,
    /// Overall data integrity status
    pub is_valid: bool,
    /// Recommended actions to resolve issues
    pub recommendations: Vec<String>,
}

/// Mock implementation for testing
#[derive(Debug)]
pub struct MockComplianceRepository {
    events: Arc<tokio::sync::RwLock<Vec<ComplianceEvent>>>,
    reports: Arc<tokio::sync::RwLock<Vec<ComplianceReport>>>,
    should_fail: Arc<std::sync::atomic::AtomicBool>,
}

impl MockComplianceRepository {
    pub fn new() -> Self {
        Self {
            events: Arc::new(tokio::sync::RwLock::new(Vec::new())),
            reports: Arc::new(tokio::sync::RwLock::new(Vec::new())),
            should_fail: Arc::new(std::sync::atomic::AtomicBool::new(false)),
        }
    }

    pub fn set_should_fail(&self, should_fail: bool) {
        self.should_fail
            .store(should_fail, std::sync::atomic::Ordering::Relaxed);
    }

    pub async fn get_event_count(&self) -> usize {
        self.events.read().await.len()
    }

    pub async fn get_report_count(&self) -> usize {
        self.reports.read().await.len()
    }

    pub async fn clear_all(&self) {
        self.events.write().await.clear();
        self.reports.write().await.clear();
    }
}

#[async_trait]
impl ComplianceRepository for MockComplianceRepository {
    async fn initialize_schema(&self) -> ComplianceRepositoryResult<()> {
        if self.should_fail.load(std::sync::atomic::Ordering::Relaxed) {
            return Err(ComplianceRepositoryError::SchemaInit(
                "Mock failure".to_string(),
            ));
        }
        Ok(())
    }

    async fn store_event(&self, event: ComplianceEvent) -> ComplianceRepositoryResult<()> {
        if self.should_fail.load(std::sync::atomic::Ordering::Relaxed) {
            return Err(ComplianceRepositoryError::QueryExecution(
                "Mock failure".to_string(),
            ));
        }
        self.events.write().await.push(event);
        Ok(())
    }

    async fn store_events(&self, events: Vec<ComplianceEvent>) -> ComplianceRepositoryResult<()> {
        if self.should_fail.load(std::sync::atomic::Ordering::Relaxed) {
            return Err(ComplianceRepositoryError::QueryExecution(
                "Mock failure".to_string(),
            ));
        }
        self.events.write().await.extend(events);
        Ok(())
    }

    async fn query_events(
        &self,
        _start_time: DateTime<Utc>,
        _end_time: DateTime<Utc>,
        event_type: Option<ComplianceEventType>,
        severity: Option<ComplianceSeverity>,
        limit: Option<u32>,
    ) -> ComplianceRepositoryResult<Vec<ComplianceEvent>> {
        if self.should_fail.load(std::sync::atomic::Ordering::Relaxed) {
            return Err(ComplianceRepositoryError::QueryExecution(
                "Mock failure".to_string(),
            ));
        }

        let events = self.events.read().await;
        let mut filtered: Vec<ComplianceEvent> = events
            .iter()
            .filter(|event| {
                if let Some(ref et) = event_type {
                    if event.event_type != *et {
                        return false;
                    }
                }
                if let Some(ref sev) = severity {
                    if event.severity != *sev {
                        return false;
                    }
                }
                true
            })
            .cloned()
            .collect();

        if let Some(limit) = limit {
            filtered.truncate(limit as usize);
        }

        // Ok variant
        Ok(filtered)
    }

    async fn generate_report(
        &self,
        parameters: ReportParameters,
    ) -> ComplianceRepositoryResult<ComplianceReport> {
        if self.should_fail.load(std::sync::atomic::Ordering::Relaxed) {
            return Err(ComplianceRepositoryError::ReportGeneration(
                "Mock failure".to_string(),
            ));
        }

        let report = ComplianceReport {
            id: uuid::Uuid::new_v4().to_string(),
            report_type: parameters.report_type.clone(),
            generated_at: Utc::now(),
            parameters,
            data: serde_json::json!({"mock": "data"}),
            summary: ReportSummary {
                total_events: 100,
                violations: 5,
                warnings: 10,
                unique_symbols: 20,
                unique_users: 15,
                time_range: "Mock range".to_string(),
            },
            file_path: Some("/tmp/mock_report.json".to_string()),
        };

        self.reports.write().await.push(report.clone());
        // Ok variant
        Ok(report)
    }

    async fn store_best_execution_data(
        &self,
        _data: Vec<BestExecutionData>,
    ) -> ComplianceRepositoryResult<()> {
        if self.should_fail.load(std::sync::atomic::Ordering::Relaxed) {
            return Err(ComplianceRepositoryError::QueryExecution(
                "Mock failure".to_string(),
            ));
        }
        Ok(())
    }

    async fn store_transaction_data(
        &self,
        _data: Vec<TransactionReportData>,
    ) -> ComplianceRepositoryResult<()> {
        if self.should_fail.load(std::sync::atomic::Ordering::Relaxed) {
            return Err(ComplianceRepositoryError::QueryExecution(
                "Mock failure".to_string(),
            ));
        }
        Ok(())
    }

    async fn get_compliance_stats(
        &self,
        _start_time: DateTime<Utc>,
        _end_time: DateTime<Utc>,
    ) -> ComplianceRepositoryResult<ComplianceStats> {
        let event_count = self.events.read().await.len() as u64;
        Ok(ComplianceStats {
            total_events: event_count,
            events_by_type: HashMap::new(),
            violations_count: 5,
            warnings_count: 10,
            unique_users: 15,
            unique_symbols: 20,
            storage_size_bytes: event_count * 1024,
        })
    }

    async fn archive_old_data(&self, _retention_days: u32) -> ComplianceRepositoryResult<u64> {
        let count = self.events.read().await.len() as u64;
        self.events.write().await.clear();
        // Ok variant
        Ok(count)
    }

    async fn verify_data_integrity(&self) -> ComplianceRepositoryResult<IntegrityReport> {
        Ok(IntegrityReport {
            checked_at: Utc::now(),
            total_records: self.events.read().await.len() as u64,
            integrity_violations: Vec::new(),
            is_valid: true,
            recommendations: Vec::new(),
        })
    }

    async fn health_check(&self) -> ComplianceRepositoryResult<()> {
        if self.should_fail.load(std::sync::atomic::Ordering::Relaxed) {
            return Err(ComplianceRepositoryError::Connection(
                "Mock failure".to_string(),
            ));
        }
        Ok(())
    }
}

impl Default for MockComplianceRepository {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
#[allow(clippy::assertions_on_result_states)]
mod tests {
    use super::*;
    use chrono::Duration;

    #[tokio::test]
    async fn test_mock_compliance_repository() {
        let repo = MockComplianceRepository::new();

        // Test schema initialization
        assert!(repo.initialize_schema().await.is_ok());

        // Test health check
        assert!(repo.health_check().await.is_ok());

        // Test event storage
        let event = ComplianceEvent {
            id: uuid::Uuid::new_v4().to_string(),
            event_type: ComplianceEventType::OrderSubmission,
            timestamp: Utc::now(),
            user_id: Some("test_user".to_string()),
            session_id: None,
            order_id: Some("test_order".to_string()),
            symbol: Some("BTCUSD".to_string()),
            description: "Test order submission".to_string(),
            metadata: HashMap::new(),
            severity: ComplianceSeverity::Info,
            regulatory_context: None,
        };

        assert!(repo.store_event(event).await.is_ok());
        assert_eq!(repo.get_event_count().await, 1);
    }

    #[tokio::test]
    async fn test_report_generation() {
        let repo = MockComplianceRepository::new();

        let params = ReportParameters {
            report_type: ReportType::OrderActivity,
            start_date: Utc::now() - Duration::hours(24),
            end_date: Utc::now(),
            symbol_filter: None,
            user_filter: None,
            severity_filter: None,
            include_metadata: true,
            format: ReportFormat::Json,
        };

        let report = repo.generate_report(params).await.unwrap();
        assert!(!report.id.is_empty());
        assert_eq!(repo.get_report_count().await, 1);
    }
}
