🏡 index : ~doyle/jogre.git

use std::collections::HashMap;

use serde::Deserialize;
use serde_json::{value::RawValue, Value};

use crate::extensions::{JmapEndpoint, JmapExtension, ResolvedArguments};

pub struct ExtensionRouter<Ext: JmapExtension> {
    routes: HashMap<&'static str, Box<dyn ErasedJmapEndpoint<Ext> + Send + Sync>>,
}

impl<Ext: JmapExtension> ExtensionRouter<Ext> {
    pub fn register<E: JmapEndpoint<Ext> + Send + Sync + 'static>(mut self, endpoint: E) -> Self {
        self.routes.insert(E::ENDPOINT, Box::new(endpoint));
        self
    }

    pub fn handle(
        &self,
        extension: &Ext,
        method: &str,
        params: ResolvedArguments<'_>,
    ) -> Option<HashMap<String, Value>> {
        Some(self.routes.get(method)?.handle(extension, params))
    }
}

impl<Ext: JmapExtension> Default for ExtensionRouter<Ext> {
    fn default() -> Self {
        Self {
            routes: HashMap::new(),
        }
    }
}

trait ErasedJmapEndpoint<Ext> {
    fn handle(&self, endpoint: &Ext, params: ResolvedArguments<'_>) -> HashMap<String, Value>;
}

impl<Ext: JmapExtension, E: JmapEndpoint<Ext>> ErasedJmapEndpoint<Ext> for E {
    fn handle(&self, endpoint: &Ext, params: ResolvedArguments<'_>) -> HashMap<String, Value> {
        let res = <Self as JmapEndpoint<Ext>>::handle(
            self,
            endpoint,
            Deserialize::deserialize(params).unwrap(),
        );

        serde_json::from_value(serde_json::to_value(res).unwrap()).unwrap()
    }
}