#![warn(missing_docs)]
use std::collections::BTreeSet;
use std::fmt::Debug;
use std::iter::FusedIterator;
use serde::{Deserialize, Serialize};
use slotmap::{Key, SecondaryMap, SlotMap};
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(from = "EdgeList<V, E>", into = "EdgeList<V, E>")]
pub struct DiMulGraph<V, E>
where
    V: Key,
    E: Key,
{
    edges: SlotMap<E, (V, V)>,
    succs: SecondaryMap<V, Vec<E>>,
    preds: SecondaryMap<V, Vec<E>>,
}
impl<V, E> Default for DiMulGraph<V, E>
where
    V: Key,
    E: Key,
{
    fn default() -> Self {
        let (edges, succs, preds) = Default::default();
        Self {
            edges,
            succs,
            preds,
        }
    }
}
impl<V, E> DiMulGraph<V, E>
where
    V: Key,
    E: Key,
{
    pub fn new() -> Self {
        Default::default()
    }
    pub fn with_capacity(capacity: usize) -> Self {
        Self {
            edges: SlotMap::with_capacity_and_key(capacity),
            succs: SecondaryMap::with_capacity(capacity),
            preds: SecondaryMap::with_capacity(capacity),
        }
    }
    pub fn assert_valid(&self) {
        for (edge_id, &(src, dst)) in self.edges.iter() {
            assert!(self.succs[src].contains(&edge_id));
            assert!(self.preds[dst].contains(&edge_id));
        }
        for succ_list in self.succs.values() {
            let set: BTreeSet<&E> = succ_list.iter().collect();
            assert_eq!(set.len(), succ_list.len());
        }
        for pred_list in self.succs.values() {
            let set: BTreeSet<&E> = pred_list.iter().collect();
            assert_eq!(set.len(), pred_list.len());
        }
        assert_eq!(
            self.edges.len(),
            self.succs.values().map(|vec| vec.len()).sum::<usize>(),
            "succs broken (contains duplicate or removed edge?)"
        );
        assert_eq!(
            self.edges.len(),
            self.preds.values().map(|vec| vec.len()).sum::<usize>(),
            "preds broken (contains duplicate or removed edge?)"
        );
    }
    fn get_adj_edges(adj_list: &mut SecondaryMap<V, Vec<E>>, v: V) -> &mut Vec<E> {
        if !adj_list.contains_key(v) {
            adj_list.insert(v, Default::default());
        }
        &mut adj_list[v]
    }
    pub fn insert_edge(&mut self, src: V, dst: V) -> E {
        let e = self.edges.insert((src, dst));
        Self::get_adj_edges(&mut self.succs, src).push(e);
        Self::get_adj_edges(&mut self.preds, dst).push(e);
        e
    }
    pub fn insert_intermediate_vertex(&mut self, new_vertex: V, edge: E) -> Option<(E, E)> {
        self.assert_valid();
        let (src, dst) = self.edges.remove(edge)?;
        let e0 = self.edges.insert((src, new_vertex));
        let e1 = self.edges.insert((new_vertex, dst));
        let succ_vec_idx = self.succs[src].iter().position(|&e| e == edge).unwrap();
        let pred_vec_idx = self.preds[dst].iter().position(|&e| e == edge).unwrap();
        assert_eq!(
            edge,
            std::mem::replace(&mut self.succs[src][succ_vec_idx], e0)
        );
        assert_eq!(
            edge,
            std::mem::replace(&mut self.preds[dst][pred_vec_idx], e1)
        );
        assert!(
            self.preds.insert(new_vertex, vec![e0]).is_none(),
            "Cannot insert intermediate vertex that already exists"
        );
        assert!(
            self.succs.insert(new_vertex, vec![e1]).is_none(),
            "Cannot insert intermediate vertex that already exists"
        );
        self.assert_valid();
        Some((e0, e1))
    }
    pub fn remove_intermediate_vertex(&mut self, vertex: V) -> Option<(E, (E, E))> {
        let preds = self.preds.remove(vertex)?;
        let &[pred_edge] = &*preds else {
            return None;
        };
        let succs = self.succs.remove(vertex).unwrap();
        let &[succ_edge] = &*succs else {
            return None;
        };
        let (src, _v) = self.edges.remove(pred_edge).unwrap();
        let (_v, dst) = self.edges.remove(succ_edge).unwrap();
        self.succs[src].retain(|&e| e != pred_edge);
        self.preds[dst].retain(|&e| e != succ_edge);
        let new_edge = self.insert_edge(src, dst);
        Some((new_edge, (pred_edge, succ_edge)))
    }
    pub fn remove_edge(&mut self, e: E) -> Option<(V, V)> {
        let (src, dst) = self.edges.remove(e)?;
        self.succs[src].retain(|x| *x != e);
        self.preds[dst].retain(|x| *x != e);
        Some((src, dst))
    }
    pub fn remove_vertex(&mut self, v: V) {
        assert!(self.preds[v].is_empty() && self.succs[v].is_empty());
        self.preds.remove(v);
        self.succs.remove(v);
    }
    pub fn edge(&self, e: E) -> Option<(V, V)> {
        self.edges.get(e).copied()
    }
    pub fn edge_ids(&self) -> slotmap::basic::Keys<E, (V, V)> {
        self.edges.keys()
    }
    pub fn edges(
        &self,
    ) -> impl '_ + ExactSizeIterator<Item = (E, (V, V))> + FusedIterator + Clone + Debug {
        self.edges.iter().map(|(e, &(src, dst))| (e, (src, dst)))
    }
    pub fn successor_edges(&self, v: V) -> std::iter::Copied<std::slice::Iter<'_, E>> {
        self.succs
            .get(v)
            .map(|v| v.iter())
            .unwrap_or_else(|| [].iter())
            .copied()
    }
    pub fn predecessor_edges(&self, v: V) -> std::iter::Copied<std::slice::Iter<'_, E>> {
        self.preds
            .get(v)
            .map(|v| v.iter())
            .unwrap_or_else(|| [].iter())
            .copied()
    }
    pub fn successor_vertices(
        &self,
        v: V,
    ) -> impl '_ + DoubleEndedIterator<Item = V> + ExactSizeIterator + FusedIterator + Clone + Debug
    {
        self.successor_edges(v).map(|edge_id| self.edges[edge_id].1)
    }
    pub fn predecessor_vertices(
        &self,
        v: V,
    ) -> impl '_ + DoubleEndedIterator<Item = V> + ExactSizeIterator + FusedIterator + Clone + Debug
    {
        self.predecessor_edges(v)
            .map(|edge_id| self.edges[edge_id].0)
    }
    pub fn successors(
        &self,
        v: V,
    ) -> impl '_ + DoubleEndedIterator<Item = (E, V)> + ExactSizeIterator + FusedIterator + Clone + Debug
    {
        self.successor_edges(v)
            .map(|edge_id| (edge_id, self.edges[edge_id].1))
    }
    pub fn predecessors(
        &self,
        v: V,
    ) -> impl '_ + DoubleEndedIterator<Item = (E, V)> + ExactSizeIterator + FusedIterator + Clone + Debug
    {
        self.predecessor_edges(v)
            .map(|edge_id| (edge_id, self.edges[edge_id].0))
    }
    pub fn degree_out(&self, v: V) -> usize {
        self.succs.get(v).map(Vec::len).unwrap_or_default()
    }
    pub fn degree_in(&self, v: V) -> usize {
        self.preds.get(v).map(Vec::len).unwrap_or_default()
    }
}
impl<V, E> From<DiMulGraph<V, E>> for EdgeList<V, E>
where
    V: Key,
    E: Key,
{
    fn from(value: DiMulGraph<V, E>) -> Self {
        value.edges
    }
}
impl<V, E> From<EdgeList<V, E>> for DiMulGraph<V, E>
where
    V: Key,
    E: Key,
{
    fn from(edges: EdgeList<V, E>) -> Self {
        let mut out = Self {
            edges,
            ..Default::default()
        };
        for (edge, &(src, dst)) in out.edges.iter() {
            out.succs.entry(src).unwrap().or_default().push(edge);
            out.preds.entry(dst).unwrap().or_default().push(edge);
        }
        out
    }
}
#[expect(type_alias_bounds, reason = "code readability")]
pub type EdgeList<V, E>
where
    V: Key,
    E: Key,
= SlotMap<E, (V, V)>;