use anyhow::Result;
use mlua::{ErrorContext, ExternalError, IntoLua, Value};
use yazi_binding::runtime_scope;
use yazi_dds::LOCAL;
use yazi_parser::spark::{Spark, SparkKind};
use yazi_plugin::LUA;

use crate::{Ctx, lives::Lives};

pub struct Preflight;

impl Preflight {
	pub fn act<'a>(cx: &mut Ctx, opt: (SparkKind, Spark<'a>)) -> Result<Spark<'a>> {
		let kind = opt.0;
		let Some(handlers) = LOCAL.read().get(kind.into()).filter(|&m| !m.is_empty()).cloned() else {
			return Ok(opt.1);
		};

		Ok(Lives::scope(cx.core, |_| {
			let mut body = opt.1.into_lua(&LUA)?;
			for (name, cb) in handlers {
				match runtime_scope!(LUA, &name, cb.call::<Value>(&body)) {
					Ok(Value::Nil) => {
						Err(format!("`{kind}` event cancelled by `{name}` plugin on preflight").into_lua_err())?
					}
					Ok(v) => body = v,
					Err(e) => Err(
						format!("Failed to run `{kind}` event handler in `{name}` plugin: {e}").into_lua_err(),
					)?,
				};
			}

			Spark::from_lua(&LUA, kind, body)
				.with_context(|e| format!("Unexpected return type from `{kind}` event handlers: {e}"))
		})?)
	}
}
