using Aspose.Cells;
using Microsoft.Extensions.Caching.Memory;
using System.Collections.Concurrent;
using System.Data;
using System.Diagnostics;
using Txgy.RBS.DTO;
using Txgy.RBS.Framework;
using Txgy.RBS.Framework.Api;
using Txgy.RBS.Framework.FileWatcherHelper;
using Txgy.RBS.Framework.Models;
using Txgy.RBS.Framework.RedisHelper.Service;
using Txgy.RBS.IServices;

namespace Txgy.RBS.Services
{
    public class ProcessManagerService
    {
        private readonly IMemoryCache _cache;
        private readonly RedisListService _redisList;
        private readonly IResultInfoService _resultInfoService;

        public ProcessManagerService(RedisListService  redisList, IResultInfoService resultInfoService, IMemoryCache cache)
        {
            MoniTimer.Interval = 10000;
            MoniTimer.Elapsed += MoniTimer_Elapsed;
            MoniTimer.Start();
            this._redisList = redisList;
            this._resultInfoService = resultInfoService;
            _cache = cache;
            RedisServer = new ProcessInfo()
            {
                ProName = "server",
                StartTime = DateTime.Now,
                State = true
            };
        }
        public ProcessInfo RedisServer { get; set; }
      
        private void MoniTimer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
        {         
            foreach (var item in ProjectMonitor)
            {
                _redisList.Publish(CommonData.RedisPublish, Newtonsoft.Json.JsonConvert.SerializeObject(new
                {
                    projectName = item.Key,
                    ProName = RedisServer.ProName,
                    RunState = RedisServer.State?1:0,
                    RunTime = (DateTime.Now - RedisServer.StartTime).TotalSeconds,
                }));
                foreach (var proValue in item.Value.GetType().GetProperties())
                {
                    var pro = proValue.GetValue(item.Value) as ProcessInfo;
                    if (pro != null)
                    {
                        int sfp = FindProcess(pro);
                        if (sfp != 0)
                        {
                            pro.State = false;
                            Console.WriteLine($"{pro.ProName}程序重启中, path:{pro.ProPath}");
                            StartProcess(pro);
                            Thread.Sleep(20); 
                        }
                        else
                        {
                            pro.State = true;
                        }
                        _redisList.Publish(CommonData.RedisPublish, Newtonsoft.Json.JsonConvert.SerializeObject(new
                        {
                            projectName=item.Key,
                            ProName = pro.ProName,
                            RunState = sfp == 0 ? 1 : 0,
                            RunTime = (DateTime.Now - pro.StartTime).TotalSeconds,
                        }));
                    }
                }     
            }
        }
        
        public ConcurrentDictionary<string, ProcessConfig> ProjectMonitor = new ConcurrentDictionary<string, ProcessConfig>();

        public void StartMointor(string projectName, ProcessConfig processInfo)
        {
            if (!ProjectMonitor.ContainsKey(projectName))
            {
                ProjectMonitor.TryAdd(projectName, processInfo);
                processInfo.FilesWatcherService.InitializeParams();
                processInfo.FilesWatcherService.Start();
               processInfo.FilesWatcherService.WatcherFileChanged = WatcherChanged;
            }
        }
        System.Timers.Timer MoniTimer { get; set; } = new System.Timers.Timer();
        public void StopMointor(string projectName)
        {
            if (ProjectMonitor.ContainsKey(projectName))
            {
                ProjectMonitor.TryRemove(projectName, out ProcessConfig process);
                process.FilesWatcherService.Stop();
                foreach (var proValue in process.GetType().GetProperties())
                {
                    var pro = proValue.GetValue(process) as ProcessInfo;
                    if (pro != null)
                    {
                        _redisList.Publish(CommonData.RedisPublish, Newtonsoft.Json.JsonConvert.SerializeObject(new
                        {
                            projectName = projectName,
                            ProName = pro.ProName,
                            RunState = 0,
                            RunTime = (DateTime.Now - pro.StartTime).TotalSeconds,
                        }));
                    }
                }
            }
        }

