use std::any::type_name;

use serde::{de::Deserializer, ser::Serializer};
use shred::{Fetch, FetchMut, Resource};
use shrev::{Event, EventChannel, ReaderId};
use specs::World;

use crate::Error;

use super::Persistence;

/* WorldHelper */

pub trait WorldHelper {
    fn resource<R>(&self) -> Result<Fetch<R>, Error>
    where
        R: Resource;

    fn resource_mut<R>(&self) -> Result<FetchMut<R>, Error>
    where
        R: Resource;

    fn register_event_reader<E>(&self) -> Result<ReaderId<E>, Error>
    where
        E: Event;

    fn serialize<T, S>(&self, persistence: T, serializer: S) -> Result<(), S::Error>
    where
        T: Persistence,
        S: Serializer;

    fn deserialize<'de, T, D>(&self, persistence: T, deserializer: D) -> Result<(), D::Error>
    where
        T: Persistence,
        D: Deserializer<'de>;
}

impl WorldHelper for World {
    fn resource<R>(&self) -> Result<Fetch<R>, Error>
    where
        R: Resource,
    {
        self.try_fetch::<R>()
            .ok_or_else(|| Error::ResourceNotRegistered(type_name::<R>()))
    }

    fn resource_mut<R>(&self) -> Result<FetchMut<R>, Error>
    where
        R: Resource,
    {
        self.try_fetch_mut::<R>()
            .ok_or_else(|| Error::ResourceNotRegistered(type_name::<R>()))
    }

    fn register_event_reader<E>(&self) -> Result<ReaderId<E>, Error>
    where
        E: Event,
    {
        Ok(self.resource_mut::<EventChannel<E>>()?.register_reader())
    }

    fn serialize<T, S>(&self, persistence: T, serializer: S) -> Result<(), S::Error>
    where
        T: Persistence,
        S: Serializer,
    {
        persistence.serialize(self, serializer)
    }

    fn deserialize<'de, T, D>(&self, persistence: T, deserializer: D) -> Result<(), D::Error>
    where
        T: Persistence,
        D: Deserializer<'de>,
    {
        persistence.deserialize(self, deserializer)
    }
}
