
use salvo::{
    prelude::*,
    websocket::{Message, WebSocket, WebSocketUpgrade},
    basic_auth::{ BasicAuthValidator },
    serve_static::StaticDir,
    conn::rustls::{Keycert, RustlsConfig},
    catch_panic::CatchPanic,
    catcher::Catcher,
    // cors::Cors,
    // http::Method,
    // routing::filters,
};

use lwleen_rpc::{ serde_json,futures::{self, StreamExt,FutureExt } };   //引入特征
use super::*;
use super::web::*;

use crate::app_exec文本信令;
use crate::prelude::*;
use async_compat::{Compat, CompatExt};





/// ## 完整 路由handler 写法
///  - 示例,  `#[handler]`  是一个特征, 不想有 fn handle()方法
/// ```no_run
/// let 设置共享数据 = 路由共享数据::new(服务器.clone(),"/socket监听地址_后台管理",vec![]);
/// let router = Router::new()
///      .path("/socket监听地址_后台管理")  
///      .hoop(设置共享数据)       //这种等效于 下面 affix_state::inject
///     ;
/// ```
#[derive(Clone)]
pub struct 路由共享数据{
    WEB服务器:WEB服务器,
    相对路径:String,
    根路径数组:Vec<String>,
}
#[handler]
impl 路由共享数据{
    // #[handler] 必须对应这个实现
    async fn handle(&self, req: &mut Request,depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl ){
        // let 共享数据 = depot.get::<路由共享数据>("路由共享数据").unwrap().clone();
        if !depot.contains_key("路由共享数据"){  depot.insert("路由共享数据", self.clone()); }
    }
    pub fn new<T:AsRef<str>>(WEB服务器:WEB服务器, 相对路径:T, 根路径数组:Vec<String>)->Self{
        Self{ 相对路径:相对路径.as_ref().to_string(),根路径数组,WEB服务器 }
    }
    pub async fn get所有服务器信息(&self)->(Vec<WEB服务器信息>, String){
        let 所有服务器信息 = self.WEB服务器.信令路由.WEB服务器_查询().await.ok().unwrap_or_default();
        let url = format!("{协议头}://{ip}:{端口}",协议头 = self.WEB服务器.协议头, ip = self.WEB服务器.ip, 端口 = self.WEB服务器.端口);
        (所有服务器信息, url)
    }
}









#[derive(Clone)]
pub struct 服务器DATA{
    WEB服务器:WEB服务器,
    相对路径:String,
    根路径数组:Vec<String>,
}
impl 服务器DATA{
    pub fn new<T:AsRef<str>>(WEB服务器:WEB服务器, 相对路径:T, 根路径数组:Vec<String>)->Self{
        Self{ 相对路径:相对路径.as_ref().to_string(),根路径数组,WEB服务器 }
    }
    pub async fn get所有服务器信息(&self)->(Vec<WEB服务器信息>, String){
        let 所有服务器信息 = self.WEB服务器.信令路由.WEB服务器_查询().await.ok().unwrap_or_default();
        let url = format!("{协议头}://{ip}:{端口}",协议头 = self.WEB服务器.协议头, ip = self.WEB服务器.ip, 端口 = self.WEB服务器.端口);
        (所有服务器信息, url)
    }
}










