#![allow(non_snake_case)]
#![allow(non_camel_case_types)] 
#![allow(unused_imports)]
#![allow(unused_variables)]
#![allow(dead_code)]
#![allow(unused_labels)]
#![allow(unreachable_code)]
// #![allow(unused_braces)]


use std::{ time, };
//https://crates.io/crates/gio
use gio::{ prelude::*, Volume};

#[cfg(all(target_os = "linux"))]
use linicon;
use serde::{Serialize, Deserialize};
use lwleen_rpc::futures::{self, Future, stream::{FusedStream, Stream}, task::SpawnExt, FutureExt as FutureExt_, StreamExt, TryFutureExt };

use crate::prelude::*;


static 全局_记录SMB_IP数组: Lazy<DashSet<String>> = Lazy::new(||{ DashSet::new() });  //这里初始化




#[gen_特征_derive(MOD特征_gio)]
impl 信令路由{
    async fn exec文本信令_gio(&self,函数名:&str, mut 参数数组:Vec<String>)-> anyhow_Result<(bool,Value,Vec<String>)>{
        let 信令路由 = self;
        let 结果 = match 函数名{
            "gio_磁盘查询数组"=>{            json!(信令路由.gio_磁盘查询数组().await?)       }
            "gio_磁盘查询smb磁盘"=>{         json!(信令路由.gio_磁盘查询smb磁盘().await?)    }
            "smb" | "gio_磁盘查询smb共享"=>{ json!(信令路由.gio_磁盘查询smb共享().await?)    }

            "gio_mount"=>{
                if 参数数组.len() < 1 {  return Err(anyhow_err!("gio_mount, 缺少参数::  <uri路径> <用户名> <密码> <工作域>")) } 
                let 工作域 = if 参数数组.len() >=4 {   Some(参数数组.remove(3))   } else { None } ; 
                let 密码   = if 参数数组.len() >=3 {   Some(参数数组.remove(2))   } else { None } ;
                let 用户名 = if 参数数组.len() >=2 {   Some(参数数组.remove(1))   } else { None } ;
                
                信令路由.gio_mount(参数数组.remove(0),用户名, 密码, 工作域).await?;
                json!(true)
            }
            "gio_unmount"=>{
                if 参数数组.len() < 1 {  return Err(anyhow_err!("gio_unmount, 缺少参数:: <uri路径> , 比如:smb://192.168.1.1/share")) }  
                信令路由.gio_unmount(参数数组.remove(0)).await?;
                json!(true)
            }
            "gio_mount尝试挂载局域网内所有smb"=>{         json!(信令路由.gio_mount尝试挂载局域网内所有smb().await?)   }
            "gio_mime查询_默认启动程序"=>{
                if 参数数组.len() < 1 {  return Err(anyhow_err!("gio_mime查询_默认启动程序, 缺少参数::  <mime> <查找图标bool>")) }
                let 查找图标bool = if 参数数组.len() >=2 && 参数数组[1] == "true" { true }else{ false };
                json!(信令路由.gio_mime查询_默认启动程序(参数数组.remove(0), 查找图标bool).await?)
            }
            "gio_mime查询_关联程序数组"=>{
                if 参数数组.len() < 1 {  return Err(anyhow_err!("gio_mime查询_关联程序数组, 缺少参数::  <mime> <查找图标bool>")) }
                let 查找图标bool = if 参数数组.len() >=2 && 参数数组[1] == "true" { true }else{ false };
                json!(信令路由.gio_mime查询_关联程序数组(参数数组.remove(0), 查找图标bool).await?)
            }
            "gio_mime设置_默认启动程序"=>{
                if 参数数组.len() < 2 {  return Err(anyhow_err!("gio_mime设置_默认启动程序, 缺少参数::<desktop>  <mime数组>")) }
                json!(信令路由.gio_mime设置_默认启动程序(参数数组.remove(0), 参数数组).await?) 
            }
            "gio_desktop查询程序"=>{
                if 参数数组.len() < 1 {  return Err(anyhow_err!("gio_desktop查询程序, 缺少参数::  <desktop>")) }
                let 查找图标bool = if 参数数组.len() >=2 && 参数数组[1] == "true" { true }else{ false };  
                json!(信令路由.gio_desktop查询程序(参数数组.remove(0),查找图标bool).await?) 
            }
            "gio_uri查询_默认启动程序"=>{
                if 参数数组.len() < 1 {  return Err(anyhow_err!("gio_uri查询_默认启动程序, 缺少参数::  <uri协议>  ，比如 http  smb")) }
                let 查找图标bool = if 参数数组.len() >=2 && 参数数组[1] == "true" { true }else{ false };
                json!(信令路由.gio_uri查询_默认启动程序(参数数组.remove(0), 查找图标bool).await?)
            }
            "gio_desktop打开程序"=>{
                if 参数数组.len() < 1 {  return Err(anyhow_err!("gio_desktop打开程序, 缺少参数::  <desktop> <文件路径>")) } 
                let 文件路径 = if 参数数组.len() >= 2 { 参数数组.remove(1) } else { "".to_string() }; 
                信令路由.gio_desktop打开程序(参数数组.remove(0), 文件路径).await?;
                json!(true)
            }
            "gio_trash文件数组"=>{     信令路由.gio_trash文件数组(参数数组).await?;     json!(true)}
            "gio_trash还原文件数组"=>{  信令路由.gio_trash还原文件(参数数组).await?; json!(true)}
            "gio_trash清空文件"=>{  信令路由.gio_trash清空文件().await?;                json!(true)}
            "gio_trash查询所有文件"=>{ json!(信令路由.gio_trash查询所有文件().await?) }
            _=>{ return Ok((false, json!(""), 参数数组)); }
        };
        Ok((true, 结果, Vec::new()))
    }

