//! Merge service — domain logic for merging agent work to master.
//!
//! Extracted from `http/mcp/merge_tools.rs` following the conventions in
//! `docs/architecture/service-modules.md`:
//! - `mod.rs` (this file) — public API, typed [`Error`], orchestration
//! - `io.rs` — the ONLY place that performs side effects
//! - `status.rs` — pure merge-status message formatting

/// Side-effectful merge I/O — rebase, cherry-pick, and branch operations.
pub mod io;
/// Pure merge-status message formatting.
pub mod status;
/// Pure condensed gate/merge-failure summaries.
pub mod summary;

#[allow(unused_imports)]
pub use status::format_merge_status_message;
#[allow(unused_imports)]
pub use summary::{summarize_merge_failure_kind, summarize_merge_result};

// ── Error type ────────────────────────────────────────────────────────────────

/// Typed errors returned by `service::merge` functions.
///
/// HTTP handlers map these to status codes:
/// - [`Error::NotFound`] → 404 Not Found
/// - [`Error::Validation`] → 400 Bad Request
/// - [`Error::Conflict`] → 409 Conflict
/// - [`Error::Io`] → 500 Internal Server Error
/// - [`Error::UpstreamFailure`] → 500 Internal Server Error
#[allow(dead_code)]
#[derive(Debug)]
pub enum Error {
    /// The requested story or merge job was not found.
    NotFound(String),
    /// A required argument is missing or has an invalid value.
    Validation(String),
    /// The merge cannot proceed due to a conflicting state.
    Conflict(String),
    /// A filesystem or process I/O operation failed.
    Io(String),
    /// An upstream dependency (agents, git) returned an unexpected error.
    UpstreamFailure(String),
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::NotFound(msg) => write!(f, "Not found: {msg}"),
            Self::Validation(msg) => write!(f, "Validation error: {msg}"),
            Self::Conflict(msg) => write!(f, "Conflict: {msg}"),
            Self::Io(msg) => write!(f, "I/O error: {msg}"),
            Self::UpstreamFailure(msg) => write!(f, "Upstream failure: {msg}"),
        }
    }
}

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

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn error_display_not_found() {
        let e = Error::NotFound("merge job missing".to_string());
        assert!(e.to_string().contains("Not found"));
    }

    #[test]
    fn error_display_validation() {
        let e = Error::Validation("story_id required".to_string());
        assert!(e.to_string().contains("Validation error"));
    }

    #[test]
    fn error_display_conflict() {
        let e = Error::Conflict("story already merged".to_string());
        assert!(e.to_string().contains("Conflict"));
    }

    #[test]
    fn error_display_io() {
        let e = Error::Io("write failed".to_string());
        assert!(e.to_string().contains("I/O error"));
    }

    #[test]
    fn error_display_upstream_failure() {
        let e = Error::UpstreamFailure("git crashed".to_string());
        assert!(e.to_string().contains("Upstream failure"));
    }
}
