use std::sync::Arc;

use tokio::sync::mpsc;

use crate::agent::AgentError;
use crate::config::LLMProviderConfig;
use crate::protocol::WsOutbound;
use crate::skills::SkillRuntime;
use crate::storage::{ConversationRepository, SessionStore, SkillEventRepository};

use super::agent_factory::AgentFactory;
use super::session::Session;

#[derive(Clone)]
pub(crate) struct SessionFactory {
    provider_config: LLMProviderConfig,
    skills: Arc<SkillRuntime>,
    agent_factory: AgentFactory,
    conversations: Arc<dyn ConversationRepository>,
    skill_events: Arc<dyn SkillEventRepository>,
    store: Arc<SessionStore>,
}

impl SessionFactory {
    pub(crate) fn new(
        provider_config: LLMProviderConfig,
        skills: Arc<SkillRuntime>,
        agent_factory: AgentFactory,
        conversations: Arc<dyn ConversationRepository>,
        skill_events: Arc<dyn SkillEventRepository>,
        store: Arc<SessionStore>,
    ) -> Self {
        Self {
            provider_config,
            skills,
            agent_factory,
            conversations,
            skill_events,
            store,
        }
    }

    pub(crate) async fn create(
        &self,
        channel_name: impl Into<String>,
        user_tx: mpsc::Sender<WsOutbound>,
    ) -> Result<Session, AgentError> {
        Session::with_factories(
            channel_name.into(),
            self.provider_config.clone(),
            user_tx,
            self.skills.clone(),
            self.agent_factory.clone(),
            self.conversations.clone(),
            self.skill_events.clone(),
            self.store.clone(),
        )
        .await
    }
}