pub async fn loop_Li文件浏览器(服务器:WEB服务器){
    //https://salvo.rs/zh-hans/book/topics/send-file.html#serve-static
    let 信令路由 = 服务器.信令路由.clone();
    let web_id = 服务器.web_id;

    let 生成路由服务 = {
        let mut router = Router::new().hoop(CatchPanic::new());  
        
        // 🔥 socket监听  post监听  普通路径监听
        { 
            router = router.push(Router::new()
                .path("/socket监听地址_后台管理")      //监听  socket  地址
                .hoop(affix_state::inject(服务器DATA::new(服务器.clone(),"/socket监听地址_后台管理",vec![])))       
                .goal( WEB_SOCKET连接_后台管理 ));
            
            router = router.push(Router::new()
                .path("/post监听地址_后台管理")         //监听  post  地址
                .hoop(affix_state::inject(服务器DATA::new(服务器.clone(),"/post监听_后台管理",vec![])))       
                .hoop(WEB_POST_自由开放信令)
                .hoop(BasicAuth::new(POST_Validator验证密码))                        //会自动弹出密码窗口
                .post( WEB_POST_后台加密信令 ));
            
            if let Some(路由表) = 服务器.路由表.as_ref(){
                for (相对路径, 根路径数组) in 路由表{
                    let 根路径数组 = 根路径数组.iter().map(|路径|{ 路径.trim_start_matches("file://").to_string()  }).collect::<Vec<_>>();
                    eprintln!("\x1b[32m➜\x1b[0m  rust_Network: \x1b[36m{}://{}:{}{相对路径}\x1b[0m  {根路径数组:?}", &服务器.协议头, &服务器.ip ,&服务器.端口 ); 
                    
                    router = router.unshift(Router::new()
                                                        .path( format!("{相对路径}{{**rest_path}}") )  //  ===>   /lwleen-vitepress/<**path>
                                                        .hoop(affix_state::inject(服务器DATA::new(服务器.clone(),相对路径,根路径数组.clone())))         
                                                        .hoop( 重定向页面 )
                                                        .get(  StaticDir::new(根路径数组) .defaults("index.html")  .auto_list(true)   ));
                
                }
            }
        }
        
        //----------- 跨域控制 CORS --------------
        // let cors = Cors::new()
        //     .allow_origin(["http://127.0.0.1:5800", "http://localhost:5800"])
        //     .allow_methods(vec![Method::GET, Method::POST, Method::DELETE])
        //     .allow_headers("authorization")
        //     .into_handler();

        // 🔥 优先级最低   最后匹配不到时,打开 默认后台404页面     
        Service::new(router)
            .catcher(  
                    Catcher::default()
                        .hoop(affix_state::inject(服务器DATA::new(服务器.clone(),"/默认后台404页面",vec![])))       
                        .hoop(默认后台404页面)  
            ) 
            //.hoop(cors)
    };
    
    
    { *服务器.状态.lock() = 服务器状态::正常; }
    if 服务器.协议头 == "https" {
        let mut tls = None;
        if let Some(tls证书) = 服务器.tls证书{
            if tls证书.len() == 2 {
                if let (Ok(reak_cert),Ok(reak_key)) = join!(信令路由.文件_读(&tls证书[0]), 信令路由.文件_读(&tls证书[1])){  
                    tls = Some(Keycert::new().cert(reak_cert).key(reak_key));
                }
            }
        };
        if tls.is_none() {  tls = Some(Keycert::new().cert(include_bytes!("./https证书/cert.pem").to_vec()).key(include_bytes!("./https证书/key.pem").to_vec()));  } 
        
        let config = RustlsConfig::new(tls.unwrap());
        let 地址 = format!("{}:{}",&服务器.ip, 服务器.端口);
        // http2
        // let acceptor = TcpListener::new( 地址 ).rustls(config).bind().await;
        // 启动同时支持 HTTP/3 (QUIC) 和 HTTPS (TCP) 的服务器
        let acceptor = QuinnListener::new(config.clone().build_quinn_config().unwrap(), 地址.clone())
                            .join(TcpListener::new(地址 ).rustls(config) )
                            .bind().await;
        let server  = Server::new(acceptor);
        *服务器.server_handle.lock() = Some(server.handle());
        server.serve(生成路由服务).await;           //loop无限循环   启动运行服务器 
    }
    else{
        let acceptor = TcpListener::new( format!("{}:{}",服务器.ip, 服务器.端口) ).bind().await;
        let server  = Server::new(acceptor);
        *服务器.server_handle.lock() = Some(server.handle());
        server.serve(生成路由服务).await;           //loop无限循环   启动运行服务器  
    };
    
    { *服务器.状态.lock() = 服务器状态::已停止; }
    信令路由.emit_WEB服务器_已退出(web_id, "服务器结束");
}




//------------------ 内部实现 ---------------------
 
