use crate::gateway::{AppTurnResult, SessionService, SessionServiceError};
use crate::httpserver::channel_ingress::{build_channel_turn_request, GatewayChannelMessage};
use agent_contracts::{ChannelFileSender, InteractionHandle, LoopEventSink};
use std::sync::Arc;
use thiserror::Error;

#[derive(Debug, Clone)]
pub struct GatewayTurnResponse {
    pub session_id: String,
    pub conversation_id: String,
    pub raw_reply: String,
    pub visible_reply: String,
}

pub struct GatewayService {
    session_service: Arc<dyn SessionService>,
}

#[derive(Debug, Error)]
pub enum GatewayServiceError {
    #[error("session service failed: {0}")]
    Session(#[from] SessionServiceError),
}

impl GatewayService {
    pub fn new(session_service: Arc<dyn SessionService>) -> Self {
        Self { session_service }
    }

    pub async fn handle_channel_message(
        &self,
        message: GatewayChannelMessage,
    ) -> Result<GatewayTurnResponse, GatewayServiceError> {
        self.handle_channel_message_with_interaction(message, None, None, None)
            .await
    }

    pub async fn handle_channel_message_with_interaction(
        &self,
        message: GatewayChannelMessage,
        event_sink: Option<Arc<dyn LoopEventSink>>,
        interaction_handle: Option<Arc<dyn InteractionHandle>>,
        channel_file_sender: Option<Arc<dyn ChannelFileSender>>,
    ) -> Result<GatewayTurnResponse, GatewayServiceError> {
        let request = build_channel_turn_request(&message);
        let session_id = request.session_id.clone();
        let conversation_id = request.conversation_id.clone();
        let AppTurnResult {
            raw_reply,
            visible_reply,
            messages: _messages,
            ..
        } = self
            .session_service
            .run_turn_with_interaction(request, event_sink, interaction_handle, channel_file_sender)
            .await?;

        Ok(GatewayTurnResponse {
            session_id,
            conversation_id,
            raw_reply,
            visible_reply,
        })
    }

    pub async fn handle_channel_message_with_events(
        &self,
        message: GatewayChannelMessage,
        event_sink: Option<Arc<dyn LoopEventSink>>,
    ) -> Result<GatewayTurnResponse, GatewayServiceError> {
        self.handle_channel_message_with_interaction(message, event_sink, None, None)
            .await
    }
}