    fn gio_磁盘查询数组(&self)-> impl 信令任务<Vec<gio磁盘文件项>>{
        core发布信令任务!(self, 信令表::gio_磁盘查询数组,  信令表::gio_磁盘查询数组_回复 => 磁盘数组 )    
    }
    fn gio_磁盘查询smb磁盘(&self)-> impl 信令任务<Vec<gio磁盘文件项>>{
        core发布信令任务!(self, 信令表::gio_磁盘查询smb磁盘,  信令表::gio_磁盘查询smb磁盘_回复 => 磁盘数组 )    
    }
    fn gio_磁盘查询smb共享(&self)-> impl 信令任务<Vec<共享smb文件夹>>{
        core发布信令任务!(self, 信令表::gio_磁盘查询smb共享,  信令表::gio_disk查询smb共享_回复 => smb共享数组 )
    }

    fn gio_trash查询所有文件(&self)-> impl 信令任务<Vec<回收文件项>>{
        core发布信令任务!(self, 信令表::gio_trash查询所有文件,  信令表::gio_trash查询所有文件_回复 => trash文件数组 )
    }
    fn gio_trash文件数组(&self,路径数组:Vec<String>)-> impl 信令任务<()>{
        core发布信令任务!(self, 信令表::gio_trash文件数组 { 路径数组},  信令表::gio_trash文件数组_回复 )
    }
    fn gio_trash还原文件(&self,路径数组:Vec<String>)-> impl 信令任务<()>{
        core发布信令任务!(self, 信令表::gio_trash还原文件数组 { 路径数组},  信令表::gio_trash还原文件数组_回复 )
    }
    fn gio_trash清空文件(&self)-> impl 信令任务<()>{
        core发布信令任务!(self, 信令表::gio_trash清空文件,  信令表::gio_trash清空文件_回复 )
    }
    fn gio_mount尝试挂载局域网内所有smb(&self)-> impl 信令任务<Vec<String>>{
        core发布信令任务!(self, 信令表::gio_mount尝试挂载局域网内所有smb,  信令表::gio_mount尝试挂载局域网内所有smb_回复 => ip数组 )
    }
    fn gio_mount(&self,uri路径:String, 用户名:Option<String>, 密码:Option<String>, 工作域:Option<String>)-> impl 信令任务<()>{ 
        core发布信令任务!(self, 信令表::gio_mount{uri路径,用户名,密码,工作域},  信令表::gio_mount_回复 )
    }
    fn gio_unmount(&self,uri路径:String)-> impl 信令任务<()>{
        core发布信令任务!(self, 信令表::gio_unmount{uri路径},  信令表::gio_unmount_回复 )
    }
    
    /// - desktop_id  如  vlc.desktop 
    fn gio_mime设置_默认启动程序<T:AsRef<str>>(&self, desktop_id:T, mime数组:Vec<T>,)-> impl 信令任务<()>{
        core发布信令任务!(self, 信令表::gio_mime设置_默认启动程序{mime数组:mime数组.iter().map(|item|item.as_ref().to_string()).collect::<_>(), desktop_id:desktop_id.as_ref().to_string()  },  信令表::gio_mime设置默认启动程序_回复 )
    }
    fn gio_mime查询_默认启动程序(&self,mime类型:String,查询图标:bool) -> impl 信令任务<程序INFO>{
        信令表::gio_mime查询_关联程序数组{mime类型, 只查找默认程序:true, 查询图标 }
            .task发布信令任务(self.clone(), 
                |res|{
                    let mut 结果arr = match取出!(res? ,信令表::gio_mime查找关联程序数组_回复 => 程序数组)?;
                    if 结果arr.len() >=1 { Ok(结果arr.remove(0))  }else{ Err(anyhow_err!("gio_mime查询_默认启动程序 空 失败!!!")) }
            })
    }
    fn gio_mime查询_关联程序数组(&self,mime类型:String, 查询图标:bool)-> impl 信令任务<Vec<程序INFO>>{
        core发布信令任务!(self, 信令表::gio_mime查询_关联程序数组{mime类型, 只查找默认程序:false, 查询图标},  信令表::gio_mime查找关联程序数组_回复 => 程序数组 )
    }
    fn gio_uri查询_默认启动程序(&self,uri协议:String,查询图标:bool)-> impl 信令任务<程序INFO>{
        core发布信令任务!(self, 信令表::gio_uri查询_默认启动程序{uri协议, 查询图标},  信令表::gio_uri查找默认启动程序_回复 => 程序info )
    }
    fn gio_desktop查询程序(&self,desktop:String, 查询图标:bool)-> impl 信令任务<程序INFO>{
        core发布信令任务!(self, 信令表::gio_查询desktop{desktop, 查询图标},  信令表::gio_查询desktop_回复 => 程序info )
    }
    fn gio_desktop打开程序(&self,desktop:String, 路径:String)-> impl 信令任务<()>{
        core发布信令任务!(self, 信令表::gio_desktop打开程序{desktop,路径},  信令表::gio_desktop打开文件_回复 )
    }
}