#[handler]
pub async fn 重定向页面(req: &mut Request,depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
    let 共享数据 = depot.obtain::<服务器DATA>().unwrap();
    let 请求相对路径 = 信令路由::fn_decodeURI(&req.uri().path()).unwrap_or_default().to_string();  //  ==   共享数据.相对路径
    
    if 共享数据.根路径数组.len() >0 && (共享数据.根路径数组[0].starts_with("http://") || 共享数据.根路径数组[0].starts_with("https://")){
        let  定向路径 = &共享数据.根路径数组[0];
        res.render(Redirect::found(定向路径));
        eprintln!("\x1b[1;35m rust服务器重定向: {相对路径}\x1b[0m   {all_path:?} \x1b[1;32m => {定向路径}\x1b[0m", 相对路径 = &共享数据.相对路径 , all_path = req.params()  );
        ctrl.skip_rest();  //结束
    }
}

#[handler]
pub async fn  WEB_SOCKET连接_后台管理(req: &mut Request,depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl)  -> Result<(), StatusError>  {
    let 共享数据 = depot.obtain::<服务器DATA>().unwrap();
    let 信令路由c1 = 共享数据.WEB服务器.信令路由.clone();
    
    WebSocketUpgrade::new()
        .upgrade(req, res, | ws| async move { 
            let 信令路由c2 = 信令路由c1.clone();
            let (mut user_tx_sink, mut user_rx_stream) = ws.split();
            
            let (tx发送信令,rx接收信令) = async_unbounded::<Message>();
            // let rx等待发送信令流 = tokio_stream::wrappers::UnboundedReceiverStream::new(rx接收信令);
            // // forward 将结果 Result<> 转发到其他通道：user_ws_tx
            // let fut发送任务流 = rx等待发送信令流.forward(user_tx_sink).map(|result| {
            //     if let Err(e) = result {
            //         eprintln!("🍁salvo_WEB_SOCKET 发送数据错误：：  {e}");  
            //     }
            // });
            // tokio::task::spawn(fut发送任务流);
            
            use lwleen_rpc::futures::SinkExt;
            信令路由c2.spawn异步任务(Compat::new(async move{
                while let Ok(msg) = rx接收信令.recv().await{
                    if let Err(err) = user_tx_sink.send(msg).await{
                        eprintln!("🍁salvo_WEB_SOCKET 发送数据错误：：  {err}");
                    }
                }
            }));
            let fut接收任务流 = async move {
                while let Some(result) = user_rx_stream.next().await {
                    let msg = if let Ok(msg) = result { msg }else{ break; };
                    let 执行结果= if msg.is_text(){
                            let 文本 = msg.as_str().unwrap_or_default();
                            match serde_json::from_str::<Vec<String>>(文本){
                                Err(err)=>{          Err(anyhow_err!("serde_json::from_str 解析信令错误: {err}   {文本}"))   }
                                Ok(信令) =>{  
                                    let res = 通用执行信令(&信令路由c1, 信令).await;
                                    tx发送信令.send(Message::text(res.to_string())).await.map_err(|err|anyhow_err!("{err}"))
                                }
                            }
                    }
                    else if msg.is_binary(){  Err(anyhow_err!("收到的 Message is_binary"))  }
                    else if msg.is_ping(){    Err(anyhow_err!("收到的 Message is_ping"))    }
                    else if msg.is_pong(){    Err(anyhow_err!("收到的 Message is_pong"))    }
                    else if msg.is_close(){   Err(anyhow_err!("收到的 Message is_close"))   }
                    else{ Err(anyhow_err!("收到的 Message 不是文本"))   };

                    //处理收到到的信令
                    if let Err(err) = 执行结果{ eprintln!("🍁salvo_WEB_SOCKET 执行信令错误: {err}");   }
                }
                //运行到这里退出 websocket
                eprintln!("🍁salvo_WEB_SOCKET  🧊断开连接🧊");
            };
            信令路由c2.spawn异步任务(Compat::new(fut接收任务流));  
        })
        .await
}








