Analyze dependencies of cargo projects
use crate::graph::Node;
use crate::{AnnotationGraph, Measurement};

use charming::{
    element::{ItemStyle, Label},
    series::{TreemapData, TreemapLevel},
};
use petgraph::Direction;

// TODO: reference
const COLORS: [&str; 9] = [
    "#5470c6", "#91cc75", "#fac858", "#ee6666", "#73c0de", "#3ba272", "#fc8452", "#9a60b4",
    "#ea7ccc",
];

pub fn color() -> Vec<String> {
    COLORS
        .iter()
        .map(|color| color.to_string())
        .collect::<Vec<String>>()
}

pub fn data<'graph>(
    annotations: &'graph AnnotationGraph,
    packages: Vec<&'graph Node>,
) -> Vec<TreemapData> {
    let mut treemap_items = Vec::new();

    for node in packages {
        let self_times = node.timings().iter().map(|message| TreemapData {
            value: message.duration,
            id: None,
            name: Some(format!("{:?} {:?}", message.mode, message.target.kind)),
            upper_label: None,
            visual_dimension: None,
            children: vec![],
            children_visible_min: None,
        });

        // Recursively call this function for all direct dependencies
        let direct_dependencies = annotations
            .node_edges(node, Direction::Outgoing)
            .collect::<Vec<_>>();
        let mut children = data(annotations, direct_dependencies);
        children.extend(self_times);

        treemap_items.push(TreemapData {
            value: annotations.variable(
                node,
                crate::Variable::TotalDuration,
                Measurement::Relative,
            ),
            id: None,
            name: Some(node.name().to_string()),
            upper_label: Some(Label::new().show(true)),
            visual_dimension: None,
            children,
            children_visible_min: Some(200_000),
        })
    }

    treemap_items
}

pub fn levels(depth: usize) -> Vec<TreemapLevel> {
    let mut levels = Vec::with_capacity(depth);

    levels.extend([
        TreemapLevel {
            item_style: Some(ItemStyle::new().border_width(1).gap_width(0)),
            upper_label: Some(Label::new().show(false)),
        },
        TreemapLevel {
            item_style: Some(
                ItemStyle::new()
                    .border_color("#777")
                    .border_width(1)
                    .gap_width(0),
            ),
            upper_label: Some(Label::new().show(false)),
        },
    ]);

    while levels.len() < depth {
        levels.push(TreemapLevel {
            item_style: Some(
                ItemStyle::new()
                    .border_width(5)
                    .gap_width(1)
                    .border_color_saturation(0.6),
            ),
            upper_label: None,
        });
    }

    levels
}