#![allow(clippy::missing_errors_doc)]
#![allow(clippy::cargo_common_metadata)]

use std::io::ErrorKind;

use async_fs::read_to_string;
use async_io::block_on;

use mlua::prelude::*;
use mlua_luau_scheduler::{LuaSpawnExt, Scheduler};

const MAIN_SCRIPT: &str = include_str!("./lua/basic_spawn.luau");

pub fn main() -> LuaResult<()> {
    tracing_subscriber::fmt()
        .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
        .with_target(false)
        .without_time()
        .init();

    // Set up persistent Lua environment
    let lua = Lua::new();
    lua.globals().set(
        "readFile",
        lua.create_async_function(|lua, path: String| async move {
            // Spawn background task that does not take up resources on the Lua thread
            let task = lua.spawn(async move {
                match read_to_string(path).await {
                    Ok(s) => Ok(Some(s)),
                    Err(e) if e.kind() == ErrorKind::NotFound => Ok(None),
                    Err(e) => Err(e),
                }
            });

            // Wait for it to complete
            let result = task.await.into_lua_err();

            // We can also spawn local tasks that do take up resources
            // on the Lua thread, but that do not have the Send bound
            if result.is_ok() {
                lua.spawn_local(async move {
                    println!("File read successfully!");
                });
            }

            result
        })?,
    )?;

    // Load the main script into a scheduler
    let sched = Scheduler::new(&lua);
    let main = lua.load(MAIN_SCRIPT);
    sched.push_thread_front(main, ())?;

    // Run until completion
    block_on(sched.run());

    Ok(())
}

#[test]
fn test_basic_spawn() -> LuaResult<()> {
    main()
}