Skip to content
use std::sync::Arc;

use corium::{
    code::{Code, Lang},
    compiler::Compiler,
    runner::Runner,
    store::DB,
};

fn create_test_db() -> Arc<DB> {
    let dir = tempfile::tempdir().unwrap();
    let db_path = dir.path().join("test.db");
    let db_path_str = db_path.to_str().unwrap().to_string();
    let db = DB::new(&db_path_str).expect("Failed to create test DB");
    std::mem::forget(dir);
    Arc::new(db)
}

#[tokio::test]
async fn test_create_and_load_code() {
    let db = create_test_db();
    let wasm = Compiler::new()
        .compile("fun main() {}", Lang::Kotlin)
        .await
        .unwrap();

    let code = Code::new("/api/test", "fun main() {}", Lang::Kotlin, wasm);
    let path = code.path().to_string();

    db.save_code(&code).await.unwrap();
    let loaded = db.load_code(&path).await.unwrap();

    assert_eq!(loaded.path(), "/api/test");
    assert_eq!(loaded.lang(), &Lang::Kotlin);
    assert_eq!(loaded.raw(), "fun main() {}");
}

#[tokio::test]
async fn test_load_code_by_id() {
    let db = create_test_db();
    let wasm = Compiler::new()
        .compile("fun main() {}", Lang::Kotlin)
        .await
        .unwrap();

    let code = Code::new("/api/byid", "fun main() {}", Lang::Kotlin, wasm);
    let id = code.id().to_string();

    db.save_code(&code).await.unwrap();
    let loaded = db.load_code_by_id(&id).await.unwrap();

    assert_eq!(loaded.path(), "/api/byid");
    assert_eq!(loaded.id(), &id);
}

#[tokio::test]
async fn test_list_codes() {
    let db = create_test_db();

    let wasm = Compiler::new()
        .compile("fun main() {}", Lang::Kotlin)
        .await
        .unwrap();

    let code1 = Code::new("/api/alpha", "code1", Lang::Kotlin, wasm.clone());
    let code2 = Code::new("/api/beta", "code2", Lang::Rust, wasm.clone());

    db.save_code(&code1).await.unwrap();
    db.save_code(&code2).await.unwrap();

    let codes = db.list_codes().await;
    assert_eq!(codes.len(), 2);
}

#[tokio::test]
async fn test_delete_code() {
    let db = create_test_db();
    let wasm = Compiler::new()
        .compile("fun main() {}", Lang::Kotlin)
        .await
        .unwrap();

    let code = Code::new("/api/delete_me", "fun main() {}", Lang::Kotlin, wasm);
    let path = code.path().to_string();

    db.save_code(&code).await.unwrap();
    assert!(db.load_code(&path).await.is_some());

    let deleted = db.delete_code(&path).await;
    assert!(deleted);
    assert!(db.load_code(&path).await.is_none());
}

#[tokio::test]
async fn test_delete_nonexistent() {
    let db = create_test_db();
    let deleted = db.delete_code("/api/nonexistent").await;
    assert!(!deleted);
}

#[tokio::test]
async fn test_update_code() {
    let db = create_test_db();
    let wasm = Compiler::new()
        .compile("fun main() {}", Lang::Kotlin)
        .await
        .unwrap();

    let mut code = Code::new("/api/update", "original", Lang::Kotlin, wasm.clone());
    db.save_code(&code).await.unwrap();

    code.set_revision("updated", Lang::Kotlin, wasm);
    db.save_code(&code).await.unwrap();

    let loaded = db.load_code("/api/update").await.unwrap();
    assert_eq!(loaded.raw(), "updated");
}

#[tokio::test]
async fn test_compiler_placeholder_wasm() {
    let compiler = Compiler::new();
    let result = compiler.compile("fun main() {}", Lang::Kotlin).await;
    assert!(result.is_ok());

    let wasm = result.unwrap();
    assert!(wasm.starts_with(&[0x00, 0x61, 0x73, 0x6d]));
}

#[tokio::test]
async fn test_runner_placeholder() {
    let runner = Runner::new();
    let code = Code::new("/api/runner_test", "fun main() {}", Lang::Kotlin, vec![]);
    let result = runner.run(&code, "{}");

    assert!(result.is_ok());
    let run_result = result.unwrap();
    assert_eq!(run_result.status, 200);
    assert!(run_result.output.contains("No WASM binary"));
}

#[tokio::test]
async fn test_runner_with_wasm() {
    let runner = Runner::new();
    let compiler = Compiler::new();
    let wasm = compiler.compile("fun main() {}", Lang::Kotlin).await.unwrap();
    let code = Code::new("/api/runner_wasm", "fun main() {}", Lang::Kotlin, wasm);

    let result = runner.run(&code, "{}");
    assert!(result.is_ok(), "WASM execution should succeed, got error: {:?}", result.err());

    let run_result = result.unwrap();
    assert_eq!(run_result.status, 0);
}