use std::{
    fs, time::Instant,
};
use xcap::{ Monitor,VideoRecorder };

use crate::prelude::*;

pub static 全局_屏幕录像管理: OnceCell<屏幕录像管理> = OnceCell::new(); 





#[gen_特征_derive(MOD特征_screen)]
impl 信令路由{
    async fn exec文本信令_screen(&self,函数名:&str, 参数数组:Vec<String>)-> anyhow_Result<(bool,Value,Vec<String>)>{
        let 信令路由ref = self;
        let 结果 = match 函数名{
            "屏幕_截图"=>{
                json!(信令路由ref.屏幕_截图().await?)
            }
            _=>{ return Ok((false, json!(""), 参数数组)); }
        };
        Ok((true, 结果, Vec::new()))
    }

    fn 屏幕_截图(&self)-> impl 信令任务<Vec<屏幕截屏信息>>{
        core发布信令任务!(self, 信令表::屏幕_截图 { },  信令表::屏幕_截图_回复 => 截图数组 )
    }
    fn 屏幕录像机_新建(&self)-> impl 信令任务<原子ID>{
        core发布信令任务!(self, 信令表::屏幕录像机_新建 { },  信令表::屏幕录像机_新建_回复 => video_id )
    }
    fn emit_屏幕录像机_输出数据流(&self, video_id: 原子ID,输出数据:屏幕录像帧){
        if let Some(通道数组) = self.core_chan数据流通道表().get(&video_id){
            if 通道数组.len()==1{  通道数组[0].force_send(Box::new(信令表::屏幕录像机_输出数据流 { video_id, 输出数据   })).ok();   }
            else{ for 通道 in 通道数组.iter(){  通道.force_send(Box::new(信令表::屏幕录像机_输出数据流 { video_id, 输出数据:输出数据.clone()   })).ok();  }     }
        }
    }
    fn emit_屏幕录像机_已退出(&self, video_id: 原子ID, 退出原因:String) {  self.task发布信令_单向(信令表::屏幕录像机_已退出 { video_id, 退出原因 });  }  
    fn on_屏幕录像机数据流<F>(&self, video_id: 原子ID, 外部回调:impl Fn(原子ID,屏幕录像帧) ->() + Send + 'static){
        let (发送tx,接收rx) =  async_unbounded();
        self.core_chan数据流通道表().entry(video_id)
                        .or_insert(Vec::new())
                        .push(发送tx);
        let _ = self.pool异步任务(async move{
            while let Ok(信令) = 接收rx.recv().await{
                if let Ok(信令表::屏幕录像机_输出数据流 { video_id, 输出数据  }) = 信令.try_into(){
                    外部回调(video_id, 输出数据);
                }else{ break; };
            }
        });
    }
}


#[derive(Clone, Serialize, Deserialize)]//可选特征
enum 信令表{
    屏幕录像机_新建{},
    屏幕录像机_新建_回复{ video_id:原子ID },
    屏幕录像机_控制{ video_id:原子ID,控制指令:屏幕录像机控制指令 },
    屏幕录像机_控制_回复,
    屏幕录像机_已退出{ video_id:原子ID, 退出原因:String },
    屏幕录像机_输出数据流{ video_id:原子ID, 输出数据:屏幕录像帧 },

    屏幕_截图{ },
    屏幕_截图_回复{ 截图数组:Vec<屏幕截屏信息>   },
}
impl信令特征!(信令表, 执行函数);


async fn 执行函数(信令路由:信令路由,id:信令ID,单个信令:信令表)->anyhow_Result<信令表>{
    let 录像管理 = 全局_屏幕录像管理.get_or_init(||屏幕录像管理::new(信令路由.clone()));
    
    match 单个信令{
        信令表::屏幕_截图{ } =>{
            let res =  信令路由.pool同步任务(move ||{  屏幕截图() }).await??;
            anyhow_Ok信令!(信令表::屏幕_截图_回复 { 截图数组:res })
        }
        信令表::屏幕录像机_新建{ }=>{
            let 结果 = 录像管理.启动屏幕录像机()
                .map(|video_id| 信令表::屏幕录像机_新建_回复{ video_id } ) ; 
            anyhow_Ok信令!(结果?)
        }
        信令表::屏幕录像机_控制{ video_id,  控制指令  }=>{
            let 结果 =  录像管理.控制屏幕录像机(video_id, 控制指令).map(|_|{  信令表::屏幕录像机_控制_回复  }); 
            anyhow_Ok信令!(结果?)
        }
        信令表::屏幕录像机_已退出{ video_id, 退出原因 }=>{
            return Err(anyhow_err!("屏幕录像机_已退出 {video_id} {退出原因}")); 
        }
        _ =>{ return Err(anyhow_err!("信令不存在")); }
    }
}



