use std::{ffi::{c_int, CString, OsStr}, path::Path, ptr};

use crate::path;


pub struct Repository {
    raw: *mut libgit2_sys::git_repository,
}
impl Repository {
    pub fn open(path: &Path) -> Result<Repository, path::Error> {
        libgit2_sys::init();

        let path = convert_path_into_c_string(path)?;

        let mut repository = ptr::null_mut();

        unsafe {
            let result_code = libgit2_sys::git_repository_open(
                &mut repository,
                path.as_ptr()
            );
            if result_code != 0 {
                return Err(format!("Received exit code of {result_code} when calling libgit2 function to open repository."));
            }
        }

        Ok(Repository {
            raw: repository,
        })
    }

    pub fn is_path_ignored(&self, path: &Path) -> Result<bool, path::Error> {

        let mut ignored: c_int = 0;

        let path = convert_path_into_c_string(path)?;

        unsafe {
            let result_code = libgit2_sys::git_ignore_path_is_ignored(
                &mut ignored,
                self.raw,
                path.as_ptr(),
            );
            if result_code != 0 {
                return Err(format!("Received exit code of {result_code} when calling libgit2 function to determine whether a path is ignored by Git."));
            }
        }

        Ok(ignored == 1)
    }
}

fn convert_path_into_c_string(path: &Path) -> Result<CString, path::Error> {
    let mut path_bytes = convert_os_string_to_bytes(path.as_os_str())?.to_owned();

    replace_slashes_in_windows_path(&mut path_bytes);

    CString::new(path_bytes)
        .map_err(|cause| format!("Path {path:?} could not be read into C string: {cause}"))
}


#[cfg(unix)]
fn convert_os_string_to_bytes(path: &OsStr) -> Result<&[u8], path::Error> {
    use std::os::unix::ffi::OsStrExt;
    Ok(path.as_bytes())
}
#[cfg(windows)]
fn convert_os_string_to_bytes(path: &OsStr) -> Result<&[u8], path::Error> {
    match path.to_str() {
        Some(path) => Ok(path.as_bytes()),
        None => Err(format!("Path '{path:?}' could not be converted to Unicode, which is unsupported on Windows.")),
    }
}

#[cfg(unix)]
fn replace_slashes_in_windows_path(_bytes: &mut [u8]) {
    /*do nothing*/
}
#[cfg(windows)]
fn replace_slashes_in_windows_path(bytes: &mut [u8]) {
    for byte in bytes {
        if *byte == b'\\' {
            *byte = b'/';
        }
    }
}
