use anyhow::{Context, Result};
#[cfg(feature = "gitops")]
use git2::Repository;
use tracing::{info, warn};

/// Pull latest changes from remote and trigger deployment logic.
///
/// Uses `git2` for fetch+merge when the `gitops` feature is enabled.
/// Falls back to advisory logging when compiled without git2.
pub async fn pull_and_deploy(workspace_id: &str, local_path: &str) -> Result<()> {
    info!(
        workspace_id = %workspace_id,
        local_path = %local_path,
        "Starting git pull + deploy"
    );

    #[cfg(feature = "gitops")]
    {
        tokio::task::spawn_blocking({
            let local_path = local_path.to_string();
            let workspace_id = workspace_id.to_string();
            move || git_fetch_and_merge(&workspace_id, &local_path)
        })
        .await
        .context("git executor task panicked")??;
    }

    #[cfg(not(feature = "gitops"))]
    {
        warn!(
            workspace_id = %workspace_id,
            "gitops feature not compiled — git pull skipped (advisory only)"
        );
    }

    info!(workspace_id = %workspace_id, "Deployment triggered");
    Ok(())
}

#[cfg(feature = "gitops")]
fn git_fetch_and_merge(workspace_id: &str, local_path: &str) -> Result<()> {
    let repo =
        Repository::open(local_path).with_context(|| format!("open repo at {}", local_path))?;

    // Fetch origin
    let mut remote = repo.find_remote("origin").context("find remote 'origin'")?;

    let fetch_opts = git2::FetchOptions::default();
    remote
        .fetch(
            &[] as &[&str],
            Some(&mut git2::FetchOptions::default()),
            None,
        )
        .context("fetch from origin")?;

    // Find FETCH_HEAD
    let fetch_head = repo
        .find_reference("FETCH_HEAD")
        .context("find FETCH_HEAD")?;
    let fetch_commit = repo
        .reference_to_annotated_commit(&fetch_head)
        .context("resolve FETCH_HEAD commit")?;

    // Perform merge analysis
    let (analysis, _) = repo
        .merge_analysis(&[&fetch_commit])
        .context("merge analysis")?;

    if analysis.is_up_to_date() {
        info!(workspace_id = %workspace_id, "Already up to date");
        return Ok(());
    }

    if analysis.is_fast_forward() {
        let refname = format!(
            "refs/heads/{}",
            repo.head()
                .ok()
                .and_then(|h| h.shorthand().map(|s| s.to_string()))
                .unwrap_or_else(|| "main".to_string())
        );
        let mut reference = repo
            .find_reference(&refname)
            .context("find HEAD reference")?;
        reference
            .set_target(fetch_commit.id(), "fast-forward")
            .context("fast-forward HEAD")?;
        repo.set_head(&refname).context("set HEAD")?;
        repo.checkout_head(Some(git2::build::CheckoutBuilder::default().force()))
            .context("checkout HEAD")?;
        info!(
            workspace_id = %workspace_id,
            commit = %fetch_commit.id(),
            "Fast-forwarded to latest commit"
        );
    } else {
        warn!(
            workspace_id = %workspace_id,
            "Non-fast-forward merge required — deployment skipped (requires manual resolution)"
        );
    }

    Ok(())
}
