use iri_string::types::{UriAbsoluteStr, UriAbsoluteString};

use crate::event_loop::ExtensionState;

pub type DeferredPromise = napi::JsDeferred<
    Option<String>,
    Box<dyn FnOnce(napi::Env) -> Result<Option<String>, napi::Error>>,
>;

#[tracing::instrument(skip(deferred_promise, extension_state))]
pub async fn handle(
    uri: UriAbsoluteString,
    deferred_promise: DeferredPromise,
    extension_state: &ExtensionState,
) {
    let tracked_contents = get_tracked_contents(&uri, extension_state);
    tracing::info!(
        message = "Providing tracked contents",
        length = ?tracked_contents.as_ref().map(|contents| contents.len())
    );

    deferred_promise.resolve(Box::new(move |_env| Ok(tracked_contents)));
}

#[tracing::instrument(skip(extension_state))]
fn get_tracked_contents(uri: &UriAbsoluteStr, extension_state: &ExtensionState) -> Option<String> {
    let Some((repository_path, relative_path, repository)) = extension_state.get_repository(uri)
    else {
        tracing::info!(message = "No matching repository for path", ?uri);
        return None;
    };

    let Some(open_file) = repository.repository.get_open_file(relative_path) else {
        tracing::info!(
            message = "No open file found in repository",
            ?repository_path,
            ?relative_path
        );
        return None;
    };

    let Some(tracked_contents) = open_file.tracked_contents() else {
        tracing::info!(
            message = "No tracked contents for file",
            ?repository_path,
            ?relative_path
        );
        return None;
    };

    Some(tracked_contents.to_string())
}