use super::*;

#[async_trait::async_trait]
impl crate::plugin::SessionReadService for RuntimeSessionStateService {
    async fn snapshot_current(&self) -> Result<SessionSnapshot, crate::PluginError> {
        self.services.current.snapshot_current().await
    }

    async fn snapshot_session(
        &self,
        session_id: &str,
    ) -> Result<SessionSnapshot, crate::PluginError> {
        self.services
            .current
            .snapshot_session(&self.services.managed, session_id)
            .await
    }

    async fn tool_catalog(
        &self,
        session_id: &str,
    ) -> Result<Vec<serde_json::Value>, crate::PluginError> {
        self.services
            .current
            .tool_catalog(&self.services.managed, session_id)
            .await
    }

    async fn shared_tool_catalog(
        &self,
        session_id: &str,
    ) -> Result<Arc<Vec<serde_json::Value>>, crate::PluginError> {
        self.services
            .current
            .shared_tool_catalog(&self.services.managed, session_id)
            .await
    }

    async fn tool_state(&self, session_id: &str) -> Result<crate::ToolState, crate::PluginError> {
        self.services
            .current
            .tool_state(&self.services.managed, session_id)
            .await
    }
}

#[async_trait::async_trait]
impl crate::plugin::SessionStateService for RuntimeSessionStateService {
    async fn snapshot_current(&self) -> Result<SessionSnapshot, crate::PluginError> {
        self.services.current.snapshot_current().await
    }

    async fn snapshot_session(
        &self,
        session_id: &str,
    ) -> Result<SessionSnapshot, crate::PluginError> {
        self.services
            .current
            .snapshot_session(&self.services.managed, session_id)
            .await
    }

    async fn tool_catalog(
        &self,
        session_id: &str,
    ) -> Result<Vec<serde_json::Value>, crate::PluginError> {
        self.services
            .current
            .tool_catalog(&self.services.managed, session_id)
            .await
    }

    async fn shared_tool_catalog(
        &self,
        session_id: &str,
    ) -> Result<Arc<Vec<serde_json::Value>>, crate::PluginError> {
        self.services
            .current
            .shared_tool_catalog(&self.services.managed, session_id)
            .await
    }

    async fn tool_state(&self, session_id: &str) -> Result<crate::ToolState, crate::PluginError> {
        self.services
            .current
            .tool_state(&self.services.managed, session_id)
            .await
    }

    async fn apply_tool_state(
        &self,
        session_id: &str,
        snapshot: crate::ToolState,
    ) -> Result<u64, crate::PluginError> {
        self.services
            .current
            .apply_tool_state(&self.services.managed, session_id, snapshot)
            .await
    }
}

#[async_trait::async_trait]
impl crate::plugin::SessionLifecycleService for RuntimeSessionLifecycleService {
    async fn create_session(
        &self,
        request: SessionCreateRequest,
    ) -> Result<SessionHandle, crate::PluginError> {
        self.services
            .managed
            .create_session(&self.services.current, &self.services.usage, request)
            .await
    }

    async fn close_session(&self, session_id: &str) -> Result<(), crate::PluginError> {
        self.services
            .managed
            .close_session(&self.services.current, &self.services.usage, session_id)
            .await
    }

    async fn start_turn(
        &self,
        request: crate::SessionTurnRequest<'_>,
    ) -> Result<AssembledTurn, crate::PluginError> {
        self.services
            .managed
            .start_turn(&self.services.current, &self.services.usage, request)
            .await
    }
}

#[async_trait::async_trait]
impl crate::plugin::SessionGraphService for RuntimeSessionGraphService {
    async fn append_session_nodes(
        &self,
        session_id: &str,
        request: crate::AppendSessionNodesRequest,
    ) -> Result<crate::AppendSessionNodesResult, crate::PluginError> {
        self.services
            .current
            .append_session_nodes(
                &self.services.managed,
                &self.services.usage,
                &self.services.processes,
                session_id,
                request,
            )
            .await
    }
    async fn emit_trace_event(
        &self,
        context: lash_trace::TraceContext,
        event: lash_trace::TraceEvent,
    ) -> Result<(), crate::PluginError> {
        self.services.current.emit_trace_event(context, event).await
    }
}

#[async_trait::async_trait]
impl crate::plugin::ProcessReadService for RuntimeSessionProcessService {
    async fn list_visible(
        &self,
        session_id: &str,
        mode: crate::ProcessListMode,
        scope: crate::ProcessOpScope<'_>,
    ) -> Result<Vec<crate::runtime::ProcessHandleGrantEntry>, crate::PluginError> {
        self.services
            .processes
            .list_process_handles(&self.services.current, session_id, mode, scope)
            .await
    }
}

