use std::path::Path;
use std::fs;
use storage_manager::catalog::{Column, Database, Table, init_catalog, load_catalog, save_catalog};
use storage_manager::types::DataType;

use storage_manager::layout::CATALOG_FILE;

#[test]
fn test_save_catalog() {
    // Step 1: Ensure the catalog file exists (create if missing)
    if !Path::new(CATALOG_FILE).exists() {
        init_catalog();
    }

    // Step 2: Load catalog into memory
    let mut catalog = load_catalog();

    // Setup cleanup guard to remove the test database from catalog json when test ends
    struct CatalogCleanup(&'static str);
    impl Drop for CatalogCleanup {
        fn drop(&mut self) {
            let mut cat = load_catalog();
            if cat.databases.remove(self.0).is_some() {
                let _ = save_catalog(&cat);
            }
            // Also clean up any directory it might have created
            let _ = std::fs::remove_dir_all(format!("database/base/{}", self.0));
        }
    }
    let _cleanup = CatalogCleanup("test_db");

    // Step 3: Ensure a test database exists
    let db_name = "test_db";
    if !catalog.databases.contains_key(db_name) {
        catalog.databases.insert(
            db_name.to_string(),
            Database {
                tables: Default::default(),
            },
        );
    }

    // Step 4: Add a new test table entry inside the test database
    let test_table = Table {
        columns: vec![
            Column::new("id".to_string(), DataType::Int),
            Column::new("name".to_string(), DataType::Varchar(10)),
            Column::new("email".to_string(), DataType::Varchar(10)),
        ],
    };

    let db = catalog.databases.get_mut(db_name).unwrap();
    db.tables.insert("users".to_string(), test_table);

    // Step 5: Save catalog back to disk
    let _ = save_catalog(&catalog);

    // Step 6: Reload catalog from disk and verify it contains the database and table
    let reloaded_catalog = load_catalog();

    assert!(
        reloaded_catalog.databases.contains_key(db_name),
        "Saved catalog does not contain expected database '{}'",
        db_name
    );

    let reloaded_db = reloaded_catalog.databases.get(db_name).unwrap();

    assert!(
        reloaded_db.tables.contains_key("users"),
        "Saved catalog does not contain 'users' table inside database '{}'",
        db_name
    );

    let users_table = reloaded_db.tables.get("users").unwrap();
    assert_eq!(
        users_table.columns.len(),
        3,
        "Expected 3 columns in 'users' table"
    );

    assert!(users_table.columns.iter().all(|c| c.nullable));
    assert!(
        users_table
            .columns
            .iter()
            .all(|c| !c.constraints.not_null && !c.constraints.unique && c.constraints.default.is_none())
    );

    // Step 7: Clean up (optional)
    if Path::new(CATALOG_FILE).exists() {
        fs::remove_file(CATALOG_FILE).expect("Failed to clean up test catalog.json");
    }
}