#[derive(Clone, Serialize, Deserialize)]//可选特征
enum 信令表{
    gio_trash文件数组{          路径数组:Vec<String> },
    gio_trash文件数组_回复,
    gio_trash还原文件数组{      路径数组:Vec<String> },
    gio_trash还原文件数组_回复,
    gio_trash清空文件,
    gio_trash清空文件_回复,
    gio_trash查询所有文件,
    gio_trash查询所有文件_回复{ trash文件数组:Vec<回收文件项>  },
    gio_磁盘查询数组,
    gio_磁盘查询数组_回复{      磁盘数组:Vec<gio磁盘文件项>   }, 
    gio_磁盘查询smb磁盘,
    gio_磁盘查询smb磁盘_回复{   磁盘数组:Vec<gio磁盘文件项>   }, 
    gio_磁盘查询smb共享,
    gio_disk查询smb共享_回复{   smb共享数组:Vec<共享smb文件夹>  },
    gio_mount尝试挂载局域网内所有smb,
    gio_mount尝试挂载局域网内所有smb_回复{ ip数组:Vec<String> },
    gio_mount{               uri路径:String, 用户名:Option<String>, 密码:Option<String>, 工作域:Option<String>  },
    gio_mount_回复,
    gio_unmount{             uri路径:String },
    gio_unmount_回复,
    gio_mime查询_关联程序数组{       mime类型:String, 只查找默认程序:bool ,查询图标:bool     },
    gio_mime查找关联程序数组_回复{  程序数组:Vec<程序INFO>      },
    gio_mime设置_默认启动程序{      mime数组:Vec<String>, desktop_id:String },
    gio_mime设置默认启动程序_回复,
    
    gio_uri查询_默认启动程序{       uri协议:String ,查询图标:bool           },
    gio_uri查找默认启动程序_回复{   程序info:程序INFO  },
    gio_查询desktop{          desktop:String ,查询图标:bool            }, 
    gio_查询desktop_回复{      程序info:程序INFO   },
    gio_desktop打开程序{       desktop:String, 路径:String },
    gio_desktop打开文件_回复,
}


impl信令特征!(信令表, 执行函数);
async fn 执行函数(信令路由:信令路由,id:信令ID,单个信令:信令表)->anyhow_Result<信令表>{ 
    // Err::<(), anyhow_Error>(anyhow_err!("gio模块的执行函数, 无法跨线程, 必须直接调用"))
    let (tx,rx) = oneshot::channel();
    信令路由.clone().core_gtk_MainContext().spawn_from_within(move||async move{
        let res = run_执行函数_gio(信令路由,id ,单个信令).await;
        tx.send(res).ok();
    });
    rx.await?
}


