use super::*;
use cursive_table_view::*;
use std::cmp::Ordering;
use veilid_core::PeerTableData;

#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum PeerTableColumn {
    NodeId,
    Address,
    LatencyAvg,
    TransferDownAvg,
    TransferUpAvg,
}

// impl PeerTableColumn {
//     fn as_str(&self) -> &str {
//         match self {
//             PeerTableColumn::NodeId => "Node Id",
//             PeerTableColumn::Address => "Address",
//             PeerTableColumn::LatencyAvg => "Latency",
//             PeerTableColumn::TransferDownAvg => "Down",
//             PeerTableColumn::TransferUpAvg => "Up",
//         }
//     }
// }

fn format_ts(ts: u64) -> String {
    let secs = timestamp_to_secs(ts);
    if secs >= 1.0 {
        format!("{:.2}s", timestamp_to_secs(ts))
    } else {
        format!("{:.2}ms", timestamp_to_secs(ts) * 1000.0)
    }
}

fn format_bps(bps: u64) -> String {
    if bps >= 1024u64 * 1024u64 * 1024u64 {
        format!("{:.2}GB/s", (bps / (1024u64 * 1024u64)) as f64 / 1024.0)
    } else if bps >= 1024u64 * 1024u64 {
        format!("{:.2}MB/s", (bps / 1024u64) as f64 / 1024.0)
    } else if bps >= 1024u64 {
        format!("{:.2}KB/s", bps as f64 / 1024.0)
    } else {
        format!("{:.2}B/s", bps as f64)
    }
}

impl TableViewItem<PeerTableColumn> for PeerTableData {
    fn to_column(&self, column: PeerTableColumn) -> String {
        match column {
            PeerTableColumn::NodeId => self.node_id.encode(),
            PeerTableColumn::Address => format!(
                "{:?}:{}",
                self.peer_address.protocol_type(),
                self.peer_address.to_socket_addr()
            ),
            PeerTableColumn::LatencyAvg => format!(
                "{}",
                self.peer_stats
                    .latency
                    .as_ref()
                    .map(|l| format_ts(l.average))
                    .unwrap_or("---".to_owned())
            ),
            PeerTableColumn::TransferDownAvg => format_bps(self.peer_stats.transfer.down.average),
            PeerTableColumn::TransferUpAvg => format_bps(self.peer_stats.transfer.up.average),
        }
    }

    fn cmp(&self, other: &Self, column: PeerTableColumn) -> Ordering
    where
        Self: Sized,
    {
        match column {
            PeerTableColumn::NodeId => self.node_id.cmp(&other.node_id),
            PeerTableColumn::Address => self.to_column(column).cmp(&other.to_column(column)),
            PeerTableColumn::LatencyAvg => self
                .peer_stats
                .latency
                .as_ref()
                .map(|l| l.average)
                .cmp(&other.peer_stats.latency.as_ref().map(|l| l.average)),
            PeerTableColumn::TransferDownAvg => self
                .peer_stats
                .transfer
                .down
                .average
                .cmp(&other.peer_stats.transfer.down.average),
            PeerTableColumn::TransferUpAvg => self
                .peer_stats
                .transfer
                .up
                .average
                .cmp(&other.peer_stats.transfer.up.average),
        }
    }
}

pub type PeersTableView = TableView<PeerTableData, PeerTableColumn>;