        void WatcherChanged(MsEventModel msEvent, FileSystemEventArgs e)
        {

            var path= Path.GetDirectoryName(e.FullPath);
            var dir =  new DirectoryInfo(path);
            var files= dir.GetFiles("*.json");
            string name = $"HA.{msEvent.OriginTime.Year}{msEvent.OriginTime.Month:D2}{msEvent.OriginTime.Day:D2}T{msEvent.OriginTime.Hour:D2}{msEvent.OriginTime.Minute:D2}{msEvent.OriginTime.Second:D2}";
            string jsonStr = string.Empty;
            foreach (var item in files)
            {
                if (item.FullName.Contains(name))
                {
                    jsonStr= File.ReadAllText(item.FullName);
                    break;
                }
            }
            _resultInfoService.AddResultInfo(new ResultDTO
            {
                project_id = msEvent.ProjectId,
                otime = msEvent.OriginTime.ToString("O"),
                xlon = msEvent.EastCoordinate,
                ylat = msEvent.NorthCoordinate,
                depth = msEvent.Depth,
                ml = msEvent.ML,
                energy = msEvent.Energy,
                json_str= jsonStr,
                phases_count = msEvent.PhasesCount,
                amps_count = msEvent.AmpsCount,
            });
            _redisList.Publish($"{msEvent.ProjectName}result", Newtonsoft.Json.JsonConvert.SerializeObject(new
            {
                projectName = msEvent.ProjectName,
                otime = msEvent.OriginTime,
                message = msEvent.ToString(),
                jsonStr = jsonStr
            }));
        }


        #region 方法

        public ApiResult StartProject(string projectName, ProcessConfig processConfig)
        {
            int res = 0;
            if (ProjectMonitor.ContainsKey(projectName))
            {
                return new ApiResult();
            } 
            foreach (var item in processConfig.GetType().GetProperties())
            {
                var pro = item.GetValue(processConfig) as ProcessInfo;
                if (pro != null && pro.IsEnable)
                {
                    res = StartProcess(pro);
                    if (res != 0)
                    {
                        continue;
                    }
                    pro.StartTime = DateTime.Now;
                    pro.State = true;
                 //   _cache.Set(pro.ProPath, pro);
                    Thread.Sleep(10);
                }
            }
            StartMointor(projectName, processConfig);

            if (res == 0)
            {
                return new ApiResult();
            }
            return new ApiResult() { Message = "操作失败" };

        }

        public ApiResult StopProject(string projectName)
        {
            int res = 0;
            ProjectMonitor.TryGetValue(projectName, out ProcessConfig process);
            if(process == null) { return new ApiResult(); }
            foreach (var item in process.GetType().GetProperties())
            {
                var pro = item.GetValue(process) as ProcessInfo;
                if (pro != null && pro.IsEnable)
                {
                    res = KillProcess(pro);
                    if (res != 0)
                    {
                        break;
                    }
                    pro.State = false;
                  //  _cache.Set(pro.ProPath, pro);
                    Thread.Sleep(10);
                }
            }
            StopMointor(projectName);
            if (res == 0)
            {
                return new ApiResult();
            }
            return new ApiResult() { Message = "操作失败" };
        }

        private bool CMDStartProcess(ProcessInfo proInfo)
        {
            //* Create your Process
            Process process = new Process();
            process.Exited += Process_Exited;
            process.EnableRaisingEvents = true;
            process.StartInfo.FileName = Path.GetFullPath(Path.Combine(proInfo.ProPath, proInfo.ProName + ".exe"));
            process.StartInfo.WorkingDirectory = Path.GetFullPath(proInfo.ProPath);
            process.StartInfo.Arguments = proInfo.ProParams;
            Debug.WriteLine($"*******ProcessName:{process.StartInfo.FileName}, arguments:{process.StartInfo.Arguments}*********");
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;
            process.StartInfo.CreateNoWindow = true;
            //* Set your output and error (asynchronous) handlers
            {
                process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
                process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
            }
            //* Start process and handlers
            bool res = process.Start();
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();
            //  process.WaitForExit();
            return res;
        }

