use crate::lib::error::{AptOstreeError, AptOstreeResult};
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use uuid::Uuid;


/// Transaction types for different operations
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum TransactionType {
    PkgChange,      // Package installation/removal
    Deploy,         // Deployment operations
    Rebase,         // System rebase operations
    Upgrade,        // System upgrade operations
    Rollback,       // Rollback operations
    Kargs,          // Kernel argument changes
    Initramfs,      // Initramfs modifications
    Override,       // Package override changes
    UsrOverlay,     // User overlay operations
    ApplyLive,      // Live deployment changes
    Finalize,       // Deployment finalization
    Cleanup,        // Cleanup operations
    Reload,         // Configuration reload
    Reset,          // Reset operations
    RefreshMd,      // Metadata refresh
    Compose,        // Tree composition
    Container,      // Container operations
    Experimental,   // Experimental features
}

/// Upgrade-specific transaction data
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpgradeTransaction {
    pub packages_to_install: Vec<String>,
    pub packages_to_remove: Vec<String>,
    pub allow_downgrade: bool,
    pub require_signatures: bool,
    pub reboot_after: bool,
    pub preview_mode: bool,
    pub cache_only: bool,
    pub download_only: bool,
}

impl Default for UpgradeTransaction {
    fn default() -> Self {
        Self {
            packages_to_install: Vec::new(),
            packages_to_remove: Vec::new(),
            allow_downgrade: false,
            require_signatures: true,
            reboot_after: false,
            preview_mode: false,
            cache_only: false,
            download_only: false,
        }
    }
}

/// Transaction states throughout the lifecycle
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub enum TransactionState {
    Initialized,    // Transaction created
    Preparing,      // Preparation phase
    Ready,          // Ready for execution
    Running,        // Currently executing
    Paused,         // Paused for user input
    Completed,      // Successfully completed
    Failed,         // Execution failed
    Cancelled,      // User cancelled
    RollingBack,    // Rolling back changes
    RolledBack,     // Successfully rolled back
}

/// Transaction step information for detailed progress tracking
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionStep {
    pub id: String,
    pub name: String,
    pub description: String,
    pub status: StepStatus,
    pub progress: f64,
    pub started_at: Option<DateTime<Utc>>,
    pub completed_at: Option<DateTime<Utc>>,
    pub error: Option<String>,
    pub metadata: HashMap<String, String>,
}

/// Step status for detailed progress tracking
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum StepStatus {
    Pending,
    Running,
    Completed,
    Failed,
    Skipped,
}

/// Transaction priority levels
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd)]
pub enum TransactionPriority {
    Low = 1,
    Normal = 2,
    High = 3,
    Critical = 4,
}

/// Parameters for creating a transaction with steps
#[derive(Debug, Clone)]
pub struct TransactionCreationParams {
    pub transaction_type: TransactionType,
    pub user_id: u32,
    pub session_id: String,
    pub title: String,
    pub description: String,
    pub steps: Vec<TransactionStep>,
    pub priority: TransactionPriority,
}

/// Transaction result information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionResult {
    pub success: bool,
    pub message: String,
    pub details: Option<String>,
    pub rollback_required: bool,
    pub steps_completed: usize,
    pub steps_total: usize,
    pub warnings: Vec<String>,
}

/// Transaction object representing a single operation
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Transaction {
    pub id: String,
    pub transaction_type: TransactionType,
    pub user_id: u32,
    pub session_id: String,
    pub title: String,
    pub description: String,
    pub state: TransactionState,
    pub created_at: DateTime<Utc>,
    pub started_at: Option<DateTime<Utc>>,
    pub completed_at: Option<DateTime<Utc>>,
    pub progress: f64, // 0.0 to 1.0
    pub result: Option<TransactionResult>,
    pub metadata: HashMap<String, String>,
    pub upgrade_data: Option<UpgradeTransaction>,
    pub steps: Vec<TransactionStep>,
    pub dependencies: Vec<String>,
    pub priority: TransactionPriority,
    pub estimated_duration: Option<u64>, // in seconds
    pub actual_duration: Option<u64>, // in seconds
}

impl Transaction {
    /// Create a new transaction
    pub fn new(
        id: String,
        transaction_type: TransactionType,
        user_id: u32,
        session_id: String,
        title: String,
        description: String,
        created_at: DateTime<Utc>,
    ) -> Self {
        Self {
            id,
            transaction_type,
            user_id,
            session_id,
            title,
            description,
            state: TransactionState::Initialized,
            created_at,
            started_at: None,
            completed_at: None,
            progress: 0.0,
            result: None,
            metadata: HashMap::new(),
            upgrade_data: None,
            steps: Vec::new(),
            dependencies: Vec::new(),
            priority: TransactionPriority::Normal,
            estimated_duration: None,
            actual_duration: None,
        }
    }
    
