//! Server-side Rhai scripting engine.
//!
//! Registers native functions and loads `scripts/server.rhai` at runtime.
//!
//! ## Available native functions
//!
//! | Function | Returns | Description |
//! |---|---|---|
//! | `list_players()` | `Array` of strings | Names of all connected players |
//! | `kick_player(name)` | `String` | Kick a player by name |
//! | `send_msg(text)` | `()` | Broadcast a system message to all clients |
//!
//! ## Adding a new server command
//!
//! 1. Register the native function on the engine in [`create_engine`].
//! 2. Add a `fn cmd_<name>(args)` wrapper in `scripts/server.rhai`.

use rhai::{Engine, AST};
use tokio::sync::broadcast;

use super::SharedClients;
use crate::core::protocol::ServerMessage;
use crate::script::load_script;

/// Build the server Rhai engine with admin commands.
pub fn create_engine(
    clients: SharedClients,
    tx: broadcast::Sender<ServerMessage>,
) -> (Engine, AST) {
    let mut engine = Engine::new();

    let clients_ref = clients.clone();
    engine.register_fn("list_players", move || -> rhai::Array {
        let clients = clients_ref.lock().unwrap();
        clients
            .values()
            .map(|c| rhai::Dynamic::from(c.name.clone()))
            .collect()
    });

    let clients_ref = clients.clone();
    let tx_ref = tx.clone();
    engine.register_fn("kick_player", move |name: &str| -> String {
        let mut clients = clients_ref.lock().unwrap();
        let entry = clients.iter().find(|(_, c)| c.name == name);
        if let Some((&id, _)) = entry {
            let client = clients.remove(&id).unwrap();
            let _ = client.kick_tx.send(());
            let _ = tx_ref.send(ServerMessage::System {
                content: format!("{name} was kicked"),
            });
            format!("Kicked {name}")
        } else {
            format!("Player '{name}' not found")
        }
    });

    let tx_ref = tx.clone();
    engine.register_fn("send_msg", move |text: &str| {
        let _ = tx_ref.send(ServerMessage::System {
            content: text.to_string(),
        });
    });

    let ast = load_script(&engine, "server").expect("failed to load scripts/server.rhai");

    (engine, ast)
}
