use std::rc::Rc;

use camino::Utf8PathBuf;
use napi::bindgen_prelude::{External, FunctionCallContext};
use pijul_extension::path_state::PathState;

use crate::vscode_sys::reference::SourceControlResourceGroupRef;
use crate::vscode_sys::{SourceControlResourceState, Uri};

pub struct Arguments {
    pub repository_path: Utf8PathBuf,
    pub repository_states: Vec<(Utf8PathBuf, PathState)>,
    pub unrecorded_changes: Rc<SourceControlResourceGroupRef>,
    pub untracked_paths: Rc<SourceControlResourceGroupRef>,
}

pub type Prototype = napi::threadsafe_function::ThreadsafeFunction<
    External<Arguments>,
    (),
    External<Arguments>,
    napi::Status,
    false,
    false,
    0,
>;

pub fn build(env: &napi::Env) -> Result<Prototype, napi::Error> {
    env.create_function_from_closure("update_resource_states", callback)?
        .build_threadsafe_function()
        .build()
}

fn callback(function_call_context: FunctionCallContext) -> Result<(), napi::Error> {
    let (external,): (&External<Arguments>,) = function_call_context.args()?;
    let Arguments {
        repository_path,
        repository_states,
        unrecorded_changes,
        untracked_paths,
    } = &**external;

    let mut modified_resource_states = Vec::new();
    let mut untracked_resource_states = Vec::new();

    for (relative_path, path_state) in repository_states {
        let absolute_path = repository_path.join(relative_path);
        let resource_uri = Uri::file(function_call_context.env, absolute_path.as_str())?;

        let resource_state =
            SourceControlResourceState::new(function_call_context.env, &resource_uri)?;

        match path_state {
            PathState::Untracked => untracked_resource_states.push(resource_state),
            PathState::Tracked(_tracked_state) => modified_resource_states.push(resource_state),
        }
    }

    unrecorded_changes
        .get_inner(function_call_context.env)?
        .set_resource_states(modified_resource_states)?;
    untracked_paths
        .get_inner(function_call_context.env)?
        .set_resource_states(untracked_resource_states)?;

    Ok(())
}