    /// Update transaction state
    pub fn update_state(&mut self, new_state: TransactionState) {
        self.state = new_state;
        match new_state {
            TransactionState::Running => {
                self.started_at = Some(Utc::now());
            }
            TransactionState::Completed | TransactionState::Failed | TransactionState::RolledBack => {
                self.completed_at = Some(Utc::now());
            }
            _ => {}
        }
    }
    
    /// Update progress
    pub fn update_progress(&mut self, progress: f64) {
        self.progress = progress.clamp(0.0, 1.0);
    }
    
    /// Set transaction result
    pub fn set_result(&mut self, result: TransactionResult) {
        self.result = Some(result);
    }
    
    /// Add metadata
    pub fn add_metadata(&mut self, key: String, value: String) {
        self.metadata.insert(key, value);
    }
    
    /// Add a transaction step
    pub fn add_step(&mut self, step: TransactionStep) {
        self.steps.push(step);
    }
    
    /// Update step status
    pub fn update_step_status(&mut self, step_id: &str, status: StepStatus) -> AptOstreeResult<()> {
        if let Some(step) = self.steps.iter_mut().find(|s| s.id == step_id) {
            step.status = status.clone();
            match status {
                StepStatus::Running => {
                    step.started_at = Some(Utc::now());
                }
                StepStatus::Completed | StepStatus::Failed => {
                    step.completed_at = Some(Utc::now());
                }
                _ => {}
            }
            Ok(())
        } else {
            Err(AptOstreeError::System(format!("Step {} not found", step_id)))
        }
    }
    
    /// Get step by ID
    pub fn get_step(&self, step_id: &str) -> Option<&TransactionStep> {
        self.steps.iter().find(|s| s.id == step_id)
    }
    
    /// Calculate overall progress from steps
    pub fn calculate_progress_from_steps(&mut self) {
        if self.steps.is_empty() {
            return;
        }
        
        let completed_steps = self.steps.iter()
            .filter(|s| s.status == StepStatus::Completed)
            .count();
        
        let total_steps = self.steps.len();
        self.progress = completed_steps as f64 / total_steps as f64;
    }
    
    /// Set transaction priority
    pub fn set_priority(&mut self, priority: TransactionPriority) {
        self.priority = priority;
    }
    
    /// Add dependency
    pub fn add_dependency(&mut self, transaction_id: String) {
        if !self.dependencies.contains(&transaction_id) {
            self.dependencies.push(transaction_id);
        }
    }
    
    /// Check if dependencies are satisfied
    pub fn dependencies_satisfied(&self, completed_transactions: &[String]) -> bool {
        self.dependencies.iter().all(|dep| completed_transactions.contains(dep))
    }
    
    /// Check if transaction is active
    pub fn is_active(&self) -> bool {
        matches!(
            self.state,
            TransactionState::Preparing | TransactionState::Ready | TransactionState::Running | TransactionState::Paused
        )
    }
    
    /// Check if transaction can be cancelled
    pub fn can_cancel(&self) -> bool {
        matches!(
            self.state,
            TransactionState::Preparing | TransactionState::Ready | TransactionState::Running | TransactionState::Paused
        )
    }
    
    /// Check if transaction can be rolled back
    pub fn can_rollback(&self) -> bool {
        matches!(
            self.state,
            TransactionState::Completed | TransactionState::Failed
        )
    }
}

/// Transaction manager for handling all transactions
#[allow(dead_code, clippy::new_without_default)]
pub struct TransactionManager {
    transactions: Arc<RwLock<HashMap<String, Transaction>>>,
}

impl TransactionManager {
    /// Create a new transaction manager
    pub fn new() -> Self {
        Self {
            transactions: Arc::new(RwLock::new(HashMap::new())),
        }
    }
}

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

impl TransactionManager {
    /// Create a new transaction
    pub async fn create_transaction(
        &self,
        transaction_type: TransactionType,
        user_id: u32,
        session_id: String,
        title: String,
        description: String,
    ) -> AptOstreeResult<String> {
        let transaction_id = Uuid::new_v4().to_string();
        
        let transaction = Transaction::new(
            transaction_id.clone(),
            transaction_type,
            user_id,
            session_id,
            title,
            description,
            Utc::now(),
        );
        
        // Store transaction
        self.transactions
            .write()
            .await
            .insert(transaction_id.clone(), transaction);
        
        Ok(transaction_id)
    }
    
