use crate::{container_map::ContainerMap, vector::Vector};

use pns::{Pid, Tid};
use text_editing::TextLine;

use std::collections::BTreeMap;

pub struct TextCursor {
    pub row: usize,
    pub column: usize,
}

impl TextCursor {
    pub fn new() -> Self {
        Self { row: 0, column: 0 }
    }

    pub fn line_changer(forward: bool) -> fn(&mut Self, &[TextLine]) -> bool {
        if forward {
            Self::next_line
        } else {
            Self::prev_line
        }
    }

    pub fn next_line(&mut self, lines: &[TextLine]) -> bool {
        if self.row == lines.len() - 1 {
            false
        } else {
            self.row += 1;
            self.column = 0;
            true
        }
    }

    pub fn prev_line(&mut self, lines: &[TextLine]) -> bool {
        if self.row == 0 {
            false
        } else {
            self.row -= 1;
            self.column = lines[self.row].len();
            true
        }
    }
}

pub struct TextContent {
    pub lines: Vec<TextLine>,
    pub cursor: TextCursor,
    pub offset: usize,
}

impl TextContent {
    pub fn new() -> Self {
        Self {
            lines: vec![TextLine::new()],
            cursor: TextCursor::new(),
            offset: 0,
        }
    }
}

pub struct NodeMap<Id, Node> {
    pub map: ContainerMap<Id>,
    pub nodes: BTreeMap<Id, Node>,
}

impl<Id: Copy + Ord, Node> NodeMap<Id, Node> {
    pub fn new() -> Self {
        Self {
            map: ContainerMap::new(),
            nodes: BTreeMap::new(),
        }
    }

    pub fn from_map(nodes: BTreeMap<Id, Node>) -> Self {
        Self {
            map: ContainerMap::from_iter(nodes.keys().cloned()),
            nodes,
        }
    }

    pub fn node(&self, id: Id) -> &Node {
        &self.nodes[&id]
    }

    pub fn node_mut(&mut self, id: Id) -> &mut Node {
        self.nodes.get_mut(&id).unwrap()
    }

    pub fn insert(&mut self, id: Id, node: Node) {
        self.map.insert(id);
        self.nodes.insert(id, node);
    }

    pub fn remove(&mut self, id: Id) -> Option<Node> {
        self.map.remove(id);
        self.nodes.remove(&id)
    }
}

pub struct PlaceNode {
    pub positions: Vec<Vector>,
    pub name: TextLine,
    pub name_cursor: usize,
}

impl PlaceNode {
    pub fn new(positions: &[Vector], name: String) -> Self {
        let name = TextLine::from_string(name.chars().collect());
        let name_cursor = name.len();
        Self {
            positions: positions.iter().cloned().collect::<Vec<_>>(),
            name,
            name_cursor,
        }
    }
}

pub struct TransitionNode {
    pub position: Vector,
    pub name: TextLine,
    pub name_cursor: usize,
    pub content: TextContent,
}

impl TransitionNode {
    pub fn new(position: Vector, name: String) -> Self {
        let name = TextLine::from_string(name.chars().collect());
        let name_cursor = name.len();
        Self {
            position,
            name,
            name_cursor,
            content: TextContent::new(),
        }
    }
}

pub struct NodeContainer {
    places: BTreeMap<Pid, PlaceNode>,
    pub transitions: NodeMap<Tid, TransitionNode>,
}

impl NodeContainer {
    pub fn empty() -> Self {
        Self {
            places: BTreeMap::new(),
            transitions: NodeMap::new(),
        }
    }

    pub fn new(
        places: BTreeMap<Pid, PlaceNode>,
        transitions: BTreeMap<Tid, TransitionNode>,
    ) -> Self {
        Self {
            places,
            transitions: NodeMap::from_map(transitions),
        }
    }

    pub fn place(&self, pid: Pid) -> &PlaceNode {
        &self.places[&pid]
    }

    pub fn place_mut(&mut self, pid: Pid) -> &mut PlaceNode {
        self.places.get_mut(&pid).unwrap()
    }

    pub fn get_place(&self, pid: Pid) -> Option<&PlaceNode> {
        self.places.get(&pid)
    }

    pub fn add_place(&mut self, pid: Pid, node: PlaceNode) {
        self.places.insert(pid, node);
    }

    pub fn remove_place(&mut self, pid: Pid) {
        self.places.remove(&pid);
    }

    pub fn iter_places(
        &self,
    ) -> impl Iterator<Item = (&Pid, &PlaceNode)> + DoubleEndedIterator + ExactSizeIterator {
        self.places.iter()
    }

    pub fn iter_places_mut(
        &mut self,
    ) -> impl Iterator<Item = (&Pid, &mut PlaceNode)> + DoubleEndedIterator + ExactSizeIterator
    {
        self.places.iter_mut()
    }
}
