use iri_string::types::{UriAbsoluteStr, UriAbsoluteString};
use pijul_extension::path_state::{PathState, TrackedState};

use crate::event_loop::ExtensionState;
use crate::vscode_sys;

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

#[tracing::instrument(skip(deferred_promise, extension_state))]
pub async fn handle(
    uri: UriAbsoluteString,
    deferred_promise: DeferredPromise,
    extension_state: &ExtensionState,
) {
    let optional_path_state = get_decoration(&uri, extension_state);
    tracing::debug!(message = "Providing file decoration", ?optional_path_state);

    deferred_promise.resolve(Box::new(move |env| {
        let Some(path_state) = optional_path_state else {
            return Ok(None);
        };

        // TODO: l10n_embed
        let (badge, tooltip, color_id) = match path_state {
            PathState::Untracked => ("U", "Untracked", "pijul.decorations.path.untracked"),
            PathState::Tracked(modified_state) => match modified_state {
                TrackedState::Added => ("A", "Added", "pijul.decorations.path.added"),
                TrackedState::Removed => ("RM", "Removed", "pijul.decorations.path.removed"),
                TrackedState::Modified => ("M", "Modified", "pijul.decorations.path.modified"),
                TrackedState::Moved => ("MV", "Moved", "pijul.decorations.path.moved"),
                TrackedState::ModifiedAndMoved => (
                    "M,MV",
                    "Modified, Moved",
                    "pijul.decorations.path.modifiedAndMoved",
                ),
            },
        };

        let color = vscode_sys::ThemeColor::new(&env, color_id)?;
        let path_decoration = vscode_sys::FileDecoration::new(&env, badge, tooltip, &color)?;

        Ok(Some(path_decoration.create_ref()?))
    }));
}

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

    repository.repository.get_path_state(relative_path)
}