
use lwleen_rpc::{futures, prelude::*};
// use async_net;
use async_io;
use ipnet;
use local_ip_address::{self,local_ip};
use portpicker;

use std::{
    net::{IpAddr,SocketAddr},
};



#[gen_特征_derive(MOD特征_net)]
impl 信令路由{
    async fn exec文本信令_net(&self,函数名:&str, 参数数组:Vec<String>)-> anyhow_Result<(bool,Value,Vec<String>)>{
        let 信令路由ref = self;
        let 结果 = match 函数名{
            "ip" | "网络_本机ip"=>{            json!(信令路由ref.网络_本机ip().await?)         }
            "port" | "网络_获取空闲端口"=>{     json!(信令路由ref.网络_获取空闲端口().await?)    }
            "网络_判断端口空闲"=>{     
                    if 参数数组.len() < 1 {  return Err(anyhow_err!("网络_判断端口空闲, 缺少参数::  <端口>")) }
                    json!(信令路由ref.网络_判断端口空闲(参数数组[0].parse::<u16>()?).await?) 
            }
            _=>{ return Ok((false, json!(""), 参数数组)); }
        };
        Ok((true, 结果, Vec::new()))
    }

    fn 网络_获取空闲端口(&self)-> impl 信令任务<u16>{                       
        core发布信令任务!(self, 信令表::网络_获取空闲端口,  信令表::网络_获取空闲端口_回复 => 空闲端口 )
    }
    fn 网络_判断端口空闲<T:Into<u16>>(&self,端口:T)-> impl 信令任务<bool>{    
        core发布信令任务!(self, 信令表::网络_判断端口空闲{ 端口:端口.into()  },  信令表::网络_判断端口空闲_回复 => 空闲  )
    }
    fn 网络_本机ip(&self)-> impl 信令任务<本机IP>{            
        core发布信令任务!(self, 信令表::网络_本机ip,  信令表::网络_本机ip_回复 => 本机ip )
    }
    fn 网络_查询局域网内已打开端口的ip数组(&self,端口数组:Vec<u16>)-> impl 信令任务<Vec<SocketAddr>>{     
        core发布信令任务!(self, 信令表::网络_查询局域网内端口ip数组{ 端口数组 },  信令表::网络_查询局域网内端口ip数组_回复 => addr数组 )
    }
}


#[derive(Clone, Serialize, Deserialize)]//可选特征
enum 信令表{
    网络_获取空闲端口,
    网络_获取空闲端口_回复{ 空闲端口:u16 },
    网络_判断端口空闲{     端口:u16     },
    网络_判断端口空闲_回复{ 空闲:bool   },
    网络_本机ip,
    网络_本机ip_回复{      本机ip:本机IP  },

    网络_查询局域网内端口ip数组{       端口数组:Vec<u16>          },
    网络_查询局域网内端口ip数组_回复{  addr数组:Vec<SocketAddr>   },
} 
impl信令特征!(信令表, 执行函数);


async fn 执行函数(信令路由:信令路由,id:信令ID,单个信令:信令表)->anyhow_Result<信令表>{
    match 单个信令{
        信令表::网络_获取空闲端口=>{
            anyhow_Ok信令!(信令表::网络_获取空闲端口_回复 { 空闲端口:网络_选取空闲端口() })
        }
        信令表::网络_判断端口空闲{  端口  }=>{
            anyhow_Ok信令!(信令表::网络_判断端口空闲_回复 { 空闲: 网络_判断端口是否空闲(端口) })
        }
        信令表::网络_本机ip=>{
            anyhow_Ok信令!(信令表::网络_本机ip_回复 { 本机ip:网络_本机ip() })
        }
        信令表::网络_查询局域网内端口ip数组{ 端口数组 }=>{
            let res =  信令路由.pool异步任务(网络_局域网内所有打开端口的_ip数组(端口数组)).await??;
            anyhow_Ok信令!(信令表::网络_查询局域网内端口ip数组_回复 { addr数组:res })
        }
        _ =>{ return Err(anyhow_err!("信令不存在")); }
    }
}






