use mlua::{ExternalResult, Function, Lua, LuaString, Value};
use yazi_binding::runtime;
use yazi_dds::ember::Ember;
use yazi_shared::id::Id;

pub struct Pubsub;

impl Pubsub {
	pub(super) fn r#pub(lua: &Lua) -> mlua::Result<Function> {
		lua.create_function(|lua, (kind, value): (LuaString, Value)| {
			yazi_dds::Pubsub::r#pub(Ember::from_lua(lua, &kind.to_str()?, value)?).into_lua_err()
		})
	}

	pub(super) fn pub_to(lua: &Lua) -> mlua::Result<Function> {
		lua.create_function(|lua, (receiver, kind, value): (Id, LuaString, Value)| {
			yazi_dds::Pubsub::pub_to(receiver, Ember::from_lua(lua, &kind.to_str()?, value)?)
				.into_lua_err()
		})
	}

	pub(super) fn sub(lua: &Lua) -> mlua::Result<Function> {
		lua.create_function(|lua, (kind, f): (LuaString, Function)| {
			let rt = runtime!(lua)?;
			if !yazi_dds::Pubsub::sub(rt.name()?, &kind.to_str()?, f) {
				return Err("`sub()` called twice").into_lua_err();
			}
			Ok(())
		})
	}

	pub(super) fn sub_remote(lua: &Lua) -> mlua::Result<Function> {
		lua.create_function(|lua, (kind, f): (LuaString, Function)| {
			let rt = runtime!(lua)?;
			if !yazi_dds::Pubsub::sub_remote(rt.name()?, &kind.to_str()?, f) {
				return Err("`sub_remote()` called twice").into_lua_err();
			}
			Ok(())
		})
	}

	pub(super) fn unsub(lua: &Lua) -> mlua::Result<Function> {
		lua.create_function(|lua, kind: LuaString| {
			let rt = runtime!(lua)?;
			Ok(yazi_dds::Pubsub::unsub(rt.name()?, &kind.to_str()?))
		})
	}

	pub(super) fn unsub_remote(lua: &Lua) -> mlua::Result<Function> {
		lua.create_function(|lua, kind: LuaString| {
			let rt = runtime!(lua)?;
			Ok(yazi_dds::Pubsub::unsub_remote(rt.name()?, &kind.to_str()?))
		})
	}
}