async fn run_执行函数_gio(信令路由:信令路由,id:信令ID,单个信令:信令表) -> anyhow_Result<信令表>{
        let 结果 =  match 单个信令{
            信令表::gio_磁盘查询数组 =>{
                gio_磁盘查询数组().await .map(|返回|{   信令表::gio_磁盘查询数组_回复{ 磁盘数组:返回  }   }) 
            }
            信令表::gio_磁盘查询smb磁盘 =>{
                gio_磁盘查询smb磁盘().await .map(|返回|{   信令表::gio_磁盘查询smb磁盘_回复{ 磁盘数组:返回  }   }) 
            }
            信令表::gio_磁盘查询smb共享 =>{
                gio_磁盘查询smb共享(信令路由.clone()).await .map(|返回|{   信令表::gio_disk查询smb共享_回复 { smb共享数组:返回 }  })
            }
            信令表::gio_mount尝试挂载局域网内所有smb =>{
                gio_mount尝试挂载局域网内所有smb(信令路由.clone()).await .map(|返回|{   信令表::gio_mount尝试挂载局域网内所有smb_回复 { ip数组:返回 }  })
            }
            信令表::gio_trash查询所有文件{}=>{
                gio_trash查询所有文件().await .map(|返回|{   信令表::gio_trash查询所有文件_回复 { trash文件数组:返回 }  }) 
            }
            信令表::gio_trash文件数组 { 路径数组}=>{
                gio_trash文件数组(路径数组).await .map(|返回|{   信令表::gio_trash文件数组_回复  }) 
            }
            信令表::gio_trash还原文件数组 { 路径数组}=>{
                gio_trash还原文件数组(路径数组).await .map(|返回|{   信令表::gio_trash还原文件数组_回复     }) 
            }   
            信令表::gio_trash清空文件 =>{
                gio_trash清空文件().await .map(|返回|{   信令表::gio_trash清空文件_回复     }) 
            }
            信令表::gio_mount{uri路径,用户名,密码,工作域}=>{
                gio_mount(&uri路径,用户名.as_deref(),密码.as_deref(),工作域.as_deref()).await
                                    .map(|返回|{   信令表::gio_mount_回复 }) 
            }
            信令表::gio_unmount{uri路径}=>{
                gio_unmount(&uri路径).await .map(|返回|{   信令表::gio_unmount_回复  }) 
            }
            信令表::gio_mime设置_默认启动程序{mime数组,desktop_id}=>{
                gio_mime设置_默认启动程序(mime数组, desktop_id)
                                    .map(|返回|{   信令表::gio_mime设置默认启动程序_回复 }) 
            }
            信令表::gio_mime查询_关联程序数组{mime类型, 只查找默认程序,查询图标: 查询图标bool}=>{
                gio_mime查询_关联程序数组(&mime类型, 只查找默认程序,查询图标bool).await  .map(|返回|{ 信令表::gio_mime查找关联程序数组_回复 {  程序数组:返回 } }) 
            }
            信令表::gio_uri查询_默认启动程序{uri协议, 查询图标: 查询图标bool}=>{
                gio_uri查询_默认启动程序(&uri协议, 查询图标bool).await .map(|返回|{   信令表::gio_uri查找默认启动程序_回复 {  程序info:返回 }  }) 
            }
            信令表::gio_查询desktop{desktop,查询图标: 查询图标bool}=>{
                gio_desktop查询程序(&desktop, 查询图标bool) .map(|返回|{   信令表::gio_查询desktop_回复 {  程序info:返回 }  }) 
            }
            信令表::gio_desktop打开程序{desktop,路径}=>{
                gio_desktop打开程序(&desktop,&路径) .map(|返回|{   信令表::gio_desktop打开文件_回复  }) 
            }
            _ =>{ return Err(anyhow_err!("信令不存在")); }
        }?;
        anyhow_Ok信令!(结果)
}








pub async fn gio_info文件(路径:&str)-> anyhow_Result<String> {
    let 文件 = gio::File::for_parse_name(路径);
    let info = 文件.query_info_future( "*" , gio::FileQueryInfoFlags::NONE,gio::glib::Priority::DEFAULT).await?;
    eprintln!("{:#?}",info.attribute_as_string("*"));
    Ok("".into())
}
pub async fn gio_info文件系统(路径:&str)-> anyhow_Result<文件系统info> {
    let 文件 = gio::File::for_parse_name(路径);
    let info = 文件.query_filesystem_info_future( "filesystem"  , gio::glib::Priority::DEFAULT).await?;
    let mut 信息 = 文件系统info::default();
    信息.容量size = info.attribute_uint64(gio::FILE_ATTRIBUTE_FILESYSTEM_SIZE);
    信息.可用size = info.attribute_uint64(gio::FILE_ATTRIBUTE_FILESYSTEM_FREE);
    信息.已用size = info.attribute_uint64(gio::FILE_ATTRIBUTE_FILESYSTEM_USED);
    信息.已用百分比 = (信息.已用size as f64/信息.容量size as f64 * 100. ).round() as u64;
    信息.磁盘格式 = info.attribute_string(gio::FILE_ATTRIBUTE_FILESYSTEM_TYPE).unwrap_or_default().to_string();
    信息.远程标志 = info.boolean(gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE);
    信息.只读标志 = info.boolean(gio::FILE_ATTRIBUTE_FILESYSTEM_READONLY);
    Ok(信息)
}




fn sub_生成appinfo_单个(info: impl AppInfoExt , 查询图标bool:bool)->程序INFO{
    let mut app = 程序INFO::default();
    app.desktop_id = info.id().unwrap_or_default().to_string();
    app.显示名称 = info.display_name().to_string();
    app.名称 = info.name().to_string();
    app.描述 = info.description().unwrap_or_default().to_string();
    app.路径 = info.executable().display().to_string();
    app.启动指令 = info.commandline().unwrap_or_default().display().to_string();
    app.图标 = if let Some(icon) = info.icon(){   icon.to_string().unwrap_or_default().to_string()   }else{ "".into() };  
    
    #[cfg(all(target_os = "linux"))]
    if 查询图标bool{
        if let Some(Ok(路径)) = linicon::lookup_icon(&app.图标).with_size(128).next(){
            app.图片src = 路径.path.display().to_string();
        };
    }
    app
}

