use std::io::{BufRead, BufReader, LineWriter, Read, Write};

use itertools::Itertools;

use super::graph::{Graph, Node};

pub fn export_adjacency_list<W>(buffer: W, graph: &Graph) -> std::io::Result<()>
where
    W: Write,
{
    let mut writer = LineWriter::new(buffer);

    for label in 0..graph.len() {
        let mut nbr_iter = graph.get_neighbours(label).iter().copied();
        if let Some(first_nbr) = nbr_iter.next() {
            write!(writer, "{first_nbr}")?;
        }
        for nbr in nbr_iter {
            write!(writer, ",{nbr}")?;
        }
        writeln!(writer)?;
    }

    Ok(())
}

// Export the adjacency list with no duplicate neighbours
pub fn export_adjacency_list_simple<W>(buffer: W, graph: &Graph) -> std::io::Result<()>
where
    W: Write,
{
    let mut writer = LineWriter::new(buffer);

    for label in 0..graph.len() {
        let mut nbr_iter = graph.get_neighbours(label).iter().copied().unique();
        if let Some(first_nbr) = nbr_iter.next() {
            write!(writer, "{first_nbr}")?;
        }
        for nbr in nbr_iter {
            write!(writer, ",{nbr}")?;
        }
        writeln!(writer)?;
    }

    Ok(())
}

// pub fn export_compact_adjacency_list<W>(buffer: W, graph: &GenericGraph) -> std::io::Result<()>
// where
//     W: Write,
// {
//     let mut writer = LineWriter::new(buffer);
//     let mut index_pointer: Vec<usize> = Vec::with_capacity(graph.len() + 1);

//     let mut index = 0;
//     index_pointer.push(0);
//     for label in graph.get_nodes().labels() {
//         for nbr in graph.iter_neighbours(label) {
//             index += 1;
//             writeln!(writer, "{nbr}")?;
//         }
//         index_pointer.push(index);
//     }
//     writeln!(writer, "-------")?;
//     for pointer in index_pointer {
//         writeln!(writer, "{pointer}")?;
//     }

//     Ok(())
// }

/// Does own buffering
pub fn import_adjacency_list<R>(buffer: R) -> std::io::Result<Graph>
where
    R: Read,
{
    let reader = BufReader::new(buffer);
    let mut nodes = Vec::new();
    for line in reader.lines() {
        let line = line?;
        let mut nbrs = Vec::with_capacity(10);
        for nbr in line.split(',').map(|nbr_str| nbr_str.trim().parse()) {
            nbrs.push(nbr.expect("Should be able to parse any entry in adjacency list."));
        }
        nodes.push(Node::new(nbrs));
    }

    Ok(Graph::new(nodes))
}
