use crate::safety;
use crate::{Outpost, OutpostError, OutpostResult, RefName, Reporter, StepKind, UpstreamRef};

pub struct PullOptions;

pub struct PullReport {
    pub source_updated: bool,
    pub outpost_updated: bool,
}

pub fn run(
    outpost: &Outpost,
    _opts: PullOptions,
    reporter: &mut dyn Reporter,
) -> OutpostResult<PullReport> {
    let branch = outpost.current_branch().map_err(|err| match err {
        OutpostError::BranchNotFound { .. } => OutpostError::NoUpstreamTracking {
            branch: "HEAD".to_owned(),
        },
        other => other,
    })?;
    let source = outpost.source_repo()?;
    if !source.branch_exists(&branch)? {
        return Err(OutpostError::BranchNotFound {
            branch: branch.as_str().to_owned(),
            repo: source.work_tree().to_path_buf(),
        });
    }

    reporter.step(
        StepKind::SourceFetch,
        &format!(
            "fast-forwarding source {} branch {} from origin/{}",
            source.work_tree().display(),
            branch.as_str(),
            branch.as_str()
        ),
    );
    let source_branch_ref = format!("refs/heads/{}", branch.as_str());
    let source_before = source
        .git()
        .run_capture(["rev-parse", &source_branch_ref])?;
    source.fast_forward_branch_from_origin(&branch)?;
    let source_after = source
        .git()
        .run_capture(["rev-parse", &source_branch_ref])?;

    let upstream = UpstreamRef {
        remote: outpost.metadata().remote_name.clone(),
        merge_ref: RefName::parse(format!("refs/heads/{}", branch.as_str()))?,
    };
    safety::check_no_divergence(outpost, &branch, &upstream)?;

    reporter.step(
        StepKind::OutpostFetch,
        &format!(
            "fast-forwarding outpost {} branch {} from {}/{}",
            outpost.work_tree().display(),
            branch.as_str(),
            upstream.remote.as_str(),
            branch.as_str()
        ),
    );
    let before = outpost.git().run_capture(["rev-parse", "HEAD"])?;
    outpost.git().run_check([
        "pull",
        "--ff-only",
        upstream.remote.as_str(),
        branch.as_str(),
    ])?;
    let after = outpost.git().run_capture(["rev-parse", "HEAD"])?;

    Ok(PullReport {
        source_updated: source_before != source_after,
        outpost_updated: before != after,
    })
}