pub async fn gio_mime查询_关联程序数组<T:AsRef<str>>(mime类型:T, 只查找默认程序:bool, 查询图标:bool)->anyhow_Result<Vec<程序INFO>>{
    let mut 输出数组 = Vec::new();
    if !只查找默认程序{
        let appinfo数组 = gio::AppInfo::all_for_type(mime类型.as_ref());
        for info in appinfo数组{
            输出数组.push( sub_生成appinfo_单个(info, 查询图标) );
        }
    }
    let info = gio::AppInfo::default_for_type_future(mime类型.as_ref(), false).await?;
    let mut 应用 =  sub_生成appinfo_单个(info, 查询图标);
    应用.系统默认程序 = true;
    输出数组.retain(|项| 项.desktop_id != 应用.desktop_id  );
    输出数组.insert(0,应用); 
    Ok(输出数组)
}
pub fn gio_mime设置_默认启动程序<T:AsRef<str>>(mime数组:Vec<T>,desktop_id:T)->anyhow_Result<()>{
    let app_info = gio::DesktopAppInfo::new(desktop_id.as_ref()).ok_or(anyhow_err!("gio_mime设置_默认启动程序 无法识别 -> {}", desktop_id.as_ref()))?;
    for mime in mime数组{
        app_info.set_as_default_for_type(mime.as_ref())?;
    }
    Ok(())
}


/// uri协议  smb://  http:// file://
pub async fn gio_uri查询_默认启动程序(协议名:&str, 查询图标bool:bool)->anyhow_Result<程序INFO>{
    let info = gio::AppInfo::default_for_uri_scheme_future(协议名).await?;
    Ok(sub_生成appinfo_单个(info, 查询图标bool))
}

pub fn gio_desktop查询程序(desktop_id:&str, 查询图标bool:bool)->anyhow_Result<程序INFO>{ 
    let info = gio::DesktopAppInfo::new(desktop_id)
                .ok_or(anyhow_err!("gio_desktop查询程序 无法识别 -> {}", desktop_id))?;
    Ok(sub_生成appinfo_单个(info, 查询图标bool))
}

pub fn gio_desktop打开程序(desktop_id:&str, 文件路径:&str) -> anyhow_Result<()>{
    if let Some(info) = gio::DesktopAppInfo::new(desktop_id){
        let uri路径 = gio::File::for_parse_name(文件路径).uri().to_string();
        info.launch_uris(&[&uri路径], gio::AppLaunchContext::NONE)?;
        Ok(())
    }else{
        return Err(anyhow_err!("gio_desktop打开程序 无法识别 -> {}", desktop_id));
    }
}




pub async fn gio_检查是否可挂载(uri路径:&str) -> anyhow_Result<()>{
    let 文件 = gio::File::for_parse_name(uri路径); 
    let uri = 文件.uri().to_string();
    if let Err(err) = 文件.query_info_future(gio::FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT , gio::FileQueryInfoFlags::NONE,gio::glib::Priority::DEFAULT).await{
        eprintln!("gio_检查是否可挂载 {uri路径}   {:#?}  ",err );  //err.kind::<gio::IOErrorEnum>()
        return Err(anyhow_err!("{uri路径} 不可挂载"));
    }
    Ok(())
}

//https://valadoc.org/gio-2.0/GLib.MountOperation.html
pub async fn gio_mount(uri路径:&str, 用户名:Option<&str>, 密码:Option<&str>, 工作域:Option<&str> )->anyhow_Result<()>{ 
    let mount操作 = gio::MountOperation::new(); 
    mount操作.set_username(用户名);
    mount操作.set_domain(Some(工作域.unwrap_or("WORKGROUP")));
    mount操作.set_password(密码);
    if let None = 用户名{   mount操作.set_anonymous(true);  }
    let 尝试次数  = Arc::new(Mutex::new(0));   //共享且可修改 
    mount操作.connect_aborted(|操作,|{ 操作.reply(gio::MountOperationResult::Aborted);  });  //这个中断操作
    mount操作.connect_ask_password(move|操作,b,c,d,需求标志|{  
        let mut 次数 = 尝试次数.lock();  *次数 += 1;      //取出共享变量                                      
        if *次数 <= 2{ 操作.reply(gio::MountOperationResult::Handled);     }   //这个相当于回车键
        else{         操作.reply(gio::MountOperationResult::Unhandled);   }    //这个中断操作
    });
    let 文件 = gio::File::for_parse_name(uri路径); 
    文件.mount_enclosing_volume_future(gio::MountMountFlags::NONE,Some(&mount操作) ).await?;
    
    Ok(())
    // let uri = 文件.uri().to_string();
    // if &uri[0..6] == "smb://"{ }
    // else if &uri[0..7] == "file://"{}
    // else{ return Err(anyhow_err!("gio_mount 无法识别协议 -> {}", uri)); }
}

