pub(crate) mod ingest;

pub(crate) use ingest::IngestableEvents;

use std::{cmp::Reverse, collections::BinaryHeap};

use crate::{Jiffies, MessagePtr, Pid, TimerId, random::Seed};

#[derive(Debug)]
pub(crate) enum MessageState {
    Init,
    AwaitLatency,
    AwaitSendBandwidth,
    AwaitRecvBandwidth,
}

#[derive(Debug)]
pub(crate) enum Event {
    Fault(FaultEvent),
    Pid { pid: Pid, event: PidEvent },
}

#[derive(Debug)]
pub(crate) enum FaultEvent {
    BreakLink { pid1: Pid, pid2: Pid },
    RestoreLink { pid1: Pid, pid2: Pid },
    Isolate { pid: Pid },
    FinishIsolation { pid: Pid },
}

#[derive(Debug)]
pub(crate) enum PidEvent {
    Start {
        base_seed: Seed,
    },
    Message {
        source: Pid,
        message: MessagePtr,
        state: MessageState,
    },
    Timer {
        id: TimerId,
    },
}

#[derive(Debug)]
pub(crate) struct TimedEvent {
    pub(crate) invocation_time: Jiffies,
    pub(crate) event: Event,
}

impl PartialEq for TimedEvent {
    fn eq(&self, other: &Self) -> bool {
        self.invocation_time.eq(&other.invocation_time)
    }
}

impl Eq for TimedEvent {}

impl PartialOrd for TimedEvent {
    fn ge(&self, other: &Self) -> bool {
        self.invocation_time.ge(&other.invocation_time)
    }
    fn le(&self, other: &Self) -> bool {
        self.invocation_time.le(&other.invocation_time)
    }
    fn gt(&self, other: &Self) -> bool {
        self.invocation_time.gt(&other.invocation_time)
    }
    fn lt(&self, other: &Self) -> bool {
        self.invocation_time.lt(&other.invocation_time)
    }
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.invocation_time.partial_cmp(&other.invocation_time)
    }
}

impl Ord for TimedEvent {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.invocation_time.cmp(&other.invocation_time)
    }
}

pub(crate) type EventQueue = BinaryHeap<Reverse<TimedEvent>>;
