use cross_socket::datalink::MacAddr;
use std::net::{IpAddr, Ipv4Addr};
use std::time::Duration;
use cross_socket::packet::tcp::TcpOption;
pub(crate) const LISTENER_WAIT_TIME_MILLIS: u64 = 100;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ProbeType {
    IcmpEchoProbe,
    IcmpTimestampProbe,
    IcmpAddressMaskProbe,
    IcmpInformationProbe,
    IcmpUnreachableProbe,
    TcpProbe,
    TcpSynAckProbe,
    TcpRstAckProbe,
    TcpEcnProbe,
}
#[derive(Clone, Copy, Debug)]
pub enum TcpOptionKind {
    Eol,
    Nop,
    Mss,
    Wscale,
    SackParmitted,
    Sack,
    Timestamp,
}
impl TcpOptionKind {
    pub fn number(&self) -> u8 {
        match *self {
            TcpOptionKind::Eol => 0,
            TcpOptionKind::Nop => 1,
            TcpOptionKind::Mss => 2,
            TcpOptionKind::Wscale => 3,
            TcpOptionKind::SackParmitted => 4,
            TcpOptionKind::Sack => 5,
            TcpOptionKind::Timestamp => 8,
        }
    }
    pub fn name(&self) -> String {
        match *self {
            TcpOptionKind::Eol => String::from("EOL"),
            TcpOptionKind::Nop => String::from("NOP"),
            TcpOptionKind::Mss => String::from("MSS"),
            TcpOptionKind::Wscale => String::from("WSCALE"),
            TcpOptionKind::SackParmitted => String::from("SACK_PERMITTED"),
            TcpOptionKind::Sack => String::from("SACK"),
            TcpOptionKind::Timestamp => String::from("TIMESTAMPS"),
        }
    }
}
#[derive(Clone, Debug)]
pub struct ProbeTarget {
    pub ip_addr: IpAddr,
    pub open_tcp_port: u16,
    pub closed_tcp_port: u16,
    pub open_udp_port: u16,
    pub closed_udp_port: u16,
}
impl ProbeTarget {
    pub fn new() -> Self {
        Self {
            ip_addr: IpAddr::V4(Ipv4Addr::LOCALHOST),
            open_tcp_port: 80,
            closed_tcp_port: 20,
            open_udp_port: 53,
            closed_udp_port: 33435,
        }
    }
}
#[derive(Clone, Debug)]
pub struct ProbeSetting {
    pub if_index: u32,
    pub if_name: String,
    pub src_mac: MacAddr,
    pub dst_mac: MacAddr,
    pub src_ip: IpAddr,
    pub src_port: u16,
    pub probe_target: ProbeTarget,
    pub probe_types: Vec<ProbeType>,
    pub timeout: Duration,
    pub wait_time: Duration,
    pub send_rate: Duration,
    pub use_tun: bool,
    pub loopback: bool,
}
#[derive(Copy, Clone, Debug)]
pub enum TcpProbeKind {
    Syn1,
    Syn2,
    Syn3,
    Syn4,
    Syn5,
    Syn6,
    Ecn,
}
impl TcpProbeKind {
    pub const VALUES: [Self; 7] = [
        Self::Syn1,
        Self::Syn2,
        Self::Syn3,
        Self::Syn4,
        Self::Syn5,
        Self::Syn6,
        Self::Ecn,
    ];
    pub fn ipv4_total_length(&self) -> u16 {
        match *self {
            TcpProbeKind::Syn1 => 60,
            TcpProbeKind::Syn2 => 60,
            TcpProbeKind::Syn3 => 60,
            TcpProbeKind::Syn4 => 56,
            TcpProbeKind::Syn5 => 60,
            TcpProbeKind::Syn6 => 56,
            TcpProbeKind::Ecn => 52,
        }
    }
    pub fn ipv6_payload_length(&self) -> u16 {
        match *self {
            TcpProbeKind::Syn1 => 40,
            TcpProbeKind::Syn2 => 40,
            TcpProbeKind::Syn3 => 40,
            TcpProbeKind::Syn4 => 36,
            TcpProbeKind::Syn5 => 40,
            TcpProbeKind::Syn6 => 36,
            TcpProbeKind::Ecn => 32,
        }
    }
    pub fn tcp_options(&self) -> Vec<TcpOption> {
        match *self {
            TcpProbeKind::Syn1 => vec![
                TcpOption::wscale(10),
                TcpOption::nop(),
                TcpOption::mss(1460),
                TcpOption::timestamp(u32::MAX, u32::MIN),
                TcpOption::sack_perm(),
            ],
            TcpProbeKind::Syn2 => vec![
                TcpOption::mss(1400),
                TcpOption::wscale(0),
                TcpOption::sack_perm(),
                TcpOption::timestamp(u32::MAX, u32::MIN),
            ],
            TcpProbeKind::Syn3 => vec![
                TcpOption::timestamp(u32::MAX, u32::MIN),
                TcpOption::nop(),
                TcpOption::nop(),
                TcpOption::wscale(5),
                TcpOption::nop(),
                TcpOption::mss(640),
            ],
            TcpProbeKind::Syn4 => vec![
                TcpOption::sack_perm(),
                TcpOption::timestamp(u32::MAX, u32::MIN),
                TcpOption::wscale(10),
            ],
            TcpProbeKind::Syn5 => vec![
                TcpOption::mss(536),
                TcpOption::sack_perm(),
                TcpOption::timestamp(u32::MAX, u32::MIN),
                TcpOption::wscale(10),
            ],
            TcpProbeKind::Syn6 => vec![
                TcpOption::mss(265),
                TcpOption::sack_perm(),
                TcpOption::timestamp(u32::MAX, u32::MIN),
            ],
            TcpProbeKind::Ecn => vec![
                TcpOption::wscale(10),
                TcpOption::nop(),
                TcpOption::mss(1460),
                TcpOption::sack_perm(),
                TcpOption::nop(),
                TcpOption::nop(),
            ],
        }
    }
}