pub async fn gio_unmount(uri路径:&str)->anyhow_Result<()>{
    let 文件 = gio::File::for_parse_name(uri路径);
    let mount = 文件.find_enclosing_mount(gio::Cancellable::NONE)?;
    mount.unmount_with_operation_future(gio::MountUnmountFlags::NONE,gio::MountOperation::NONE,).await?;
    Ok(())
}
pub async fn gio_mount尝试挂载局域网内所有smb(信令路由:信令路由)->anyhow_Result<Vec<String>>{
    let smb_ip数组 =  信令路由.网络_查询局域网内已打开端口的ip数组(vec![445]).await?;
    for addr in &smb_ip数组{
        let ip = addr.ip().to_string();
        gio_mount(&format!("smb://{ip}/"),None,None,None).await.ok();  
    }
    let ip数组 = smb_ip数组.iter().map(|addr|addr.ip().to_string()).collect();
    Ok(ip数组)
}



fn 读取磁盘容量(info:&gio::FileInfo , 文件项:&mut gio磁盘文件项){
    文件项.容量size = info.attribute_uint64(gio::FILE_ATTRIBUTE_FILESYSTEM_SIZE);
    文件项.可用size = info.attribute_uint64(gio::FILE_ATTRIBUTE_FILESYSTEM_FREE);
    文件项.已用size = 文件项.容量size - 文件项.可用size;
    文件项.容量 = 信令路由::fn_字节to可读(文件项.容量size);
    文件项.可用 = 信令路由::fn_字节to可读(文件项.可用size);
    文件项.已用 = 信令路由::fn_字节to可读(文件项.已用size);
    文件项.已用百分比 = (文件项.已用size as f64/文件项.容量size as f64 * 100. ).round() as u64; 
    文件项.磁盘格式 = info.attribute_string(gio::FILE_ATTRIBUTE_FILESYSTEM_TYPE).unwrap_or_default().to_string(); 
}
pub async fn gio_磁盘查询数组() -> anyhow_Result< Vec<gio磁盘文件项> >{

    let mut 磁盘数组:Vec<gio磁盘文件项> = Vec::new();
    let ( 挂载数组 ,个数)=  gio::UnixMountEntry::mounts(); // gio::UnixMountPoint::mount_points();  
    for mount in 挂载数组{
        let mut 文件项 = gio磁盘文件项::default();
        文件项.挂载路径 = mount.mount_path().display().to_string();
        文件项.路径 = 文件项.挂载路径.clone();
        // 文件项.磁盘配置 = mount.options().unwrap_or_default().to_string();
        // 文件项.uuid = mount.device_path().display().to_string();
        
        let 文件 = gio::File::for_parse_name(&文件项.挂载路径);
        文件项.uri路径 = 文件.uri().to_string();
        if let Ok(info) = 文件.query_filesystem_info_future( "filesystem::size,filesystem::free,filesystem::type" , gio::glib::Priority::DEFAULT).await{
            读取磁盘容量(&info, &mut 文件项 );
        }
        文件项.磁盘格式 = mount.fs_type().to_string();
        磁盘数组.push(文件项);
    }

    Ok(磁盘数组)
}

pub async fn gio_磁盘查询smb磁盘() -> anyhow_Result< Vec<gio磁盘文件项> >{
    let mut 磁盘数组:Vec<gio磁盘文件项> = Vec::new();
    let 挂载数组 = gio::VolumeMonitor::get().mounts();
    for gio_mount in 挂载数组 {
        let mut 文件项 = gio磁盘文件项::default();
        文件项.挂载路径 = gio_mount.default_location().path().unwrap_or_default().display().to_string();
        文件项.路径 = 文件项.挂载路径.clone();
        文件项.描述 = gio_mount.name().to_string(); 
        let 文件 = gio::File::for_parse_name(&文件项.挂载路径);
        文件项.uri路径 = 文件.uri().to_string();

        if ! 文件项.uri路径.starts_with("smb://") { continue; }      //跳过非 smb 重复
        // 文件项.icon = gio_mount.icon().to_string().unwrap_or_default().to_string();
        // 文件项.sort_key = gio_mount.sort_key().unwrap_or_default().to_string();
        // 文件项.path = gio_mount.default_location().path().unwrap_or_default().display().to_string();
        // 文件项.uuid = gio_mount.uuid().unwrap_or_default().to_string();
        
        if let Ok(info) = 文件.query_filesystem_info_future( "filesystem::size,filesystem::free,filesystem::type" , gio::glib::Priority::DEFAULT).await{
            读取磁盘容量(&info, &mut 文件项 );
        }
        磁盘数组.push(文件项);
    }

    Ok(磁盘数组)
}


