//! Stop reason handling for ACP.
//!
//! This module implements interpretation and action determination for
//! different stop reasons (end_turn, max_tokens, max_turn_requests, refusal, cancelled).

use crate::acp::protocol::prompt::StopReason;

/// Action to take based on a stop reason.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StopReasonAction {
    /// Normal completion, no special action needed.
    Complete,
    /// Show a warning to the user with optional continuation.
    ShowWarning(String),
    /// Show an error to the user.
    ShowError(String),
    /// Show an info message to the user.
    ShowInfo(String),
}

/// Interpret a stop reason and determine the appropriate action.
///
/// # Arguments
///
/// * `stop_reason` - The stop reason from the agent
///
/// # Returns
///
/// The action that should be taken in response to this stop reason.
pub fn handle_stop_reason(stop_reason: StopReason) -> StopReasonAction {
    match stop_reason {
        StopReason::EndTurn => {
            // Normal completion, no special action needed
            StopReasonAction::Complete
        }
        StopReason::MaxTokens => {
            // Hit token limit, offer to continue
            StopReasonAction::ShowWarning(
                "Response truncated due to token limit. You can continue the conversation to get more output.".to_string()
            )
        }
        StopReason::MaxTurnRequests => {
            // Too many LLM requests in turn, offer to continue
            StopReasonAction::ShowWarning(
                "Maximum turn requests reached. The agent made many requests. You can continue if needed.".to_string()
            )
        }
        StopReason::Refusal => {
            // Agent refused to continue
            StopReasonAction::ShowError(
                "The agent refused to continue with this request.".to_string()
            )
        }
        StopReason::Cancelled => {
            // User cancelled, show confirmation
            StopReasonAction::ShowInfo("Prompt cancelled.".to_string())
        }
    }
}

/// Check if a stop reason indicates the turn can be continued.
///
/// Some stop reasons (max_tokens, max_turn_requests) indicate the agent
/// stopped due to limits but could continue if prompted again.
pub fn is_continuable(stop_reason: StopReason) -> bool {
    matches!(
        stop_reason,
        StopReason::MaxTokens | StopReason::MaxTurnRequests
    )
}

/// Check if a stop reason indicates an error condition.
pub fn is_error(stop_reason: StopReason) -> bool {
    matches!(stop_reason, StopReason::Refusal)
}

/// Get a user-facing message for a stop reason.
pub fn stop_reason_message(stop_reason: StopReason) -> String {
    match handle_stop_reason(stop_reason) {
        StopReasonAction::Complete => "Turn completed".to_string(),
        StopReasonAction::ShowWarning(msg) => msg,
        StopReasonAction::ShowError(msg) => msg,
        StopReasonAction::ShowInfo(msg) => msg,
    }
}

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

    #[test]
    fn test_end_turn_action() {
        let action = handle_stop_reason(StopReason::EndTurn);
        assert_eq!(action, StopReasonAction::Complete);
        assert!(!is_continuable(StopReason::EndTurn));
        assert!(!is_error(StopReason::EndTurn));
    }

    #[test]
    fn test_max_tokens_action() {
        let action = handle_stop_reason(StopReason::MaxTokens);
        assert!(matches!(action, StopReasonAction::ShowWarning(_)));
        assert!(is_continuable(StopReason::MaxTokens));
        assert!(!is_error(StopReason::MaxTokens));
    }

    #[test]
    fn test_max_turn_requests_action() {
        let action = handle_stop_reason(StopReason::MaxTurnRequests);
        assert!(matches!(action, StopReasonAction::ShowWarning(_)));
        assert!(is_continuable(StopReason::MaxTurnRequests));
        assert!(!is_error(StopReason::MaxTurnRequests));
    }

    #[test]
    fn test_refusal_action() {
        let action = handle_stop_reason(StopReason::Refusal);
        assert!(matches!(action, StopReasonAction::ShowError(_)));
        assert!(!is_continuable(StopReason::Refusal));
        assert!(is_error(StopReason::Refusal));
    }

    #[test]
    fn test_cancelled_action() {
        let action = handle_stop_reason(StopReason::Cancelled);
        assert!(matches!(action, StopReasonAction::ShowInfo(_)));
        assert!(!is_continuable(StopReason::Cancelled));
        assert!(!is_error(StopReason::Cancelled));
    }

    #[test]
    fn test_stop_reason_messages() {
        let reasons = vec![
            StopReason::EndTurn,
            StopReason::MaxTokens,
            StopReason::MaxTurnRequests,
            StopReason::Refusal,
            StopReason::Cancelled,
        ];

        for reason in reasons {
            let message = stop_reason_message(reason);
            assert!(!message.is_empty());
        }
    }
}