        private void Process_Exited(object? sender, EventArgs e)
        {

        }

        void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
        {
            Debug.WriteLine("output*************:{0},{1}", sendingProcess.ToString(), outLine.Data);
            if (string.IsNullOrEmpty(outLine.Data)) return;
            if (outLine.Data.Contains("ProcessSlice:"))
            {
                var pro = sendingProcess as Process;
                if (pro != null)
                {

                }
            }
            else if (outLine.Data.Contains("ML "))
            {
                var pro = sendingProcess as Process;
                if (pro != null)
                {
                 var msEvent=  new MsEventModel(outLine.Data) { CurrentTime = DateTime.Now };
                    Console.WriteLine($"processName:{pro.ProcessName},message:{outLine.Data}");
                }
            }
        }

        public int StartProcess(ProcessInfo proInfo)
        {
            bool res = CMDStartProcess(proInfo);
            int seInd = res ? 0 : 1;
            return seInd;
        }
        /// <summary>
        /// 结束进程
        /// </summary>
        /// <param name="processInfo"></param>
        /// <returns>0=成功;1=未找到进程;-1=失败</returns>
        private int KillProcess(ProcessInfo processInfo)
        {
            int ri = 0;
            if (processInfo != null)
            {
                if (processInfo.ProName != null)
                {
                    try
                    {
                        Process[] localByName = Process.GetProcessesByName(processInfo.ProName);
                        if (localByName.Length == 0)
                        {
                            ri = 1;
                            return ri;
                        }
                        foreach (var item in localByName)
                        {
                            item.Kill();
                        }
                        return ri;
                    }
                    catch (Exception)
                    {
                        return -1;
                    }
                }
                else
                {
                    return 0;
                }
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// 查找进程
        /// </summary>
        /// <param name="processInfo"></param>
        /// <returns>0=正在运行;1=未运行;-1=系统错误</returns>
        private int FindProcess(ProcessInfo processInfo)
        {
            int ri = 0;
            try
            {
                Process[] localByName = Process.GetProcessesByName(processInfo.ProName);
                if (localByName.Length == 0)
                {
                    ri = 1;
                    return ri;
                }
                else
                {
                    List<Process> pro = null;
                    if (processInfo.ProName == "server")
                    {
                        pro = localByName.Where(p => p.MainModule.FileName.Contains(processInfo.ProName)).ToList();
                    }
                    else
                    {
                        pro = localByName.Where(p => p.MainModule.FileName.Contains(processInfo.ProPath)).ToList();
                    }
                    if (!pro.Any())
                    {
                        ri = 1;
                    }
                    return ri;
                }
            }
            catch (Exception)
            {
                return -1;
            }
        }

        public string ProcessStatus { get; set; }


        public ApiResult GetState(string projectName, int id)
        {
            ProcessInfo pro = null;
           if(id==1)
            {
                pro = this.RedisServer;
            }
            ProjectMonitor.TryGetValue(projectName, out ProcessConfig process);
            if (process == null || (id < 1|| id > 3)) { return new ApiResult(); }
            pro = id == 1 ?pro:(id==2)? process.Apms : process.RecvMqtt;
            int sfp = FindProcess(pro);
            if (sfp != 0)
            {
                return new ApiResult { Code = System.Net.HttpStatusCode.NotFound };
            }
            return new ApiResult
            {
                Code = System.Net.HttpStatusCode.OK,
                Data = new
                {
                    name = pro.ProName,
                    state = sfp == 0 ? 1 : 0,
                    start_time = pro.StartTime,
                    running_time = (DateTime.Now - pro.StartTime).TotalSeconds,
                }
            };
        }

        #endregion



        public ApiResult ExportCSV(string fileName, List<StationDTO> stations)
        {
            DataTable dataTable = new DataTable();
            string[] header = new string[] { "project_id", "net", "sta"," x2000", "y2000", "z2000", "sens", "begin", "stop", "sitenum" };
            DataColumn da = new DataColumn();
            foreach (var item in header)
            {
                dataTable.Columns.Add(item, typeof(string));
            }
            foreach (var sta in stations)
            {
                dataTable.Rows.Add(sta.project_id, sta.network,sta.num,sta.coord_e,sta.coord_n,sta.altitude,sta.sens,sta.begin_time,sta.end_time,sta.site_number);
            }
            return ExportExcel(fileName,dataTable, header);
        }
        /// 导出csv表格
        /// </summary>
        /// <param name="list">数据集合</param>
        /// <param name="header">数据表头</param>
        /// <param name=" title"> 标题</param>
        /// <returns></returns>
        private ApiResult ExportExcel(string fileName, DataTable dt, string[] header, string title = null)
        {
            Workbook wb = new Workbook();
            try
            {
                Worksheet sheet = wb.Worksheets[0];
                sheet.Name = "station数据";
                if (dt.Rows.Count <= 0)
                {
                    return new ApiResult() { Code= System.Net.HttpStatusCode.NoContent,Message="没有数据"};
                }
                // 为单元格添加样式
                Aspose.Cells.Style style = wb.CreateStyle();
                //style.HorizontalAlignment = Aspose.Cells.TextAlignmentType.Center;  //设置居中
                style.Font.Size = 20;//文字大小
                style.Font.IsBold = true;//粗体
                style.HorizontalAlignment = TextAlignmentType.Center;//文字居中

                // 为合计单元格样式
                Aspose.Cells.Style sumstyle = wb.CreateStyle();
                sumstyle.Font.Size = 12;//文字大小
                sumstyle.Font.IsBold = true;//粗体
                sumstyle.Font.Color = System.Drawing.Color.Red;   //颜色
                //style.HorizontalAlignment = TextAlignmentType.Center;//文字居中

                //添加标题
                int rowIndex = 0;
                sheet.Cells.SetRowHeight(rowIndex, 40); //设置行高
                if (title != null)
                {
                    sheet.Cells[rowIndex, 0].PutValue(title);
                    sheet.Cells[rowIndex, 0].SetStyle(style);
                    sheet.Cells.Merge(0, 0, 1, header.Length); //合并行 Merge(1, 1,1, 5); 第一行 第一列 到 第一行 第 5列  
                    //Merge切记后两位参数不能是 0 
                    rowIndex++;
                }
                //添加表头
                style.Font.Size = 12;//文字大小
                sheet.Cells.SetRowHeight(rowIndex, 20); //设置行高
                for (int c = 0; c < header.Length; c++)
                {
                    sheet.Cells[rowIndex, c].PutValue(header[c]);
                    sheet.Cells[rowIndex, c].SetStyle(style);
                    sheet.Cells.SetColumnWidth(c, 20);//设置宽度
                }
                rowIndex++;

                //添加内容
                for (int r = 0; r < dt.Rows.Count; r++)//遍历DataTable行
                {
                    for (int c = 0; c < header.Length; c++) //列只遍历到和表头数量相等的列，其余的列不导出
                    {
                        //自动把数字变量转出后 单元格变为数字类型。
                        try
                        {
                            //把添加变量转字符类型存储
                            sheet.Cells[r + rowIndex, c].PutValue(dt.Rows[r][c].ToString());

                            //  sheet.Cells[r + rowIndex, c].PutValue(Convert.ToDecimal(dt.Rows[r][c])); //要导出数字列是数字类型，必须把添加变量转数字类型。
                        }
                        catch
                        {
                            //把添加变量转字符类型存储
                            sheet.Cells[r + rowIndex, c].PutValue(dt.Rows[r][c].ToString());
                        }
                    }
                }
                //输出到Excel 
                wb.Save(fileName, new OoxmlSaveOptions(SaveFormat.Csv));
                //保存成97或2003写法
                //workbook.Save(“output.xls, New XlsSaveOptions(SaveFormat.Excel97To2003))
                // 释放Excel对象
                sheet.Dispose();
                wb.Dispose();
            }
            catch (Exception e)
            {
                return new ApiResult() { Code = System.Net.HttpStatusCode.NoContent, Message = $"保存{fileName}文件异常:{e.Message}" };
            }
            return new ApiResult();
        }

    }
}