#[async_trait::async_trait]
impl crate::ProcessService for RuntimeSessionProcessService {
    async fn start_from_request(
        &self,
        session_id: &str,
        request: crate::ProcessStartRequest,
        scope: crate::ProcessOpScope<'_>,
    ) -> Result<crate::ProcessHandleSummary, crate::PluginError> {
        let descriptor = request
            .grant
            .as_ref()
            .map(|grant| grant.descriptor.clone())
            .unwrap_or_default();
        let env_ref = match request.env_spec.as_ref() {
            Some(env_spec) => Some(
                crate::persist_process_execution_env(
                    self.services
                        .current
                        .host
                        .core
                        .durability
                        .process_env_store
                        .as_ref(),
                    env_spec,
                )
                .await?,
            ),
            None => None,
        };
        let registration = request.into_registration(env_ref);
        let record = self
            .start(
                session_id,
                registration,
                crate::ProcessStartOptions::new().with_descriptor(descriptor.clone()),
                scope,
            )
            .await?;
        Ok(crate::ProcessHandleSummary::new(
            record.id.clone(),
            descriptor,
            crate::ProcessLifecycleStatus::from(record.status.clone()),
        )
        .with_definition(record.identity.definition))
    }

    async fn start(
        &self,
        session_id: &str,
        registration: crate::ProcessRegistration,
        options: crate::ProcessStartOptions,
        scope: crate::ProcessOpScope<'_>,
    ) -> Result<crate::ProcessRecord, crate::PluginError> {
        self.services
            .processes
            .start_process(
                &self.services.current,
                &self.services.managed,
                session_id,
                registration,
                options,
                scope,
            )
            .await
    }

    async fn await_process(
        &self,
        process_id: &str,
        scope: crate::ProcessOpScope<'_>,
    ) -> Result<crate::ProcessAwaitOutput, crate::PluginError> {
        self.services
            .processes
            .await_process(&self.services.current, process_id, scope)
            .await
    }

    async fn list_visible(
        &self,
        session_id: &str,
        mode: crate::ProcessListMode,
        scope: crate::ProcessOpScope<'_>,
    ) -> Result<Vec<crate::runtime::ProcessHandleGrantEntry>, crate::PluginError> {
        self.services
            .processes
            .list_process_handles(&self.services.current, session_id, mode, scope)
            .await
    }

    async fn validate_visible(
        &self,
        session_id: &str,
        handle_ids: &[String],
        scope: crate::ProcessOpScope<'_>,
    ) -> Result<(), crate::PluginError> {
        self.services
            .processes
            .validate_process_handles_visible(
                &self.services.current,
                &self.services.managed,
                session_id,
                handle_ids,
                scope,
            )
            .await
    }

    async fn cancel(
        &self,
        session_id: &str,
        process_id: &str,
        scope: crate::ProcessOpScope<'_>,
    ) -> Result<crate::ProcessRecord, crate::PluginError> {
        self.services
            .processes
            .cancel_process(
                &self.services.current,
                &self.services.managed,
                session_id,
                process_id,
                scope,
            )
            .await
    }

    async fn signal(
        &self,
        session_id: &str,
        process_id: &str,
        signal_name: String,
        signal_id: String,
        payload: serde_json::Value,
        scope: crate::ProcessOpScope<'_>,
    ) -> Result<crate::ProcessEvent, crate::PluginError> {
        self.services
            .processes
            .signal_process(
                &self.services.current,
                session_id,
                process_id,
                signal_name,
                signal_id,
                payload,
                scope,
            )
            .await
    }

    async fn transfer(
        &self,
        from_session_id: &str,
        to_session_id: &str,
        process_ids: Vec<String>,
        scope: crate::ProcessOpScope<'_>,
    ) -> Result<(), crate::PluginError> {
        self.services
            .processes
            .transfer_process_handles(
                &self.services.current,
                &self.services.managed,
                from_session_id,
                to_session_id,
                process_ids,
                scope,
            )
            .await
    }

    async fn cancel_unreferenced(
        &self,
        session_id: &str,
        keep_process_ids: Vec<String>,
        scope: crate::ProcessOpScope<'_>,
    ) -> Result<Vec<crate::ProcessRecord>, crate::PluginError> {
        self.services
            .processes
            .cancel_unreferenced_process_handles(
                &self.services.current,
                &self.services.managed,
                session_id,
                keep_process_ids,
                scope,
            )
            .await
    }
}