#[handler]
pub async fn WEB_POST_自由开放信令(req: &mut Request,depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl){
    if let Ok(信令文本数组) = req.parse_body::<Vec<String>>().await{
        if 信令文本数组.len()>=2{
            match 信令文本数组[1].as_str() {
                "网络_WEB服务器_查询" => {        //此命令通过
                    let 共享数据 = depot.obtain::<服务器DATA>().unwrap();
                    let 信令路由c1 = &共享数据.WEB服务器.信令路由;
                    let 结果 = 通用执行信令(信令路由c1, 信令文本数组).await;
                    res.render(Json(结果));
                    ctrl.skip_rest();  //结束跳过后面的中间件 handler
                }
                _=>{ }
            }
        }
    }
}


/// - 访问端需要 验证信息
/// headers: { "Authorization": `Basic ` + btoa(`admin:admin`) }
pub struct POST_Validator验证密码;
impl BasicAuthValidator for POST_Validator验证密码 {
    async fn validate(&self, username: &str, password: &str, depot: &mut Depot) -> bool {
        username == "admin" && password == "admin"
    }
}


#[handler]
pub async fn WEB_POST_后台加密信令(req: &mut Request,depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl){
    let 共享数据 = depot.obtain::<服务器DATA>().unwrap();
    
    if let Ok(信令文本数组) = req.parse_body::<Vec<String>>().await{
        let 信令路由c1 = &共享数据.WEB服务器.信令路由;
        let 结果 = 通用执行信令(信令路由c1, 信令文本数组).await;
        res.render(Json(结果));
        ctrl.skip_rest();  //结束跳过后面的中间件 handler
    }else{
        res.status_code(StatusCode::BAD_REQUEST);
    }
}

#[handler]
pub async fn 默认后台404页面(req: &mut Request,depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
    res.render(Text::Html(html_404页面(req,depot).await));
}






static HTML模板_404页面 : Lazy<Cow<&str>>  = Lazy::new(|| Cow::Owned(include_str!("./out/WEB后台管理/index.html"))     );
async fn html_404页面(req: &mut Request,depot: &mut Depot)->String{
    HTML模板_404页面.to_string()
}






macro_rules! to_jsonValue数组 {
    ($($arg1:expr),+) => {   json!([ $($arg1),+ ])    };
}

pub async fn 通用执行信令(信令路由ref:&信令路由 , mut 信令数组:Vec<String>)-> Value{
    let 记录信令id = if 信令数组.len() >0 { 信令数组.remove(0) }else{ 0.to_string() };     // eprintln!("WEB_SOCKET连接_执行信令: {:?}",信令);
    
    match app_exec文本信令(信令路由ref,信令数组).await{
        Ok(res) =>{ to_jsonValue数组!(记录信令id, true ,res)     }
        Err(err)=>{ to_jsonValue数组!(记录信令id, false , format!("rust [WEB服务器 通用执行信令 错误] => {:?}",err))  }
    }
}