    /// Get a transaction by ID
    pub async fn get_transaction(&self, transaction_id: &str) -> AptOstreeResult<Transaction> {
        let transactions = self.transactions.read().await;
        transactions
            .get(transaction_id)
            .cloned()
            .ok_or_else(|| AptOstreeError::System(format!("Transaction {} not found", transaction_id)))
    }
    
    /// Update a transaction
    pub async fn update_transaction(&self, transaction: &Transaction) -> AptOstreeResult<()> {
        let mut transactions = self.transactions.write().await;
        transactions.insert(transaction.id.clone(), transaction.clone());
        Ok(())
    }
    
    /// List all transactions
    pub async fn list_transactions(&self) -> AptOstreeResult<Vec<Transaction>> {
        let transactions = self.transactions.read().await;
        Ok(transactions.values().cloned().collect())
    }
    
    /// List active transactions
    pub async fn list_active_transactions(&self) -> AptOstreeResult<Vec<Transaction>> {
        let transactions = self.transactions.read().await;
        Ok(transactions
            .values()
            .filter(|t| t.is_active())
            .cloned()
            .collect())
    }
    
    /// Cancel a transaction
    pub async fn cancel_transaction(&self, transaction_id: &str) -> AptOstreeResult<()> {
        let mut transaction = self.get_transaction(transaction_id).await?;
        
        if !transaction.can_cancel() {
            return Err(AptOstreeError::System(format!(
                "Transaction {} cannot be cancelled in state {:?}",
                transaction_id, transaction.state
            )));
        }
        
        transaction.update_state(TransactionState::Cancelled);
        self.update_transaction(&transaction).await?;
        
        Ok(())
    }
    
    /// Rollback a transaction
    pub async fn rollback_transaction(&self, transaction_id: &str) -> AptOstreeResult<()> {
        let mut transaction = self.get_transaction(transaction_id).await?;
        
        if !transaction.can_rollback() {
            return Err(AptOstreeError::System(format!(
                "Transaction {} cannot be rolled back in state {:?}",
                transaction_id, transaction.state
            )));
        }
        
        transaction.update_state(TransactionState::RollingBack);
        self.update_transaction(&transaction).await?;
        
        // TODO: Implement actual rollback logic based on transaction type
        
        transaction.update_state(TransactionState::RolledBack);
        self.update_transaction(&transaction).await?;
        
        Ok(())
    }
    
    /// Create an upgrade transaction
    pub async fn create_upgrade_transaction(
        &self,
        user_id: u32,
        session_id: String,
        upgrade_data: UpgradeTransaction,
    ) -> AptOstreeResult<String> {
        let transaction_id = Uuid::new_v4().to_string();
        
        let mut transaction = Transaction::new(
            transaction_id.clone(),
            TransactionType::Upgrade,
            user_id,
            session_id,
            "System Upgrade".to_string(),
            "Upgrading system packages and OSTree tree".to_string(),
            Utc::now(),
        );
        
        transaction.upgrade_data = Some(upgrade_data);
        
        // Store transaction
        self.transactions
            .write()
            .await
            .insert(transaction_id.clone(), transaction);
        
        Ok(transaction_id)
    }
    
