use serde::{Serialize, Deserialize};
use std::fmt;
use std::time::SystemTime;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ActionType {
    Add,
    Delete,
    Modify,
    Transform,
    LayerChange,
    VisibilityChange,
    BlockOperation,
    DimensionOperation,
    TextOperation,
    GroupOperation,
    BlockEdit,
}

impl fmt::Display for ActionType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ActionType::Add => write!(f, "Add"),
            ActionType::Delete => write!(f, "Delete"),
            ActionType::Modify => write!(f, "Modify"),
            ActionType::Transform => write!(f, "Transform"),
            ActionType::LayerChange => write!(f, "LayerChange"),
            ActionType::VisibilityChange => write!(f, "VisibilityChange"),
            ActionType::BlockOperation => write!(f, "BlockOperation"),
            ActionType::DimensionOperation => write!(f, "DimensionOperation"),
            ActionType::TextOperation => write!(f, "TextOperation"),
            ActionType::GroupOperation => write!(f, "GroupOperation"),
            ActionType::BlockEdit => write!(f, "BlockEdit"),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HistoryAction {
    pub id: u64,
    pub action_type: ActionType,
    pub entity_ids: Vec<String>,
    pub before_data: Vec<u8>,
    pub after_data: Vec<u8>,
    pub description: String,
    pub timestamp: SystemTime,
    pub user: Option<String>,
}

impl HistoryAction {
    pub fn new(
        action_type: ActionType,
        entity_ids: Vec<String>,
        description: impl Into<String>,
    ) -> Self {
        Self {
            id: uuid::Uuid::new_v4().as_u128() as u64,
            action_type,
            entity_ids,
            before_data: Vec::new(),
            after_data: Vec::new(),
            description: description.into(),
            timestamp: SystemTime::now(),
            user: None,
        }
    }

    pub fn with_data(
        action_type: ActionType,
        entity_ids: Vec<String>,
        before_data: Vec<u8>,
        after_data: Vec<u8>,
        description: impl Into<String>,
    ) -> Self {
        Self {
            id: uuid::Uuid::new_v4().as_u128() as u64,
            action_type,
            entity_ids,
            before_data,
            after_data,
            description: description.into(),
            timestamp: SystemTime::now(),
            user: None,
        }
    }

    pub fn set_user(&mut self, user: impl Into<String>) {
        self.user = Some(user.into());
    }

    pub fn get_entity_count(&self) -> usize {
        self.entity_ids.len()
    }

    pub fn is_same_action(&self, other: &HistoryAction) -> bool {
        self.action_type == other.action_type
            && self.entity_ids == other.entity_ids
            && self.description == other.description
    }
}

impl fmt::Display for HistoryAction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "HistoryAction(id={}, type={}, entities={}, desc=\"{}\")",
            self.id,
            self.action_type,
            self.entity_ids.len(),
            self.description
        )
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HistorySnapshot {
    pub id: u64,
    pub timestamp: SystemTime,
    pub actions: Vec<HistoryAction>,
    pub document_checksum: String,
}

