//! Pure merge-status message formatting for `service::merge`.
//!
//! These functions transform a completed merge report into human-readable
//! status messages. No I/O: they are pure functions over plain data.

use crate::agents::merge::{MergeReport, MergeResult};

/// Derive a human-readable status message from a completed [`MergeReport`].
///
/// The message explains what happened and (on failure) what the caller
/// should do next. On success, the wording reflects what
/// [`MergeReport::story_archived`] and [`MergeReport::worktree_cleaned_up`]
/// actually recorded — story 1178: the message must never claim "moved to
/// done" when the CRDT state transition to `Done` failed.
pub fn format_merge_status_message(report: &MergeReport) -> String {
    match &report.result {
        MergeResult::Success {
            conflicts_resolved, ..
        } => {
            let prefix = if *conflicts_resolved {
                "Merge complete: conflicts were auto-resolved and all quality gates passed."
            } else {
                "Merge complete: all quality gates passed."
            };
            match (report.story_archived, report.worktree_cleaned_up) {
                (true, true) => format!("{prefix} Story moved to done and worktree cleaned up."),
                (true, false) => {
                    format!("{prefix} Story moved to done, but worktree cleanup failed.")
                }
                (false, _) => format!(
                    "{prefix} The merge landed on master, but the story could not be moved to done — it needs manual follow-up."
                ),
            }
        }
        MergeResult::Conflict { .. } => {
            "Merge failed: conflicts detected that could not be auto-resolved. Merge was aborted — master is untouched. Call report_merge_failure with the conflict details so the human can resolve them. Do NOT manually move the story file or call accept_story.".to_string()
        }
        MergeResult::GateFailure { .. } => {
            "Merge committed but quality gates failed. Review gate_output and fix issues before re-running.".to_string()
        }
        MergeResult::NoCommits { .. } | MergeResult::Other { .. } => {
            "Merge failed. Review gate_output for details. Call report_merge_failure to record the failure. Do NOT manually move the story file or call accept_story.".to_string()
        }
    }
}

// ── Tests ─────────────────────────────────────────────────────────────────────

#[cfg(test)]
mod tests {
    use super::*;
    use crate::agents::merge::MergeResult;

    fn make_report(result: MergeResult) -> MergeReport {
        MergeReport {
            story_id: String::new(),
            result,
            worktree_cleaned_up: false,
            story_archived: false,
            report_path: None,
        }
    }

    #[test]
    fn clean_merge_message() {
        let mut r = make_report(MergeResult::Success {
            conflicts_resolved: false,
            conflict_details: None,
            gate_output: String::new(),
        });
        r.story_archived = true;
        r.worktree_cleaned_up = true;
        let msg = format_merge_status_message(&r);
        assert!(msg.contains("quality gates passed"));
        assert!(msg.contains("moved to done"));
    }

    #[test]
    fn conflicts_resolved_message() {
        let mut r = make_report(MergeResult::Success {
            conflicts_resolved: true,
            conflict_details: None,
            gate_output: String::new(),
        });
        r.story_archived = true;
        r.worktree_cleaned_up = true;
        let msg = format_merge_status_message(&r);
        assert!(msg.contains("auto-resolved"));
    }

    /// Regression test (story 1178): a git-level merge success whose CRDT
    /// state transition to Done failed (`story_archived: false`) must never
    /// produce a message claiming the story was "moved to done".
    #[test]
    fn success_without_archival_does_not_claim_moved_to_done() {
        let r = make_report(MergeResult::Success {
            conflicts_resolved: false,
            conflict_details: None,
            gate_output: String::new(),
        });
        assert!(!r.story_archived);
        let msg = format_merge_status_message(&r);
        assert!(
            !msg.contains("Story moved to done"),
            "message must not claim the story moved to done when story_archived is false: {msg}"
        );
        assert!(msg.contains("could not be moved to done"));
    }

    #[test]
    fn unresolved_conflicts_message() {
        let r = make_report(MergeResult::Conflict {
            details: None,
            output: String::new(),
        });
        let msg = format_merge_status_message(&r);
        assert!(msg.contains("could not be auto-resolved"));
        assert!(msg.contains("report_merge_failure"));
    }

    #[test]
    fn gates_failed_message() {
        let r = make_report(MergeResult::GateFailure {
            output: String::new(),
            failure_kind: None,
        });
        let msg = format_merge_status_message(&r);
        assert!(msg.contains("quality gates failed"));
    }

    #[test]
    fn general_failure_message() {
        let r = make_report(MergeResult::Other {
            output: String::new(),
            conflict_details: None,
        });
        let msg = format_merge_status_message(&r);
        assert!(msg.contains("Merge failed"));
        assert!(msg.contains("report_merge_failure"));
    }
}
