#![deny(missing_docs)]

//! A library for representing and simulating interactive stories using a multilinear system.

use derive_more::Into;
use event_simulation::{BorrowedSimulation, MultiSimulation, OwnedSimulation, SimulationInfo};
use thiserror::Error;

use std::{
    collections::{BTreeMap, BTreeSet},
    convert::Infallible,
    fmt::Display,
    iter::Copied,
};

/// Represents an event in the multilinear system.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Into)]
pub struct Event(pub usize);

impl Display for Event {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "E{}", self.0)
    }
}

/// Represents a channel in the multilinear system.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Into)]
pub struct Channel(pub usize);

impl Display for Channel {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "C{}", self.0)
    }
}

mod streams;

/// Represents a change in value for a condition.
#[derive(Copy, Clone)]
pub struct Change {
    /// The initial value of the condition.
    pub from: usize,
    /// The final value of the condition after the change.
    pub to: usize,
}

trait ChangeGetter {
    type Opposite: ChangeGetter;

    fn get(change: &Change) -> usize;
}

struct From;
impl ChangeGetter for From {
    type Opposite = To;

    #[inline]
    fn get(change: &Change) -> usize {
        change.from
    }
}

struct To;
impl ChangeGetter for To {
    type Opposite = From;

    #[inline]
    fn get(change: &Change) -> usize {
        change.to
    }
}

impl Change {
    #[inline]
    fn value(value: usize) -> Self {
        Self {
            from: value,
            to: value,
        }
    }

    #[inline]
    fn new(from: usize, to: usize) -> Self {
        Self { from, to }
    }

    #[inline]
    fn get<T: ChangeGetter>(&self) -> usize {
        T::get(self)
    }
}

/// Represents a condition for an event in the multilinear system.
#[derive(Copy, Clone)]
pub struct Condition {
    channel: Channel,
    change: Change,
}

impl Condition {
    /// Creates a new condition of the specified `channel` with `value`.
    pub fn new(channel: Channel, value: usize) -> Self {
        Self {
            channel,
            change: Change::value(value),
        }
    }

    /// Creates a new condition of the specified `channel` changing the value from `from` to `to`.
    pub fn change(channel: Channel, from: usize, to: usize) -> Self {
        Self {
            channel,
            change: Change::new(from, to),
        }
    }
}

struct ChannelNode {
    events: BTreeSet<Event>,
}

/// Represents an event.
///
/// Stores multiple conditions. One of them has to be fulfilled to be true.
pub struct EventNode {
    conditions: Vec<BTreeMap<Channel, Change>>,
}

impl EventNode {
    /// Returns an iterator over the channel and change for each of its conditions.
    pub fn iter(&self) -> impl Iterator<Item = impl Iterator<Item = (Channel, Change)>> {
        self.conditions.iter().map(|condition| {
            condition
                .iter()
                .map(|(&channel, &change)| (channel, change))
        })
    }
}

impl EventNode {
    #[inline]
    fn action_index<T: ChangeGetter>(&self, state: &[usize]) -> Option<usize> {
        fn check<T: ChangeGetter>(condition: &BTreeMap<Channel, Change>, state: &[usize]) -> bool {
            for (&channel, &change) in condition {
                if change.get::<T>() != state[channel.0] {
                    return false;
                }
            }

            true
        }

        for (i, condition) in self.conditions.iter().enumerate() {
            if check::<T>(condition, state) {
                return Some(i);
            }
        }

        None
    }

    fn check_action<T: ChangeGetter>(&self, state: &[usize]) -> bool {
        self.action_index::<T>(state).is_some()
    }

    unsafe fn invoke_action<T: ChangeGetter>(&self, state: &mut [usize]) {
        let index = unsafe { self.action_index::<T>(state).unwrap_unchecked() };

        for (&channel, &change) in &self.conditions[index] {
            state[channel.0] = change.get::<T::Opposite>();
        }
    }
}

/// Represents the information for a multilinear system.
#[derive(Default)]
pub struct MultilinearInfo {
    events: Vec<EventNode>,
    channels: Vec<ChannelNode>,
}

