use wot_network::Certificate;

use crate::types::{certification::Certification, edges::PathEdge};

/// A Path starts from an anchoring [Certificate] and consists of a list of delegation and reverse
/// edges which lead to a target identity binding.
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
pub(crate) struct Path {
    /// The trust amount that is provided by this path.
    pub trust_amount: u8,
    /// The trust anchor that's used as the start of this path.
    pub trust_anchor: Certificate,
    /// The edges from the trust_amount towards the target binding.
    pub edges: Vec<PathEdge>,
    /// The target binding whose lookup table allows us to easily determine whether a reverse
    /// edge is in the path or not.
    pub certification: Certification,
}

impl Path {
    // The total length of the path (i.e. the number of edges).
    #[allow(clippy::len_without_is_empty)]
    pub fn len(&self) -> usize {
        self.edges.len() + 1
    }

    /// Returns a simplified string representation of the path for debugging purposes.
    pub fn simple_display(&self) -> String {
        let mut output = String::new();
        output.push_str(&format!("{}", self.trust_anchor));
        for edge in &self.edges {
            match edge {
                PathEdge::ReverseEdge(reverse_edge) => {
                    output.push_str(&format!(" ┄⇢ {}", reverse_edge.target))
                }
                PathEdge::ForwardEdge(delegation) => {
                    output.push_str(&format!(" → {}", delegation.target()))
                }
            }
        }

        output.push_str(&format!(
            " ⇒ ({}, {})",
            self.certification.inner.target_cert(),
            self.certification.inner.target_id(),
        ));

        output
    }

    /// Same as [`Self::simple_display`], but without the trust anchor.
    ///
    /// Useful for visualizing the path from the first edge onward.
    pub fn simple_display_without_anchor(&self) -> String {
        let mut output = String::new();
        let mut edges_iter = self.edges.iter().peekable();
        if let Some(first_edge) = edges_iter.peek() {
            output.push_str(&format!("{}", first_edge.issuer()))
        }
        for edge in &self.edges {
            match edge {
                PathEdge::ReverseEdge(reverse_edge) => {
                    output.push_str(&format!(" ┄⇢ {}", reverse_edge.target))
                }
                PathEdge::ForwardEdge(delegation) => {
                    output.push_str(&format!(" → {}", delegation.target()))
                }
            }
        }

        output.push_str(&format!(
            " ⇒ ({}, {})",
            self.certification.inner.target_cert(),
            self.certification.inner.target_id(),
        ));

        output
    }

    /// Same as [`Self::simple_display`], but without the target node.
    ///
    /// Useful for visualizing the path up to, but not including, the target binding.
    pub fn simple_display_without_target(&self) -> String {
        let mut output = String::new();
        output.push_str(&format!("{}", self.trust_anchor));
        for edge in &self.edges {
            match edge {
                PathEdge::ReverseEdge(reverse_edge) => {
                    output.push_str(&format!(" ┄⇢ {}", reverse_edge.target))
                }
                PathEdge::ForwardEdge(delegation) => {
                    output.push_str(&format!(" → {}", delegation.target()))
                }
            }
        }

        output
    }
}
