use std::sync::Arc;

use actix_web::body::BoxBody;
use actix_web::dev::AppService;
use actix_web::dev::HttpServiceFactory;
use actix_web::dev::ResourceDef;
use actix_web::dev::ServiceFactory;
use actix_web::dev::ServiceRequest;
use actix_web::dev::ServiceResponse;
use actix_web::error::Error;
use futures_util::future::LocalBoxFuture;

use crate::mcp::jsonrpc::implementation::Implementation;
use crate::mcp::mcp_http_service::McpHttpService;
use crate::mcp::resource_list_aggregate::ResourceListAggregate;
use crate::mcp::session_manager::SessionManager;
use crate::mcp::tool_registry::ToolRegistry;
use crate::prompt_controller_collection_holder::PromptControllerCollectionHolder;

pub struct McpHttpServiceFactory {
    pub mount_path: String,
    pub prompt_controller_collection_holder: PromptControllerCollectionHolder,
    pub resource_list_aggregate: Arc<ResourceListAggregate>,
    pub server_info: Implementation,
    pub session_manager: SessionManager,
    pub tool_registry: Arc<ToolRegistry>,
}

impl ServiceFactory<ServiceRequest> for McpHttpServiceFactory {
    type Config = ();
    type Error = Error;
    type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
    type InitError = ();
    type Response = ServiceResponse<BoxBody>;
    type Service = McpHttpService;

    fn new_service(&self, _: Self::Config) -> Self::Future {
        let prompt_controller_collection_holder = self.prompt_controller_collection_holder.clone();
        let resource_list_aggregate = self.resource_list_aggregate.clone();
        let server_info = self.server_info.clone();
        let session_manager = self.session_manager.clone();
        let tool_registry = self.tool_registry.clone();

        Box::pin(async move {
            Ok(McpHttpService {
                prompt_controller_collection_holder,
                resource_list_aggregate,
                server_info,
                session_manager,
                tool_registry,
            })
        })
    }
}

impl HttpServiceFactory for McpHttpServiceFactory {
    fn register(self, config: &mut AppService) {
        config.register_service(
            if config.is_root() {
                ResourceDef::root_prefix(&self.mount_path)
            } else {
                ResourceDef::prefix(&self.mount_path)
            },
            None,
            self,
            None,
        );
    }
}