impl MultilinearInfo {
    /// Returns an iterator over the events and the event nodes containing the conditions.
    pub fn iter(&self) -> impl Iterator<Item = (Event, &EventNode)> {
        self.events
            .iter()
            .enumerate()
            .map(|(i, event_node)| (Event(i), event_node))
    }
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
struct ChannelValue {
    channel: Channel,
    value: usize,
}

#[derive(Clone)]
struct ChangeSet {
    from: BTreeSet<ChannelValue>,
    to: BTreeSet<ChannelValue>,
}

impl ChangeSet {
    fn create(&mut self, map: &BTreeMap<Channel, Change>) -> Self {
        let mut from = BTreeSet::new();
        let mut to = BTreeSet::new();

        for (&channel, &change) in map {
            let from_value = ChannelValue {
                channel,
                value: change.from,
            };
            if !self.from.remove(&from_value) {
                from.insert(from_value);
            }

            let to_value = ChannelValue {
                channel,
                value: change.to,
            };
            if !self.to.remove(&to_value) {
                to.insert(to_value);
            }
        }

        Self { from, to }
    }
}

/// Represents an error when adding an invalid change to an event.
#[derive(Copy, Clone, PartialEq, Eq, Debug, Error)]
pub enum InvalidChangeError {
    /// Indicates that a channel is being changed more than once in the same set of conditions.
    #[error("Only one condition per channel is allowed for each event")]
    DuplicateChannel,
    /// Indicates that the sets of conditions being added are conflicting because the unique part doesn't have a shared channel.
    #[error("Conflicting conditions might cause ambiguous behavior")]
    ConflictingConditions,
}

/// Represents information for building an event in the multilinear system.
#[derive(Clone, Default)]
pub struct EventInfo {
    conditions: Vec<BTreeMap<Channel, Change>>,
}

impl EventInfo {
    /// Creates a new instance of `EventInfo`.
    pub fn new() -> Self {
        Self::default()
    }

    /// Adds a change to the event.
    pub fn add_change(&mut self, conditions: &[Condition]) -> Result<(), InvalidChangeError> {
        let mut from = BTreeSet::new();
        let mut to = BTreeSet::new();
        let mut map = BTreeMap::new();

        for &Condition { channel, change } in conditions {
            if map.insert(channel, change).is_some() {
                return Err(InvalidChangeError::DuplicateChannel);
            }
            from.insert(ChannelValue {
                channel,
                value: change.from,
            });
            to.insert(ChannelValue {
                channel,
                value: change.to,
            });
        }

        let new_changes = ChangeSet { from, to };

        for condition in &self.conditions {
            let mut new_changes = new_changes.clone();
            let changes = new_changes.create(condition);

            if !changes.from.iter().any(|change| {
                new_changes
                    .from
                    .iter()
                    .any(|new_change| change.channel == new_change.channel)
            }) || !changes.to.iter().any(|change| {
                new_changes
                    .to
                    .iter()
                    .any(|new_change| change.channel == new_change.channel)
            }) {
                return Err(InvalidChangeError::ConflictingConditions);
            }
        }

        self.conditions.push(map);
        Ok(())
    }

    /// Creates a new instance of `EventInfo` with the given change.
    pub fn with_change(mut self, conditions: &[Condition]) -> Result<Self, InvalidChangeError> {
        self.add_change(conditions)?;
        Ok(self)
    }
}

impl MultilinearInfo {
    /// Creates a new instance of `MultilinearInfo`.
    pub fn new() -> Self {
        Self::default()
    }

    /// Adds a new channel to the multilinear system.
    pub fn add_channel(&mut self) -> Channel {
        let index = self.channels.len();
        self.channels.push(ChannelNode {
            events: BTreeSet::new(),
        });
        Channel(index)
    }

