//! Common test utilities and helper functions to reduce duplication in tests

use crate::db;
use rusqlite::Connection;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use tempfile::TempDir;

/// Create a temporary directory for testing
pub fn create_temp_dir() -> TempDir {
    TempDir::new().expect("Failed to create temporary directory")
}

/// Create a temporary file with the given content
pub fn create_temp_file_with_content(dir: &TempDir, filename: &str, content: &str) -> PathBuf {
    let file_path = dir.path().join(filename);
    let mut file = File::create(&file_path).expect("Failed to create test file");
    write!(file, "{content}").expect("Failed to write to test file");
    file_path
}

/// Create an empty temporary file
pub fn create_empty_temp_file(dir: &TempDir, filename: &str) -> PathBuf {
    let file_path = dir.path().join(filename);
    File::create(&file_path).expect("Failed to create empty test file");
    file_path
}

/// Helper to test basic temporary directory setup
pub fn test_temp_dir_setup() {
    let temp_dir = create_temp_dir();
    assert!(temp_dir.path().exists());
}

/// Helper to test file creation and verification
pub fn test_file_creation(dir: &TempDir, filename: &str, content: &str) -> PathBuf {
    let file_path = create_temp_file_with_content(dir, filename, content);
    assert!(file_path.exists());

    let metadata = std::fs::metadata(&file_path).expect("Failed to get file metadata");
    assert!(metadata.len() > 0);

    file_path
}

/// Create a temporary database for testing
pub fn create_temp_db() -> (TempDir, Connection, PathBuf) {
    let temp_dir = create_temp_dir();
    let db_path = temp_dir.path().join("test.db");
    let conn = db::open(db_path.clone()).expect("Failed to open database");
    (temp_dir, conn, db_path)
}

/// Create a test item in the database
pub fn create_test_item(conn: &Connection) -> i64 {
    let item = crate::db::Item {
        id: None,
        ts: chrono::Utc::now(),
        size: Some(100),
        compression: crate::compression_engine::CompressionType::None.to_string(),
    };
    db::insert_item(conn, item).expect("Failed to insert item")
}

/// Test compression and decompression with an engine
pub fn test_compression_engine(
    engine: &dyn crate::compression_engine::CompressionEngine,
    test_data: &[u8],
) {
    let dir = create_temp_dir();
    let file_path = dir.path().join("test_compression.dat");

    // Test compression
    {
        let mut writer = engine
            .create(file_path.clone())
            .expect("Failed to create writer");
        writer.write_all(test_data).expect("Failed to write data");
    }

    // Test decompression
    let mut reader = engine.open(file_path).expect("Failed to open reader");
    let mut decompressed = Vec::new();
    std::io::copy(&mut reader, &mut decompressed).expect("Failed to read data");

    assert_eq!(test_data, decompressed.as_slice());
}

/// Get the size of a file
pub fn get_file_size(file_path: &PathBuf) -> u64 {
    let metadata = std::fs::metadata(file_path).expect("Failed to get file metadata");
    metadata.len()
}

/// Assert that a file exists
pub fn assert_file_exists(file_path: &PathBuf) {
    assert!(file_path.exists(), "File {file_path:?} does not exist");
}

/// Assert that a file does not exist
pub fn assert_file_not_exists(file_path: &PathBuf) {
    assert!(
        !file_path.exists(),
        "File {file_path:?} should not exist but it does"
    );
}
