use crate::cloudhv::snapshot::*;
use crate::cloudhv::errors::CloudHypervisorError;
use std::fs;
use tempfile::TempDir;

#[test]
fn test_snapshot_manager_new() {
    let temp_dir = TempDir::new().unwrap();
    let _manager = SnapshotManager::new(temp_dir.path()).unwrap();

    assert!(temp_dir.path().exists());
}

#[test]
fn test_create_snapshot() {
    let temp_dir = TempDir::new().unwrap();
    let manager = SnapshotManager::new(temp_dir.path()).unwrap();

    let result = manager.create_snapshot("vm1", "snap1", "file:///tmp/snap1.snap");
    assert!(result.is_ok());

    let snapshot = result.unwrap();
    assert_eq!(snapshot.vm_id, "vm1");
    assert_eq!(snapshot.name, "snap1");
    assert!(snapshot.timestamp > 0);
}

#[test]
fn test_create_duplicate_snapshot() {
    let temp_dir = TempDir::new().unwrap();
    let manager = SnapshotManager::new(temp_dir.path()).unwrap();

    manager
        .create_snapshot("vm1", "snap1", "file:///tmp/snap1.snap")
        .unwrap();

    let vm_dir = temp_dir.path().join("vm1");
    let snapshot_path = vm_dir.join("snap1.snap");
    fs::write(&snapshot_path, b"test").unwrap();

    let result = manager.create_snapshot("vm1", "snap1", "file:///tmp/snap1.snap");
    assert!(result.is_err());

    match result {
        Err(CloudHypervisorError::Snapshot(msg)) => {
            assert!(msg.contains("Snapshot already exists"));
        }
        _ => panic!("Expected Snapshot error"),
    }
}

#[test]
fn test_restore_snapshot() {
    let temp_dir = TempDir::new().unwrap();
    let manager = SnapshotManager::new(temp_dir.path()).unwrap();

    let vm_dir = temp_dir.path().join("vm1");
    fs::create_dir_all(&vm_dir).unwrap();
    let snapshot_path = vm_dir.join("snap1.snap");
    fs::write(&snapshot_path, b"snapshot data").unwrap();

    let result = manager.restore_snapshot("vm1", "snap1");
    assert!(result.is_ok());

    let path = result.unwrap();
    assert_eq!(path, snapshot_path);
}

#[test]
fn test_restore_nonexistent_snapshot() {
    let temp_dir = TempDir::new().unwrap();
    let manager = SnapshotManager::new(temp_dir.path()).unwrap();

    let result = manager.restore_snapshot("vm1", "nonexistent");
    assert!(result.is_err());

    match result {
        Err(CloudHypervisorError::Snapshot(msg)) => {
            assert!(msg.contains("Snapshot not found"));
        }
        _ => panic!("Expected Snapshot error"),
    }
}

#[test]
fn test_list_snapshots_empty() {
    let temp_dir = TempDir::new().unwrap();
    let manager = SnapshotManager::new(temp_dir.path()).unwrap();

    let snapshots = manager.list_snapshots("vm1").unwrap();
    assert_eq!(snapshots.len(), 0);
}

#[test]
fn test_list_snapshots() {
    let temp_dir = TempDir::new().unwrap();
    let manager = SnapshotManager::new(temp_dir.path()).unwrap();

    manager
        .create_snapshot("vm1", "snap1", "file:///tmp/snap1.snap")
        .unwrap();
    manager
        .create_snapshot("vm1", "snap2", "file:///tmp/snap2.snap")
        .unwrap();

    let snapshots = manager.list_snapshots("vm1").unwrap();
    assert_eq!(snapshots.len(), 2);

    assert!(snapshots[0].timestamp >= snapshots[1].timestamp);
}

#[test]
fn test_delete_snapshot() {
    let temp_dir = TempDir::new().unwrap();
    let manager = SnapshotManager::new(temp_dir.path()).unwrap();

    manager
        .create_snapshot("vm1", "snap1", "file:///tmp/snap1.snap")
        .unwrap();

    let vm_dir = temp_dir.path().join("vm1");
    let snapshot_path = vm_dir.join("snap1.snap");
    fs::write(&snapshot_path, b"test").unwrap();

    let result = manager.delete_snapshot("vm1", "snap1");
    assert!(result.is_ok());

    let snapshots = manager.list_snapshots("vm1").unwrap();
    assert_eq!(snapshots.len(), 0);
}

#[test]
fn test_delete_nonexistent_snapshot() {
    let temp_dir = TempDir::new().unwrap();
    let manager = SnapshotManager::new(temp_dir.path()).unwrap();

    let result = manager.delete_snapshot("vm1", "nonexistent");
    assert!(result.is_ok());
}

#[test]
fn test_get_snapshot_path() {
    let temp_dir = TempDir::new().unwrap();
    let manager = SnapshotManager::new(temp_dir.path()).unwrap();

    let path = manager.get_snapshot_path("vm1", "snap1");
    assert_eq!(
        path,
        temp_dir.path().join("vm1").join("snap1.snap")
    );
}

#[test]
fn test_snapshot_info_serialization() {
    use std::path::PathBuf;

    let info = SnapshotInfo {
        vm_id: "vm1".to_string(),
        name: "snap1".to_string(),
        path: PathBuf::from("/tmp/snap1.snap"),
        timestamp: 1234567890,
        size: 1024,
    };

    let json = serde_json::to_string(&info).unwrap();
    let deserialized: SnapshotInfo = serde_json::from_str(&json).unwrap();

    assert_eq!(deserialized.vm_id, "vm1");
    assert_eq!(deserialized.name, "snap1");
    assert_eq!(deserialized.timestamp, 1234567890);
    assert_eq!(deserialized.size, 1024);
}

#[test]
fn test_multiple_vms_snapshots() {
    let temp_dir = TempDir::new().unwrap();
    let manager = SnapshotManager::new(temp_dir.path()).unwrap();

    manager
        .create_snapshot("vm1", "snap1", "file:///tmp/snap1.snap")
        .unwrap();
    manager
        .create_snapshot("vm2", "snap1", "file:///tmp/snap2.snap")
        .unwrap();

    let vm1_snapshots = manager.list_snapshots("vm1").unwrap();
    let vm2_snapshots = manager.list_snapshots("vm2").unwrap();

    assert_eq!(vm1_snapshots.len(), 1);
    assert_eq!(vm2_snapshots.len(), 1);
    assert_eq!(vm1_snapshots[0].vm_id, "vm1");
    assert_eq!(vm2_snapshots[0].vm_id, "vm2");
}