    /// Execute an upgrade transaction
    pub async fn execute_upgrade_transaction(&self, transaction_id: &str) -> AptOstreeResult<()> {
        let mut transaction = self.get_transaction(transaction_id).await?;
        
        if transaction.transaction_type != TransactionType::Upgrade {
            return Err(AptOstreeError::System(
                "Transaction is not an upgrade transaction".to_string()
            ));
        }
        
        // Extract upgrade data before borrowing
        let _packages_to_install = if let Some(ref upgrade_data) = transaction.upgrade_data {
            upgrade_data.packages_to_install.clone()
        } else {
            return Err(AptOstreeError::System(
                "Upgrade transaction data not found".to_string()
            ));
        };
        
        let _packages_to_remove = if let Some(ref upgrade_data) = transaction.upgrade_data {
            upgrade_data.packages_to_remove.len()
        } else {
            0
        };
        
        // Create upgrade steps if they don't exist
        if transaction.steps.is_empty() {
            let upgrade_steps = vec![
                TransactionStep {
                    id: "validate".to_string(),
                    name: "Validate System".to_string(),
                    description: "Check OSTree system status and APT availability".to_string(),
                    status: StepStatus::Pending,
                    progress: 0.0,
                    started_at: None,
                    completed_at: None,
                    error: None,
                    metadata: HashMap::new(),
                },
                TransactionStep {
                    id: "update_cache".to_string(),
                    name: "Update APT Cache".to_string(),
                    description: "Refresh package lists and metadata".to_string(),
                    status: StepStatus::Pending,
                    progress: 0.0,
                    started_at: None,
                    completed_at: None,
                    error: None,
                    metadata: HashMap::new(),
                },
                TransactionStep {
                    id: "check_updates".to_string(),
                    name: "Check for Updates".to_string(),
                    description: "Identify available system and package updates".to_string(),
                    status: StepStatus::Pending,
                    progress: 0.0,
                    started_at: None,
                    completed_at: None,
                    error: None,
                    metadata: HashMap::new(),
                },
                TransactionStep {
                    id: "download_packages".to_string(),
                    name: "Download Packages".to_string(),
                    description: "Download required package updates".to_string(),
                    status: StepStatus::Pending,
                    progress: 0.0,
                    started_at: None,
                    completed_at: None,
                    error: None,
                    metadata: HashMap::new(),
                },
                TransactionStep {
                    id: "apply_updates".to_string(),
                    name: "Apply Updates".to_string(),
                    description: "Apply package updates and system changes".to_string(),
                    status: StepStatus::Pending,
                    progress: 0.0,
                    started_at: None,
                    completed_at: None,
                    error: None,
                    metadata: HashMap::new(),
                },
                TransactionStep {
                    id: "finalize".to_string(),
                    name: "Finalize Upgrade".to_string(),
                    description: "Complete upgrade and prepare for reboot if needed".to_string(),
                    status: StepStatus::Pending,
                    progress: 0.0,
                    started_at: None,
                    completed_at: None,
                    error: None,
                    metadata: HashMap::new(),
                },
            ];
            
            for step in upgrade_steps {
                transaction.add_step(step);
            }
        }
        
        // Update transaction state
        transaction.update_state(TransactionState::Preparing);
        transaction.update_progress(0.1);
        self.update_transaction(&transaction).await?;
        
        // Execute upgrade steps
        let step_executor = |step: &TransactionStep| -> AptOstreeResult<bool> {
            match step.id.as_str() {
                "validate" => {
                    // TODO: Implement real validation logic
                    Ok(true)
                }
                "update_cache" => {
                    // TODO: Implement real APT cache update
                    Ok(true)
                }
                "check_updates" => {
                    // TODO: Implement real update checking
                    Ok(true)
                }
                "download_packages" => {
                    // TODO: Implement real package downloading
                    Ok(true)
                }
                "apply_updates" => {
                    // TODO: Implement real update application
                    Ok(true)
                }
                "finalize" => {
                    // TODO: Implement real upgrade finalization
                    Ok(true)
                }
                _ => Ok(true),
            }
        };
        
        // Execute the transaction with steps
        let result = self.execute_transaction_with_steps(transaction_id, step_executor).await?;
        
        // Update the transaction with the result
        let mut transaction = self.get_transaction(transaction_id).await?;
        transaction.result = Some(result);
        self.update_transaction(&transaction).await?;
        
        Ok(())
    }
    

    
    /// Clean up completed transactions
    pub async fn cleanup_completed_transactions(&self, max_age_hours: u64) -> AptOstreeResult<usize> {
        let mut transactions = self.transactions.write().await;
        let cutoff_time = Utc::now() - chrono::Duration::hours(max_age_hours as i64);
        
        let completed_ids: Vec<String> = transactions
            .iter()
            .filter(|(_, t)| {
                matches!(
                    t.state,
                    TransactionState::Completed | TransactionState::Failed | TransactionState::Cancelled | TransactionState::RolledBack
                ) && t.completed_at.is_some_and(|time| time < cutoff_time)
            })
            .map(|(id, _)| id.clone())
            .collect();
        
        let count = completed_ids.len();
        for id in completed_ids {
            transactions.remove(&id);
        }
        
        Ok(count)
    }
    
    /// Create a transaction with steps
    #[allow(clippy::too_many_arguments)]
    pub async fn create_transaction_with_steps(
        &self,
        params: TransactionCreationParams,
    ) -> AptOstreeResult<String> {
        let transaction_id = Uuid::new_v4().to_string();
        
        let mut transaction = Transaction::new(
            transaction_id.clone(),
            params.transaction_type,
            params.user_id,
            params.session_id,
            params.title,
            params.description,
            Utc::now(),
        );
        
        transaction.set_priority(params.priority);
        for step in params.steps {
            transaction.add_step(step);
        }
        
        // Store transaction
        self.transactions
            .write()
            .await
            .insert(transaction_id.clone(), transaction);
        
        Ok(transaction_id)
    }
    