#[derive(Clone)]
pub struct 屏幕录像管理{
    信令路由:信令路由,
    记录录像机数组: Arc<DashMap<原子ID, VideoRecorder>>,
}
impl 屏幕录像管理 {
    pub fn new(信令路由:信令路由)->Self{
        Self{
            信令路由,
            记录录像机数组:Arc::new(DashMap::new()),
        }
    }
    pub fn 启动屏幕录像机(&self)->anyhow_Result<原子ID>{
        let video_id = 原子ID对象::next().0;
        let monitor = Monitor::from_point(100, 100).unwrap();
        let (video_recorder, sx) = monitor.video_recorder().unwrap();
        

        let 信令路由c1 = self.信令路由.clone();
        std::thread::spawn(move ||{
            let 退出原因;
            loop{
                match sx.recv() {
                    Ok(frame)=>{
                        let mut 录像帧 = 屏幕录像帧::default();
                        录像帧.video_id = video_id;
                        录像帧.宽度 = frame.width;
                        录像帧.高度 = frame.height;
                        录像帧.图片dataurl = 信令路由::fn_img转WEBP图片dataurl(frame.width,frame.height, frame.raw, None).unwrap_or_default();
                        信令路由c1.emit_屏幕录像机_输出数据流(video_id, 录像帧 );
                    }
                    Err(err)=>{ 退出原因 = err.to_string();  break; }
                }
            }
            信令路由c1.emit_屏幕录像机_已退出(video_id, 退出原因);
        });
        
        self.记录录像机数组.insert(video_id, video_recorder);
        Ok(video_id)
    }


    pub fn 控制屏幕录像机(&self, video_id:原子ID, 控制指令:屏幕录像机控制指令 )-> anyhow_Result<()>{
        let 录像机 = {  
            self.记录录像机数组.get(&video_id)
                .map(|a| { a.clone() }) 
                .ok_or(anyhow_err!("系统_屏幕录像机_控制  {video_id} 错误, 屏幕录像机 !!!"))?
        };


        match 控制指令{
            屏幕录像机控制指令::启动=>{ 录像机.start()?; }
            屏幕录像机控制指令::停止=>{ 录像机.stop()?; }
            屏幕录像机控制指令::销毁=>{ 
                录像机.stop().ok();   
                self.记录录像机数组.remove(&video_id);
            }
            屏幕录像机控制指令::销毁所有=>{ }
        }

        Ok(())
    }


}






pub fn 屏幕截图()->anyhow_Result<Vec<屏幕截屏信息>>{
    let start = Instant::now();
    let monitors = Monitor::all().unwrap();
    println!("屏幕截图 monitors 个数: {}  ",monitors.len());
    
    let mut 截图信息数组 = Vec::new();
    for monitor in monitors {
        let mut 截图信息 = 屏幕截屏信息::default();
        截图信息.id = monitor.id().unwrap_or_default();
        截图信息.名称 = monitor.name().unwrap_or_default();
        截图信息.x = monitor.x().unwrap_or_default();
        截图信息.y = monitor.y().unwrap_or_default();
        截图信息.宽度 = monitor.width().unwrap_or_default();
        截图信息.高度 = monitor.height().unwrap_or_default();
        let image = monitor.capture_image().unwrap();
        
        let 最终图片 = 信令路由::fn_img转WEBP图片dataurl(image.width(),image.height(), image.into_raw(), None).unwrap_or_default();
        截图信息.图片dataurl = 最终图片;
        截图信息数组.push(截图信息);
    }
    eprintln!("屏幕截图 运行耗时: {:?}", start.elapsed());
    Ok(截图信息数组)
}

 



#[derive(Debug,Serialize, Deserialize,Clone,Default)]
pub struct 屏幕截屏信息{
    pub id:u32, pub 名称:String,
    pub x:i32,pub y:i32,
    pub 宽度:u32,pub 高度:u32,
    pub 图片dataurl:String,
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub enum 屏幕录像机控制指令{
    启动,
    停止,
    销毁, 
    销毁所有,
}
#[derive(Debug,Serialize, Deserialize,Clone,Default)]
pub struct 屏幕录像帧{
    pub video_id:原子ID, pub 宽度:u32, pub 高度:u32,
    pub 图片dataurl:String
}




#[cfg(all(test,feature = "mod_screen"))]
mod  测试{
    use super::*;
    use std::{fs,path};
    #[cfg(all(test,feature = "mod_screen"))]
    #[test]
    fn 测试screen(){
        let 数组 = 屏幕截图().unwrap();
        let 文件 = path::Path::new("/home/lwl/Desktop/screen.txt");
        let _ = std::fs::write(文件, format!("ffmpeg\n\n\n结束"));
    }


}