pub async fn gio_磁盘查询smb共享(信令路由:信令路由)->anyhow_Result<Vec<共享smb文件夹>>{
    let mut 最终数组:Vec<共享smb文件夹> = Vec::new();
    let ip数组 =  信令路由.网络_查询局域网内已打开端口的ip数组(vec![445]).await?;
    
    let 读取内部文件夹 = |ip:&str|->anyhow_Result<Vec<共享smb文件夹>>{ 
        let smb文件 = gio::File::for_parse_name(&format!("smb://{ip}"));
        let 数组 = smb文件.enumerate_children( gio::FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME ,gio::FileQueryInfoFlags::NONE,gio::Cancellable::NONE )?;
        let mut 临时数组:Vec<共享smb文件夹> = Vec::new();
        for 内部文件 in 数组{
            if let  Ok(info) = 内部文件{
                let 共享文件夹 = info.attribute_string(gio::FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME).unwrap_or_default().to_string();
                let mut 临时 = 共享smb文件夹::default();
                let 临时文件 = gio::File::for_parse_name(&format!("smb://{ip}/{共享文件夹}")); 
                临时.ip = ip.to_string();
                临时.文件名 = 共享文件夹;
                临时.uri路径 = 临时文件.uri().to_string();
                临时.挂载路径 = 临时文件.path().unwrap_or_default().display().to_string();
                临时数组.push(临时);
            }
        }
        Ok(临时数组)
    };
    for addr in ip数组{
        let ip = addr.ip().to_string();
        if let Ok(mut 数组) = 读取内部文件夹(&ip){ 最终数组.append(&mut 数组);  }
        else if 全局_记录SMB_IP数组.contains(&ip){ } 
        else{
            全局_记录SMB_IP数组.insert(ip.clone());
            let smb文件 = gio::File::for_parse_name(&format!("smb://{ip}"));     // gio::FILE_ATTRIBUTE_STANDARD_TARGET_URI 
            if let Ok(_) = smb文件.mount_enclosing_volume_future(gio::MountMountFlags::NONE,gio::MountOperation::NONE)
                                 .timeout(std::time::Duration::from_millis(350)).await
                && let Ok(mut 数组) = 读取内部文件夹(&ip)
            {   // 尝试无密码挂载
                最终数组.append(&mut 数组);
            }
        }
    }
    Ok(最终数组)
}





//g_file_resolve_relative_path
pub async fn gio_trash文件数组(路径数组: Vec<String>)->anyhow_Result<()>{
    for 路径 in 路径数组{  
        let 文件 = gio::File::for_parse_name(&路径);
        文件.trash_future(gio::glib::Priority::DEFAULT).await?;   
    }
    Ok(())
}
pub async fn gio_trash查询所有文件()->anyhow_Result<Vec<回收文件项>>{
    let trash文件 = gio::File::for_parse_name("trash://");
    let mut 返回数组:Vec<回收文件项> = Vec::new();
    if let Ok(文件枚举器) = trash文件.enumerate_children("*",gio::FileQueryInfoFlags::NONE,gio::Cancellable::NONE ){
        for 内部文件 in 文件枚举器.clone(){
            if let  Ok(info) = 内部文件{
                let uri = info.attribute_string(gio::FILE_ATTRIBUTE_STANDARD_TARGET_URI).unwrap_or_default().to_string();
                let 临时文件 = gio::File::for_parse_name(&uri); 
                
                let mut 临时 = 回收文件项::default(); 
                临时.uri路径 = 临时文件.uri().to_string();
                临时.删除时间 = info.attribute_string(gio::FILE_ATTRIBUTE_TRASH_DELETION_DATE).unwrap_or_default().to_string();
                临时.路径 = 临时文件.path().unwrap_or_default().display().to_string();
                临时.trash_info路径 = format!("{}.trashinfo", 临时.路径.replace("/files/", "/info/"));
                临时.原路径 = info.attribute_byte_string(gio::FILE_ATTRIBUTE_TRASH_ORIG_PATH).unwrap_or_default().to_string();
                临时.文件名 = std::path::Path::new(&临时.原路径).file_name().unwrap_or_default().to_string_lossy().to_string();
                            
                返回数组.push(临时);
            }
        }
        文件枚举器.close_future(gio::glib::Priority::DEFAULT).await.ok();
    }
    Ok(返回数组)
}
pub async fn gio_trash还原文件数组(路径数组: Vec<String>)->anyhow_Result<()>{
    let mut 所有回收文件 = gio_trash查询所有文件().await?; 
    所有回收文件.retain(|回收文件|  路径数组.iter().any(|路径| 路径 == &回收文件.路径 )  );

    for 回收文件 in 所有回收文件{ 
        let trash_info本体 = gio::File::for_parse_name(&回收文件.trash_info路径);
        let 文件本体 = gio::File::for_parse_name(&回收文件.路径); 
        let mut 原文件 = gio::File::for_parse_name(&回收文件.原路径);
        {//处理重名
            let mut num = 0;
            let mut 新路径buf = std::path::Path::new(&回收文件.原路径).to_path_buf();
            let 原文件名 = &新路径buf.file_name().unwrap_or_default().to_string_lossy().to_string(); 
            while 原文件.query_exists(gio::Cancellable::NONE){ 
                num +=1;
                let 新名字 = format!("~备份{}_{}",num,原文件名);
                let _ = &新路径buf.set_file_name(新名字);
                原文件 = gio::File::for_path(&新路径buf);
            }
        }
        let (移动,过程输出) = 文件本体.move_future(&原文件, gio::FileCopyFlags::BACKUP , gio::glib::Priority::DEFAULT);
        移动.await?;
        trash_info本体.delete_future(gio::glib::Priority::DEFAULT).await?;  
    }
    Ok(()) 
}
pub async fn gio_trash清空文件()->anyhow_Result<()>{
    let 所有回收文件 = gio_trash查询所有文件().await?; 
    for 回收文件 in 所有回收文件{
        if std::path::Path::new(&回收文件.路径).is_dir(){
            std::fs::remove_dir_all(&回收文件.路径).ok();
        }else{
            let 文件 = gio::File::for_parse_name(&回收文件.路径);
            文件.delete_future(gio::glib::Priority::DEFAULT).await.ok();
        }
         
        let 文件 = gio::File::for_parse_name(&回收文件.trash_info路径);
        文件.delete_future(gio::glib::Priority::DEFAULT).await.ok();
    }
    Ok(())
}