    /// Execute a transaction with step-by-step progress
    pub async fn execute_transaction_with_steps(
        &self,
        transaction_id: &str,
        step_executor: impl Fn(&TransactionStep) -> AptOstreeResult<bool> + Send + Sync,
    ) -> AptOstreeResult<TransactionResult> {
        let mut transaction = self.get_transaction(transaction_id).await?;
        
        if !transaction.is_active() {
            return Err(AptOstreeError::System(
                "Transaction is not in an active state".to_string()
            ));
        }
        
        transaction.update_state(TransactionState::Running);
        self.update_transaction(&transaction).await?;
        
        let start_time = std::time::Instant::now();
        let mut step_results = Vec::new();
        
        // Execute each step and collect results
        for step in &transaction.steps {
            if step.status == StepStatus::Pending {
                let mut step_result = step.clone();
                step_result.status = StepStatus::Running;
                step_result.started_at = Some(Utc::now());
                
                // Execute the step
                let step_success = match step_executor(step) {
                    Ok(success) => success,
                    Err(e) => {
                        step_result.status = StepStatus::Failed;
                        step_result.error = Some(e.to_string());
                        false
                    }
                };
                
                if step_success {
                    step_result.status = StepStatus::Completed;
                    step_result.completed_at = Some(Utc::now());
                } else {
                    step_result.status = StepStatus::Failed;
                    if step_result.error.is_none() {
                        step_result.error = Some("Step execution failed".to_string());
                    }
                }
                
                // Check if any step failed
                if step_result.status == StepStatus::Failed {
                    let error_message = step_result.error.clone();
                    let step_name = step_result.name.clone();
                    
                    step_results.push(step_result);
                    
                    transaction.update_state(TransactionState::Failed);
                    transaction.actual_duration = Some(start_time.elapsed().as_secs());
                    
                    // Update steps in transaction
                    for (i, result) in step_results.iter().enumerate() {
                        if i < transaction.steps.len() {
                            transaction.steps[i] = result.clone();
                        }
                    }
                    
                    self.update_transaction(&transaction).await?;
                    
                    return Ok(TransactionResult {
                        success: false,
                        message: format!("Step '{}' failed", step_name),
                        details: error_message,
                        rollback_required: true,
                        steps_completed: step_results.iter().filter(|s| s.status == StepStatus::Completed).count(),
                        steps_total: transaction.steps.len(),
                        warnings: Vec::new(),
                    });
                }
                
            } else {
                step_results.push(step.clone());
            }
        }
        
        // Update transaction with step results
        transaction.steps = step_results;
        transaction.calculate_progress_from_steps();
        
        // All steps completed successfully
        transaction.update_state(TransactionState::Completed);
        transaction.actual_duration = Some(start_time.elapsed().as_secs());
        
        let result = TransactionResult {
            success: true,
            message: "Transaction completed successfully".to_string(),
            details: None,
            rollback_required: false,
            steps_completed: transaction.steps.len(),
            steps_total: transaction.steps.len(),
            warnings: Vec::new(),
        };
        
        transaction.result = Some(result.clone());
        self.update_transaction(&transaction).await?;
        
        Ok(result)
    }
    
    /// Get transactions by priority
    pub async fn get_transactions_by_priority(&self, priority: TransactionPriority) -> AptOstreeResult<Vec<Transaction>> {
        let transactions = self.transactions.read().await;
        Ok(transactions
            .values()
            .filter(|t| t.priority == priority)
            .cloned()
            .collect())
    }
    
    /// Get transactions with dependencies
    pub async fn get_transactions_with_dependencies(&self) -> AptOstreeResult<Vec<Transaction>> {
        let transactions = self.transactions.read().await;
        Ok(transactions
            .values()
            .filter(|t| !t.dependencies.is_empty())
            .cloned()
            .collect())
    }
    
    /// Validate transaction dependencies
    pub async fn validate_transaction_dependencies(&self, transaction_id: &str) -> AptOstreeResult<bool> {
        let transaction = self.get_transaction(transaction_id).await?;
        let completed_transactions = self.list_transactions().await?
            .into_iter()
            .filter(|t| t.state == TransactionState::Completed)
            .map(|t| t.id)
            .collect::<Vec<_>>();
        
        Ok(transaction.dependencies_satisfied(&completed_transactions))
    }
}
