use std::{path::PathBuf, str::FromStr};

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum GitService {
    UploadPack,
    ReceivePack,
    UploadArchive,
}

impl FromStr for GitService {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "upload-pack" => Ok(Self::UploadPack),
            "receive-pack" => Ok(Self::ReceivePack),
            "upload-archive" => Ok(Self::UploadArchive),
            _ => Err(()),
        }
    }
}

pub fn parse_git_command(cmd: &str) -> Option<(GitService, &str)> {
    let (svc, path) = match cmd.split_once(' ') {
        Some(("git-receive-pack", path)) => (GitService::ReceivePack, path),
        Some(("git-upload-pack", path)) => (GitService::UploadPack, path),
        Some(("git-upload-archive", path)) => (GitService::UploadArchive, path),
        _ => return None,
    };
    Some((svc, strip_apostrophes(path)))
}

pub fn parse_repo_path(path: &str) -> Option<(&str, &str)> {
    let path = path.trim_matches('/');
    let mut parts = path.splitn(2, '/');
    match (parts.next(), parts.next()) {
        (Some(owner), Some(repo)) if !owner.is_empty() && !repo.is_empty() => {
            Some((owner, repo))
        }
        _ => None,
    }
}

pub fn build_git_command(
    service: GitService,
    path: PathBuf,
) -> tokio::process::Command {
    let mut cmd = tokio::process::Command::new("git");

    let cwd = match path.canonicalize() {
        Ok(p) => p,
        Err(e) => {
            tracing::debug!(error = %e, "path canonicalize failed, falling back to raw path");
            path.clone()
        }
    };
    cmd.current_dir(cwd);

    match service {
        GitService::UploadPack => {
            cmd.arg("upload-pack");
        }
        GitService::ReceivePack => {
            cmd.arg("receive-pack");
        }
        GitService::UploadArchive => {
            cmd.arg("upload-archive");
        }
    }

    cmd.arg(".")
        .env("GIT_CONFIG_NOSYSTEM", "1")
        .env("GIT_NO_REPLACE_OBJECTS", "1");

    #[cfg(unix)]
    {
        cmd.env("GIT_CONFIG_GLOBAL", "/dev/null")
            .env("GIT_CONFIG_SYSTEM", "/dev/null");
    }
    #[cfg(windows)]
    {
        let nul = "NUL";
        cmd.env("GIT_CONFIG_GLOBAL", nul)
            .env("GIT_CONFIG_SYSTEM", nul);
    }

    cmd
}

fn strip_apostrophes(s: &str) -> &str {
    s.trim_matches('\'')
}