/*

static HTML模板_404页面 : Lazy<Cow<&str>>  = Lazy::new(|| Cow::Owned(include_str!("./html/404.html"))     );
async fn html_404页面(req: &mut Request,depot: &mut Depot)->String{
    let 共享数据 = depot.obtain::<服务器DATA>().unwrap();
    let (mut 所有服务器信息 ,基础url) = 共享数据.get所有服务器信息().await;
    let req请求地址 = format!("{基础url}{}",信令路由::fn_decodeURI(&req.uri().path()).unwrap_or_default().to_string());

    let 服务器 = &共享数据.WEB服务器;
    let 默认404服务器信息 = WEB服务器信息::new( 服务器.协议头.clone(),服务器.ip.clone(),服务器.端口,Some(HashMap::from([("/后台404页面".into(), vec![ "".into() ])])) );
    所有服务器信息.insert(0,默认404服务器信息);
    
    // 网址    http://192.168.1.3:10001/
    let 服务器信息html = 所有服务器信息.iter()
        .map(|成员|{
            let 网址文本 = 成员.路由表路径数组.iter().map(|url|{ format!("<a style='color:blue;' href='{url}'>{url}</a>") }).collect::<Vec<_>>() .join("&emsp;&emsp;");
            format!(r#"<li class="li_WEB服务器 悬浮下边框"  ondblclick="事件代理.弹出WEB服务器信息({id})" style='order:{id};'>
                        <span style='white-space:nowrap;'>web_id: {id}</span>
                        <div style='flex:auto;display:flex;gap:5px;flex-wrap:wrap;'>{网址文本}</div>
                        <div style='display:flex;align-items:center;gap:10px;'>
                            <div style="{当前网页} margin-right:15px;white-space:nowrap;">此网页</div>
                            <button class="btn1 btn_pink_hover" style="{当前网页}" onclick="事件代理.WEB服务器_控制_确认删除({id},'销毁')">移除</button>

                            <button class="btn1 btn_blue_hover" style="{背景} {显示按钮}"  onclick="事件代理.WEB服务器_控制({id},'反转启停')">{状态}</button>
                            <button class="btn1 btn_pink_hover" style="{显示按钮}" onclick="事件代理.WEB服务器_控制_确认删除({id},'销毁')">移除</button>
                        </div>
                    </li>"#,
                    id = 成员.web_id,
                    显示按钮 = if 成员.状态=="" || 服务器.web_id == 成员.web_id { "display:none;" }else{ "display:block;" },
                    当前网页 = if 服务器.web_id == 成员.web_id { "display:block;" }else{ "display:none;"  },
                    状态 = 成员.状态,
                    背景 = if 成员.状态 == "正常" { "background:rgba(215, 237, 224, 1);" }else{ "background:rgba(243, 218, 224, 1);" }
                )
         }).collect::<Vec<_>>().join("<br>");
    
    HTML模板_404页面
        .replace("{{req请求地址}}", &req请求地址)
        .replace("{{服务器信息html}}", &服务器信息html)
         
}





    // let rest_path = req.param::<String>("rest_path") // 剩余路径
     
    // let url = decodeURI(&req.uri().path()).unwrap_or_default().to_string();
    // if StatusCode::NOT_FOUND == res.status_code.unwrap_or(StatusCode::NOT_FOUND) {
    //     // res.render("Custom 404 Error Page"); 
    //     ctrl.skip_rest();
    // }




use markup;
markup::define! {
    Tabs<'a>(tabs: &'a [Tab<'a>]) {
       @for tab in tabs.iter() {
            @tab
       }
    }

    Tab<'a>(
        title: &'a str,
        body: markup::DynRender<'a>,
    ) {
        h1 { @title }
        div { @body }
    }
}

 
#[handler]
async fn 本地静态文件服务页面(req: &mut Request,depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
    let 数组: Vec<u8>= tokio::fs::read("/home/lwl/Desktop/1.txt").await.unwrap();
    let 文本内容 = String::from_utf8(数组).unwrap();
    res.render(Redirect::found("https://salvo.rs/"));  //重定向
 
    let 显示404 = format!("<span>Li文件浏览器</span><br><hr><h3>找不到资源: {}</h3>", url);
    res.render(Text::Html(显示404));
 
    let 根目录 = "/home/lwl/Desktop/reference-gh-pages";
    let 根文件项 = mod_file::文件::new(根目录).通用文件项();
    let 路径 =  mod_file::path_join(&根文件项.路径, &url); 
    let 文件项 = mod_file::文件::new(路径.clone()).通用文件项();
   
    res.send_file(&路径, req.headers()).await
 
    let 数组: Vec<u8>= tokio::fs::read("/home/lwl/Desktop/1.txt").await.unwrap();
    let 文本内容 = String::from_utf8(数组).unwrap();
    eprintln!("读取文件 -> {}", &文本内容 );
    res.render(Text::Plain(文本内容));
   
    res.render(Redirect::found("https://salvo.rs/"));  //重定向
    let url = .get("id").cloned().unwrap_or_default();

    res.send_file("/home/lwl/Desktop/1.txt",);
}


*/



