//! Provides contracts and data structures which utilize components.

use std::{
    any::{Any, TypeId},
    collections::HashMap,
    iter::Iterator,
};

/// Components contain composable units of data.
///
/// For example: health or position can be individual components.
/// Components can be composed together to form entities.
pub trait Component {
    // May contain stuff later!
}

/// A collection of components.
#[derive(Default)]
pub struct ComponentPool {
    /// Channels of components keyed by the type identifiers of said components.
    component_channels: HashMap<TypeId, Box<dyn ErasedComponentChannel>>
}

impl ComponentPool {
    /// Retrieves identifiers for all components in [`self`].
    pub(crate) fn ids(&self) -> impl Iterator<Item = &TypeId> {
        self.component_channels.keys()
    }

    /// Provides an immutable iterator over all members of a component channel.
    pub fn get_components<TComponent>(&self) -> impl Iterator<Item = &TComponent>
        where
            TComponent: Component + 'static,
    {
        let id = TypeId::of::<TComponent>();

        self.component_channels
            .get(&id)
            .map(|c| c.as_any())
            .and_then(|c| c.downcast_ref::<ComponentChannel<TComponent>>())
            .into_iter()
            .flat_map(|c| c.iter())
    }

    /// Provides a mutable iterator over all components in a channel.
    pub fn get_components_mut<TComponent>(&mut self) -> impl Iterator<Item = &mut TComponent>
        where
            TComponent: Component + 'static,
    {
        let id = TypeId::of::<TComponent>();

        self.component_channels
            .get_mut(&id)
            .map(|c| c.as_any_mut())
            .and_then(|c| c.downcast_mut::<ComponentChannel<TComponent>>())
            .into_iter()
            .flat_map(|c| c.iter_mut())
    }

    /// Retrieves the first component in a channel.
    pub fn first<TComponent>(&self) -> Option<&TComponent>
        where
            TComponent: Component + 'static,
    {
        let id = TypeId::of::<TComponent>();

        self.component_channels
            .get(&id)
            .map(|c| c.as_any())
            .and_then(|c| c.downcast_ref::<ComponentChannel<TComponent>>())
            .and_then(|c| c.first())
    }

    /// Retrieves the first component as a mutable reference from a channel.
    pub fn first_mut<TComponent>(&mut self) -> Option<&mut TComponent>
        where
            TComponent: Component + 'static,
    {
        let id = TypeId::of::<TComponent>();

        self.component_channels
            .get_mut(&id)
            .map(|c| c.as_any_mut())
            .and_then(|c| c.downcast_mut::<ComponentChannel<TComponent>>())
            .and_then(|c| c.first_mut())
    }

    /// Pushes a component onto a [`ComponentChannel`].
    pub(crate) fn push_component<TComponent>(&mut self, component: TComponent)
        where
            TComponent: 'static,
    {
        let id = TypeId::of::<TComponent>();

        self.component_channels
            .entry(id)
            .or_insert_with(|| {
                let channel = ComponentChannel::<TComponent>::new();

                Box::new(channel)
            })
            .as_any_mut()
            .downcast_mut::<ComponentChannel<TComponent>>()
            .map(|c| c.push(component));
    }
}

/// A heterogenous collection of components.
struct ComponentChannel<T> {
    components: Vec<T>,
}

impl<T> ComponentChannel<T> {
    /// Retrieves the first component in [`self`] or [`None`] if it is empty.
    pub fn first(&self) -> Option<&T> {
        self.components.first()
    }

    /// Retrieves the first component in [`self`] or [`None`] if it is empty.
    pub fn first_mut(&mut self) -> Option<&mut T> {
        self.components.first_mut()
    }

    /// Retrieves an immutable iterator over [`self`].
    pub fn iter(&self) -> impl Iterator<Item = &T> {
        self.components.iter()
    }

    /// Retrieves a mutable iterator over [`self`].
    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
        self.components.iter_mut()
    }

    /// Adds a component onto [`self`].
    pub fn push(&mut self, component: T) {
        self.components.push(component);
    }
}

impl<T> ComponentChannel<T> {
    /// Initializes a new, empty instance of [`self`].
    pub fn new() -> Self {
        let components = vec![];

        Self { components }
    }
}

/// A type-erased, contiguous span of components.
pub trait ErasedComponentChannel {
    /// Upcasts [`self`] as [`Any`].
    fn as_any(&self) -> &dyn Any;

    /// Upcasts [`self`] as [`Any`].
    fn as_any_mut(&mut self) -> &mut dyn Any;
}

impl<T> ErasedComponentChannel for ComponentChannel<T> 
    where
        T: 'static,
{
    fn as_any(&self) -> &dyn Any {
        self
    }

    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }
}