    /// Adds a new event to the multilinear system.
    pub fn add_event(&mut self, info: EventInfo) -> Event {
        let EventInfo { conditions } = info;

        let index = Event(self.events.len());

        for condition in &conditions {
            for &channel in condition.keys() {
                self.channels[channel.0].events.insert(index);
            }
        }

        self.events.push(EventNode { conditions });
        index
    }
}

/// Represents the state of a multilinear system.
#[derive(Clone)]
pub struct MultilinearState {
    values: Vec<usize>,
    callables: BTreeSet<Event>,
    revertables: BTreeSet<Event>,
}

impl MultilinearState {
    fn from_values(info: &MultilinearInfo, values: Vec<usize>) -> Self {
        let mut callables = BTreeSet::new();
        let mut revertables = BTreeSet::new();

        for (index, event) in info.events.iter().enumerate() {
            if event.check_action::<From>(&values) {
                callables.insert(Event(index));
            }
            if event.check_action::<To>(&values) {
                revertables.insert(Event(index));
            }
        }

        Self {
            values,
            callables,
            revertables,
        }
    }

    fn update_events(&mut self, event: &EventNode, info: &MultilinearInfo) {
        let mut changed_events = BTreeSet::new();
        for condition in &event.conditions {
            for channel in condition.keys() {
                let channel = &info.channels[channel.0];
                for &event in &channel.events {
                    changed_events.insert(event);
                }
            }
        }

        for event in changed_events {
            let event_node = &info.events[event.0];
            if event_node.check_action::<From>(&self.values) {
                self.callables.insert(event);
            } else {
                self.callables.remove(&event);
            }
            if event_node.check_action::<To>(&self.values) {
                self.revertables.insert(event);
            } else {
                self.revertables.remove(&event);
            }
        }
    }
}

impl SimulationInfo for MultilinearInfo {
    type StateLoadingError = Infallible;
    type State = MultilinearState;
    type AccessData = [usize];
    type LoadData = Vec<usize>;
    type Event = Event;
    type EventContainer<'a>
        = Copied<std::collections::btree_set::Iter<'a, Event>>
    where
        Self: 'a;

    #[inline]
    fn default_state(&self) -> MultilinearState {
        MultilinearState::from_values(self, vec![0; self.channels.len()])
    }

    #[inline]
    fn load_state(&self, data: Vec<usize>) -> Result<MultilinearState, Infallible> {
        Ok(MultilinearState::from_values(self, data))
    }

    #[inline]
    unsafe fn clone_state(&self, state: &MultilinearState) -> MultilinearState {
        state.clone()
    }

    #[inline]
    unsafe fn data<'a>(&self, state: &'a MultilinearState) -> &'a [usize] {
        &state.values
    }

    #[inline]
    fn callables(state: &MultilinearState) -> Self::EventContainer<'_> {
        state.callables.iter().copied()
    }

    #[inline]
    fn callable(state: &MultilinearState, event: Event) -> bool {
        state.callables.contains(&event)
    }

    unsafe fn call(&self, state: &mut MultilinearState, event: Event) {
        let event = &self.events[event.0];
        unsafe { event.invoke_action::<From>(&mut state.values) };
        state.update_events(event, self);
    }

    #[inline]
    fn revertables(state: &MultilinearState) -> Self::EventContainer<'_> {
        state.revertables.iter().copied()
    }

    #[inline]
    fn revertable(state: &MultilinearState, event: Event) -> bool {
        state.revertables.contains(&event)
    }

    unsafe fn revert(&self, state: &mut MultilinearState, event: Event) {
        let event = &self.events[event.0];
        unsafe { event.invoke_action::<To>(&mut state.values) };
        state.update_events(event, self);
    }
}

/// Represents an owned simulation for the multilinear system.
pub type MultilinearSimulation = OwnedSimulation<MultilinearInfo>;

/// Represents a borrowed simulation for the multilinear system.
pub type BorrowedMultilinearSimulation<'a> = BorrowedSimulation<'a, MultilinearInfo>;

/// Represents a multi simulation for the multilinear system.
pub type MultiMultilinearSimulation = MultiSimulation<MultilinearInfo>;