pub fn 网络_判断端口是否空闲(port:u16)->bool{  portpicker::is_free(port)    }
pub fn 网络_选取空闲端口()->u16{  portpicker::pick_unused_port().unwrap_or(0)  }
pub fn 网络_本机ip()-> 本机IP {   //    std::net::Ipv4Addr::new(127, 0, 0, 1)       std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1) 
    本机IP{
        ipv4:local_ip_address::local_ip().unwrap_or(IpAddr::V4(std::net::Ipv4Addr::LOCALHOST)), 
        ipv6:local_ip_address::local_ipv6().unwrap_or(IpAddr::V6(std::net::Ipv6Addr::LOCALHOST)), 
    }
}
/// - 展开
/// 例如 192.168.1.1  -> [ 192.168.1.1, ... ... , 192.168.1.254]
/// ipv6 只取自身
pub fn 网络_所有局域网内ip数组()->anyhow_Result<Vec<IpAddr>>{
    let mut num = 0;
    let mut ip数组 = Vec::new(); 
    let 本地ip = 网络_本机ip();
    let subnet = ipnet::IpNet::new(本地ip.ipv4, 24)?;     //ipv6长度32   表示子主机254个
    for ip in subnet.hosts() {  
        ip数组.push(ip); num+=1;
        if ip.to_string() == "127.0.0.1"{break;}
    }
    let subnet = ipnet::IpNet::new(本地ip.ipv6, 128)?;    //ipv6长度128  表示子主机自身一个
    for ip in subnet.hosts() {  
        ip数组.push(ip); num+=1;
        if num>500 || ip.to_string() == "::1"  {break;}
    }
    Ok(ip数组)
}

pub async fn 网络_局域网内所有打开端口的_ip数组(端口数组:Vec<u16>)->anyhow_Result<Vec<SocketAddr>>{
    let 局域网内ip数组 = 网络_所有局域网内ip数组()?;
    Ok(网络_过滤已打开端口_ip数组(端口数组, 局域网内ip数组).await)
}

pub async fn 网络_过滤已打开端口_ip数组(端口数组:Vec<u16> ,ip数组:Vec<IpAddr>)->Vec<SocketAddr>{
    // use rustscan;
    // // let addrs:Vec<std::net::IpAddr> = ip数组.iter().map(|ip|{ ip.parse::<std::net::IpAddr>().unwrap() }).collect();
    // let range = rustscan::input::PortRange { start: 445,  end: 445,   };
    // let strategy = rustscan::port_strategy::PortStrategy::pick(&Some(range), None, rustscan::input::ScanOrder::Random);
    // let 端口扫描器 = rustscan::scanner::Scanner::new(
    //     &ip数组,
    //     50,
    //     std::time::Duration::from_millis(10),
    //     1,
    //     true,
    //     rustscan::port_strategy::PortStrategy::Manual(端口数组),
    //     true,
    //     Vec::new(), //排除端口
    //     false,
    // );
    // let 最终可用 =  端口扫描器.run().await;  // let 数组: Vec<String> =  结果.iter().map(|addr|{ addr.ip().to_string() }).collect();
    // 最终可用


    let mut 并行任务 = futures::stream::FuturesUnordered::new();
    ip数组.iter().for_each(|ip|{  
        端口数组.iter().for_each(|port|{
            let addr地址 = SocketAddr::new(ip.to_owned(), *port);
            并行任务.push(async move{
                if let Ok(Ok(tcp流)) = async_io::Async::<std::net::TcpStream>::connect(addr地址)
                                .timeout(std::time::Duration::from_millis(100)).await {
                    tcp流.get_ref().shutdown(std::net::Shutdown::Both).ok();
                    Some(addr地址)
                }else { None }
                
                // // UDP 测试
                // match async_net::UdpSocket::bind(socket).await{
                //     Ok(udp_socket) => {
                //         udp_socket.connect(socket).await?;
                //         udp_socket.send(payload).await?;
                //         let mut buf = [0u8; 1024];
                //         udp_socket.recv(&mut buf).timeout(duration).await
                //     }
                // }

            });
        });
    });
    use lwleen_rpc::futures::stream::StreamExt;
    let mut 最终可用:Vec<SocketAddr> = Vec::new();
    while let Some(Some(res))  = 并行任务.next().await {
        最终可用.push(res);
    }
    最终可用
}




#[cfg(test)]
mod  测试{
    use crate::prelude::*;
    use crate::prelude::*;

    #[cfg(all(test,feature = "mod_net"))]
    #[test]
    fn 测试1(){
        let now = std::time::Instant::now();
        // 🔥🔥🔥 js child_process.spawn 调用二进制，必须带有  process.env  ，否则报错🔥🔥🔥
        let 信令路由 =  信令路由::default();
        let 信令路由c1 = 信令路由.clone();
        信令路由.pool异步任务_block阻塞完成(async move{
            let out1 = 信令路由c1.网络_查询局域网内已打开端口的ip数组(vec![445]).await; 
            println!("返回结果: {}毫秒  {out1:?}",now.elapsed().as_millis() );
        }).ok();
    }

}





#[derive(Clone,Debug, Serialize, Deserialize)]
pub struct 本机IP{
    pub ipv4:IpAddr,
    pub ipv6:IpAddr,
}