use lsp_server::{RequestId, Response, ResponseError};
use lsp_types::{ExecuteCommandParams, TextDocumentIdentifier, Url};

use crate::{error::Error, server::Server};

pub fn handle_command(
    params: ExecuteCommandParams,
    req: RequestId,
    server: &mut Server,
) -> Result<(), ResponseError> {
    match params.command.as_str() {
        "eval" => {
            let doc: TextDocumentIdentifier =
                serde_json::from_value(params.arguments[0].clone()).unwrap();
            eval(server, &doc.uri)?;
            server.reply(Response::new_ok(req, None::<()>));
            Ok(())
        }
        #[cfg(debug_assertions)]
        "pause" => {
            // This command is only used by integration tests. It is intended to simulate
            // an operation taking some amount of time so that the behavior of requests
            // queuing behind it can be tested.
            std::thread::sleep(std::time::Duration::from_millis(100));
            server.reply(Response::new_ok(req, None::<()>));
            Ok(())
        }
        _ => Err(Error::CommandNotFound(params.command).into()),
    }
}

fn eval(server: &mut Server, uri: &Url) -> Result<(), Error> {
    if let Some(file_id) = server.world.file_id(uri)? {
        let diags = server.world.eval_diagnostics(
            file_id,
            server.world.config.eval_config.eval_limits.recursion_limit,
        );
        server.issue_diagnostics(file_id, diags);
    }
    Ok(())
}