impl HistorySnapshot {
    pub fn new(id: u64, actions: Vec<HistoryAction>, checksum: String) -> Self {
        Self {
            id,
            timestamp: SystemTime::now(),
            actions,
            document_checksum: checksum,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HistoryManager {
    actions: Vec<HistoryAction>,
    current_position: usize,
    max_actions: usize,
    transaction_depth: usize,
    transaction_stack: Vec<usize>,
    saved_position: Option<usize>,
    is_recording: bool,
}

impl Default for HistoryManager {
    fn default() -> Self {
        Self {
            actions: Vec::new(),
            current_position: 0,
            max_actions: 500,
            transaction_depth: 0,
            transaction_stack: Vec::new(),
            saved_position: None,
            is_recording: true,
        }
    }
}

impl HistoryManager {
    pub fn new(max_actions: usize) -> Self {
        Self {
            max_actions,
            ..Default::default()
        }
    }

    pub fn record(&mut self, action: HistoryAction) {
        if !self.is_recording {
            return;
        }

        if self.transaction_depth > 0 {
            let transaction_start = *self.transaction_stack.last().unwrap_or(&0);

            if let Some(last) = self.actions.last() {
                if last.description == "Transaction" && last.action_type == ActionType::Modify {
                    let combined_entities: Vec<String> = last.entity_ids.iter()
                        .chain(action.entity_ids.iter())
                        .cloned()
                        .collect();

                    let mut last_action = self.actions.last_mut().unwrap();
                    last_action.entity_ids = combined_entities;
                    return;
                }
            }
        }

        self.actions.truncate(self.current_position);
        self.actions.push(action);
        self.current_position = self.actions.len();

        while self.actions.len() > self.max_actions {
            self.actions.remove(0);
            self.current_position = self.current_position.saturating_sub(1);
        }
    }

    pub fn begin_transaction(&mut self, description: impl Into<String>) {
        self.transaction_depth += 1;
        let position = self.actions.len();
        self.transaction_stack.push(position);

        let transaction_action = HistoryAction::new(
            ActionType::Modify,
            Vec::new(),
            format!("Transaction: {}", description.into()),
        );
        self.actions.push(transaction_action);
        self.current_position = self.actions.len();
    }

    pub fn commit_transaction(&mut self) -> bool {
        if self.transaction_depth == 0 {
            return false;
        }

        if let Some(_start) = self.transaction_stack.pop() {
            if let Some(last) = self.actions.last() {
                if last.description.starts_with("Transaction:") {
                    if last.entity_ids.is_empty() {
                        self.actions.pop();
                        self.current_position = self.actions.len();
                    }
                }
            }
        }

        self.transaction_depth = self.transaction_depth.saturating_sub(1);
        true
    }

    pub fn rollback_transaction(&mut self) -> bool {
        if self.transaction_depth == 0 || self.transaction_stack.is_empty() {
            return false;
        }

        let start = self.transaction_stack.pop().unwrap();
        self.transaction_depth = self.transaction_depth.saturating_sub(1);

        while self.actions.len() > start {
            self.undo();
        }

        true
    }

    pub fn undo(&mut self) -> Option<&HistoryAction> {
        if self.can_undo() {
            self.current_position = self.current_position.saturating_sub(1);
            Some(&self.actions[self.current_position])
        } else {
            None
        }
    }

    pub fn redo(&mut self) -> Option<&HistoryAction> {
        if self.can_redo() {
            let action = &self.actions[self.current_position];
            self.current_position += 1;
            Some(action)
        } else {
            None
        }
    }

    pub fn undo_n(&mut self, n: usize) -> usize {
        let mut count = 0;
        for _ in 0..n {
            if self.undo().is_some() {
                count += 1;
            } else {
                break;
            }
        }
        count
    }

    pub fn redo_n(&mut self, n: usize) -> usize {
        let mut count = 0;
        for _ in 0..n {
            if self.redo().is_some() {
                count += 1;
            } else {
                break;
            }
        }
        count
    }

    pub fn can_undo(&self) -> bool {
        self.current_position > 0
    }

    pub fn can_redo(&self) -> bool {
        self.current_position < self.actions.len()
    }

    pub fn undo_count(&self) -> usize {
        self.current_position
    }

    pub fn redo_count(&self) -> usize {
        self.actions.len().saturating_sub(self.current_position)
    }

    pub fn save_position(&mut self) {
        self.saved_position = Some(self.current_position);
    }

    pub fn restore_position(&mut self) -> bool {
        if let Some(pos) = self.saved_position {
            while self.current_position > pos {
                self.undo();
            }
            while self.current_position < pos {
                self.redo();
            }
            self.saved_position = None;
            true
        } else {
            false
        }
    }

    pub fn mark_saved(&mut self) {
        self.saved_position = Some(self.current_position);
    }

    pub fn is_saved(&self) -> bool {
        if let Some(saved_pos) = self.saved_position {
            saved_pos == self.current_position
        } else {
            false
        }
    }

    pub fn clear(&mut self) {
        self.actions.clear();
        self.current_position = 0;
        self.transaction_depth = 0;
        self.transaction_stack.clear();
        self.saved_position = None;
    }

    pub fn set_max_actions(&mut self, max: usize) {
        self.max_actions = max;
        while self.actions.len() > self.max_actions {
            self.actions.remove(0);
        }
    }

    pub fn enable_recording(&mut self, enable: bool) {
        self.is_recording = enable;
    }

    pub fn is_recording(&self) -> bool {
        self.is_recording
    }

    pub fn get_actions(&self) -> &[HistoryAction] {
        &self.actions
    }

    pub fn get_visible_actions(&self) -> &[HistoryAction] {
        &self.actions[..self.current_position]
    }

    pub fn get_action_at(&self, index: usize) -> Option<&HistoryAction> {
        self.actions.get(index)
    }

    pub fn get_last_action(&self) -> Option<&HistoryAction> {
        self.actions.last()
    }

    pub fn find_actions_by_type(&self, action_type: ActionType) -> Vec<&HistoryAction> {
        self.actions.iter()
            .filter(|a| a.action_type == action_type)
            .collect()
    }

    pub fn find_actions_by_entity(&self, entity_id: &str) -> Vec<&HistoryAction> {
        self.actions.iter()
            .filter(|a| a.entity_ids.iter().any(|id| id == entity_id))
            .collect()
    }

    pub fn get_action_summary(&self) -> Vec<String> {
        self.actions.iter()
            .take(self.current_position)
            .map(|a| format!("[{}] {}", a.action_type, a.description))
            .collect()
    }
}

impl fmt::Display for HistoryManager {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "HistoryManager(undo={}, redo={}, total={})",
            self.undo_count(),
            self.redo_count(),
            self.actions.len()
        )
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_history_basic_operations() {
        let mut history = HistoryManager::new(100);

        assert!(!history.can_undo());
        assert!(!history.can_redo());

        history.record(HistoryAction::new(
            ActionType::Add,
            vec!["entity1".to_string()],
            "Add entity",
        ));

        assert!(history.can_undo());
        assert!(!history.can_redo());
        assert_eq!(history.undo_count(), 1);

        history.undo();
        assert!(!history.can_undo());
        assert!(history.can_redo());

        history.redo();
        assert!(history.can_undo());
        assert!(!history.can_redo());
    }

    #[test]
    fn test_transaction() {
        let mut history = HistoryManager::new(100);

        history.begin_transaction("Move operation");
        history.record(HistoryAction::new(ActionType::Transform, vec!["e1".to_string()], "Transform 1"));
        history.record(HistoryAction::new(ActionType::Transform, vec!["e2".to_string()], "Transform 2"));

        assert!(history.commit_transaction());

        history.undo();
        assert!(!history.can_undo());
    }

    #[test]
    fn test_max_actions() {
        let mut history = HistoryManager::new(3);

        for i in 0..5 {
            history.record(HistoryAction::new(
                ActionType::Add,
                vec![format!("entity{}", i)],
                format!("Add {}", i),
            ));
        }

        assert_eq!(history.actions.len(), 3);
        assert_eq!(history.undo_count(), 3);
    }
}
