//! Merge control — server-side trigger and failure reporting.
use crate::slog;
use crate::slog_error;
use crate::slog_warn;
use std::sync::Arc;

use super::super::super::AgentPool;
use crate::agents::{PipelineStage, pipeline_stage};

impl AgentPool {
    /// Trigger a deterministic server-side merge for `story_id` without spawning
    /// an LLM agent.
    ///
    /// Constructs an `Arc<Self>` from the pool's shared fields and delegates to
    /// [`start_merge_agent_work`].  The merge runs in a background task; this
    /// function returns immediately.
    pub(crate) fn trigger_server_side_merge(&self, project_root: &std::path::Path, story_id: &str) {
        let pool = Arc::new(Self {
            agents: Arc::clone(&self.agents),
            port: self.port,
            watcher_tx: self.watcher_tx.clone(),
            status_broadcaster: Arc::clone(&self.status_broadcaster),
        });
        if let Err(e) = pool.start_merge_agent_work(project_root, story_id) {
            slog_error!("[merge] Failed to trigger server-side merge for '{story_id}': {e}");
        }
    }

    /// Record that the squash merge for `story_id` succeeded with the story
    /// archived.  Sets `merge_success_reported = true` on the active
    /// mergemaster agent so the exit handler in `spawn.rs` can distinguish
    /// a clean successful exit from a transient crash (bug 1008).
    ///
    /// If the agent was already removed from the pool (race: `remove_agents_for_story`
    /// ran first) this is a no-op; the `ContentKey::MergeSuccess` DB key written
    /// by the caller acts as the authoritative fallback in that case.
    pub async fn set_merge_success_reported(&self, story_id: &str) {
        let mut lock = self.agents.lock().await;
        let found = lock.iter_mut().find(|(key, agent)| {
            let key_story_id = key
                .rsplit_once(':')
                .map(|(sid, _)| sid)
                .unwrap_or(key.as_str());
            key_story_id == story_id
                && pipeline_stage(&agent.agent_name) == PipelineStage::Mergemaster
        });
        match found {
            Some((_, agent)) => {
                agent.merge_success_reported = true;
                slog!(
                    "[pipeline] Merge success flag set for '{story_id}:{}'",
                    agent.agent_name
                );
            }
            None => {
                slog!(
                    "[pipeline] set_merge_success_reported: no running mergemaster \
                     for '{story_id}' — DB key is the authoritative fallback"
                );
            }
        }
    }

    /// Record that the mergemaster agent for `story_id` explicitly reported a
    /// merge failure via the `report_merge_failure` MCP tool.
    ///
    /// Sets `merge_failure_reported = true` on the active mergemaster agent so
    /// that `run_pipeline_advance` can block advancement to `5_done/` even when
    /// the server-owned gate check returns `gates_passed=true` (those gates run
    /// in the feature-branch worktree, not on master).
    pub async fn set_merge_failure_reported(&self, story_id: &str) {
        let mut lock = self.agents.lock().await;
        let found = lock.iter_mut().find(|(key, agent)| {
            let key_story_id = key
                .rsplit_once(':')
                .map(|(sid, _)| sid)
                .unwrap_or(key.as_str());
            key_story_id == story_id
                && pipeline_stage(&agent.agent_name) == PipelineStage::Mergemaster
        });
        match found {
            Some((_, agent)) => {
                agent.merge_failure_reported = true;
                slog!(
                    "[pipeline] Merge failure flag set for '{story_id}:{}'",
                    agent.agent_name
                );
            }
            None => {
                slog_warn!(
                    "[pipeline] set_merge_failure_reported: no running mergemaster found \
                     for story '{story_id}' — flag not set"
                );
            }
        }
    }
}