//================ gio ================

#[derive(Debug, Serialize, Deserialize,Clone,Default)]
pub struct 回收文件项{
    pub 文件名:String,
    pub uri路径:String,
    pub 路径:String,
    pub trash_info路径:String,
    pub 原路径:String,
    pub 删除时间:String,
}

#[derive(Debug, Serialize, Deserialize,Clone,Default)]
pub struct gio磁盘文件项{
    // pub uuid:String,
    pub 磁盘配置:String,
    pub 磁盘格式:String,
    pub uri路径:String,
    pub 挂载路径:String,
    pub 路径:String,
    pub 容量:String,
    pub 可用:String,
    pub 已用:String,
    pub 容量size:u64,
    pub 可用size:u64,
    pub 已用size:u64,
    pub 已用百分比:u64,
    pub 描述:String,
}

#[derive(Debug, Serialize, Deserialize,Clone,Default)]
pub struct 共享smb文件夹{
    pub 文件名:String,
    pub ip: String,
    pub uri路径: String,
    // pub 存在:bool, 
    pub 挂载路径: String, 
}


#[derive(Debug, Serialize, Deserialize,Clone,Default)]
pub struct 程序INFO{
    pub desktop_id:String,
    pub 显示名称:String,
    pub 名称:String,
    pub 描述:String,
    pub 路径:String,
    pub 启动指令:String,
    pub 图标:String,
    pub 图片src:String,
    pub 系统默认程序:bool,
}


#[derive(Debug, Serialize, Deserialize,Clone,Default)]
pub struct 文件系统info{
    pub 容量size: u64,
    pub 可用size: u64,
    pub 已用size: u64,
    pub 已用百分比: u64,
    pub 磁盘格式: String,
    pub 只读标志: bool,
    pub 远程标志: bool,
}





#[cfg(all(test,feature = "mod_gtk"))]
mod  测试{
    use super::*;
    #[cfg(all(test,feature = "mod_gtk"))]
    #[test]
    fn 测试1(){
        eprintln!("🌷测试1🌷");

        let 信令路由 =  信令路由::default();   //  gio_磁盘查询数组
        信令路由.clone().pool异步任务_block阻塞完成(async move{
            // gio_磁盘查询数组  gio_磁盘查询smb共享  gio_mount尝试挂载局域网内所有smb
            let out = 信令路由.gio_磁盘查询smb共享().await.unwrap_or_default();
            let 状态 = 信令路由.rpc信令路由_状态();
            eprintln!("\n🌷结果🌷>> \n {:?}   \n{状态:?}",json!(out) );
        }).ok();
    }
    
    #[cfg(all(test,feature = "mod_gtk"))]
    #[test]
    fn 通用(){
         
        let main_context = gio::glib::MainContext::default();
        let main_loop = gio::glib::MainLoop::new(Some(&main_context), false);
        // main_context.invoke_local(move || {  });        //异步回掉
        
        let __异步future = gio::glib::clone!(
            #[strong]
            main_loop,
            async move { 

                
                main_loop.quit();   
            }
        );
        main_context.spawn_local(__异步future);    //异步
        main_loop.run();

        
        
        let desktop = gio::DesktopAppInfo::search("lwleen");
        eprintln!("\ndesktop:  {:?}", desktop);
    }
    
  
    
}
