using Newtonsoft.Json.Linq;
using PTMedicalInsurance.Helper;
using PTMedicalInsurance.Variables;
using System;
using System.IO;
using System.IO.Compression;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace PTMedicalInsurance.Business
{
    public class ElectronicSettlementCertificate
    {
        public string ecSettlCertNo;
        public string upldBchno;
        private string xmlPath;
        private string folderPath;
        private string xmlName;
        private string pdfName;
        private string savePath;  //保存路径
        private InvokeHelper invoker = new InvokeHelper();
        private MIIrisServices mIs = new MIIrisServices();
        public ElectronicSettlementCertificate()
        { 
        
        }

        // 路径属性
        public string SavePath
        {
            get { return savePath; } // 获取
            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    throw new ArgumentException("路径不能为空", nameof(value));
                }
                savePath = value; // 设置
                if (!Directory.Exists(savePath))
                {
                    Directory.CreateDirectory(savePath);
                }
            }
        }


        #region 获取入参
        public JObject Get4901Input(JObject joIn)
        {
            //JoIn包含 患者数电号
            JObject joRtn = invoker.invokeHISService(JsonHelper.setIrisInpar("05110041", joIn).ToString(), "获取该数电号对应的数电入参"); //测试服05110039
            return joRtn;
        }

        #endregion

        #region  解构入参

        
        /// <summary>
        /// 异步下载，会造成压缩时文件还没生成，导致压缩包内容与实际文件夹内容不符
        /// </summary>
        /// <param name="url"></param>
        /// <param name="filePath"></param>
        /// <returns></returns>
        private async Task<bool> DownloadPdfFileAsync(string url, string filePath)
        {
            try
            {
                using (var httpClient = new HttpClient())
                {
                    // 发送GET请求获取内容
                    HttpResponseMessage response = await httpClient.GetAsync(url);
                    if (response.IsSuccessStatusCode)
                    {
                        // 读取内容到字节数组
                        byte[] fileBytes = await response.Content.ReadAsByteArrayAsync();
                        // 将字节数组写入文件
                        File.WriteAllBytes(filePath, fileBytes);

                        return true;
                    }
                    else
                    {
                        Console.WriteLine($"无法下载文件，状态码：{response.StatusCode}");
                        return false;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"下载过程中发生错误：{ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 同步下载
        /// </summary>
        /// <param name="url"></param>
        /// <param name="filePath"></param>
        /// <returns></returns>
        private bool DownloadPdfFile(string url, string filePath)
        {
            Global.writeLog("DownloadPdfFile", url,filePath);
            try
            {
                using (var httpClient = new HttpClient())
                {
                    // 发送GET请求获取内容
                    HttpResponseMessage response = httpClient.GetAsync(url).Result;
                    if (response.IsSuccessStatusCode)
                    {
                        // 读取内容到字节数组
                        byte[] fileBytes = response.Content.ReadAsByteArrayAsync().Result;
                        // 将字节数组写入文件
                        File.WriteAllBytes(filePath, fileBytes);

                        return true;
                    }
                    else
                    {
                        Global.writeLog($"无法下载文件，状态码：{response.StatusCode}");
                        return false;
                    }
                }
            }
            catch (Exception ex)
            {
                Global.writeLog($"下载过程中发生错误：{ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 保存XML文件
        /// </summary>
        /// <param name="jaXML"></param>
        private void SaveXML(JArray jaXML)
        {
            foreach (JObject jo in jaXML)
            {
                //税务数电票结构化数据文件（xml），命名规则为：电子结算凭证号码-extinfo  ，因可能存在多条结算信息， 命名规则为：电子结算凭证号码-结算ID-extinfo
                ecSettlCertNo = JsonHelper.getDestValue(jo, "tktextinfo.billInfo.elecSetlCertNo");
                string setlId = JsonHelper.getDestValue(jo, "tktextinfo.mdtrtInfo.setlId");
                //xmlName = $"{ecSettlCertNo}-{setlId}-extinfo.xml";
                xmlName = $"{ecSettlCertNo}-extinfo.xml";
                pdfName = $"{ecSettlCertNo}.pdf";
                // 创建临时XML文件
                folderPath = $@"{savePath}\ElecXml\{ecSettlCertNo}";
                xmlPath = $@"{savePath}\ElecXml\{ecSettlCertNo}\{xmlName}";
                if (!Directory.Exists(folderPath))
                {
                    Directory.CreateDirectory(folderPath);
                }
                XmlHelper xmler = new XmlHelper();
                string xmlContent = xmler.ToXML(jo.ToString());
                XElement xe = XElement.Parse(xmlContent);
                string xml = xmler.setInput(xe);
                File.WriteAllText(xmlPath, xml, Encoding.UTF8);
            }
        }
       
     
        /// <summary>
        /// 压缩指定的文件夹及其内容到ZIP文件中。
        /// </summary>
        /// <param name="sourceFolderPath">源文件夹路径。</param>
        /// <param name="zipFilePath">输出的ZIP文件路径。</param>
        private void CompressFolderToZIP(string sourceFolderPath, string zipFilePath)
        {
            if (!Directory.Exists(sourceFolderPath))
            {
                throw new DirectoryNotFoundException($"源文件夹不存在: {sourceFolderPath}");
            }

            try
            {
                using (FileStream fileStream = new FileStream(zipFilePath, FileMode.Create))
                {
                    using (ZipArchive archive = new ZipArchive(fileStream, ZipArchiveMode.Create, true))
                    {
                        //AddFolderToZip(archive, sourceFolderPath, Path.GetFileName(sourceFolderPath));
                        AddFolderToZip(archive, sourceFolderPath, ""); //相对路径，为空则表示ZIP无第一层
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"压缩文件夹时发生错误: {ex.Message}");
            }
        }

        /// <summary>
        /// 递归地将文件夹添加到ZIP存档中。
        /// </summary>
        /// <param name="archive">ZIP存档对象。</param>
        /// <param name="folderPath">当前处理的文件夹路径。</param>
        /// <param name="basePath">基础路径，用于构建ZIP内的相对路径。</param>
        private static void AddFolderToZip(ZipArchive archive, string folderPath, string basePath)
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(folderPath);

            // 添加当前文件夹中的所有文件到ZIP存档
            foreach (FileInfo fileInfo in directoryInfo.GetFiles())
            {
                string entryPath = Path.Combine(basePath, fileInfo.Name);
                ZipArchiveEntry entry = archive.CreateEntry(entryPath);
                using (FileStream stream = fileInfo.OpenRead())
                {
                    using (Stream entryStream = entry.Open())
                    {
                        stream.CopyTo(entryStream);
                    }
                }
            }

            // 递归地处理所有子文件夹
            foreach (DirectoryInfo subDirInfo in directoryInfo.GetDirectories())
            {
                string subFolderPath = Path.Combine(folderPath, subDirInfo.Name);
                string subBasePath = Path.Combine(basePath, subDirInfo.Name);
                AddFolderToZip(archive, subFolderPath, subBasePath);
            }
        }

        /// <summary>
        /// 转换位Base64
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private string ZipTobase64(string path)
        {
            byte[] zipBytes = File.ReadAllBytes(path);
            return Convert.ToBase64String(zipBytes);
        }



        private  string FormatToFiveDigits(int seconds)
        {
            // 确保秒数不会超过五位数的最大值
            if (seconds > 86400)
                throw new ArgumentOutOfRangeException("秒", "一天的秒数不能超过86400");

            // 使用格式化字符串将秒数转换为五位数的字符串
            return seconds.ToString("D5");
        }

        /// <summary>
        /// 根据当天0点计算当前时刻的5位时间戳，然后加上当前日期，组成序号。要求每个上传时间需要超过1秒，否则会有重复问题
        /// </summary>
        /// <returns></returns>
        private string GetSeqNoBySecondStamp()
        {
            // 获取当天零点的时间
            DateTime todayMidnight = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day);

            // 计算从当天零点到现在的时间差（秒）
            TimeSpan timeSinceMidnight = DateTime.Now - todayMidnight;
            int secondsSinceMidnight = (int)timeSinceMidnight.TotalSeconds;

            // 将秒数转换为5位时间戳
            return DateTime.Now.ToString("yyyyMMdd") + FormatToFiveDigits(secondsSinceMidnight); //2024102168281
            //return DateTime.Now.ToString("yyyyMMdd") + "68282"; // 68281
        }
        /// <summary>
        /// 正式解构HIS返回的入参，包括医保编码转换，PDF下载，XML文件保存，ZIP压缩，zip转Base64,业务编号命名等
        /// </summary>
        /// <param name="joSource"></param>
        /// <returns></returns>
        public JObject Convert4901Input(JObject joSource)
        {
            //调用医保服务开始转换为医保对应的编码 09010127
            JObject joConvertRtn = mIs.convertEcSettlUploadInpar(joSource);
            JObject joData = JObject.Parse(JsonHelper.getDestValue(joConvertRtn,"data"));
            //指定PDF，xml文件，xml文件夹路径
            //保存xml ,保存过程中给路径等私有变量赋值
            SaveXML(JArray.Parse(JsonHelper.getDestValue(joData, "xml")));
            //保存PDF
            string pdfUrl = JsonHelper.getDestValue(joData, "pdfUrl");
            //DownloadPdfFileAsync(pdfUrl,$@"{folderPath}\{pdfName}");
            DownloadPdfFile(pdfUrl, $@"{folderPath}\{pdfName}");
            //压缩文件为ZIP,并保存到文件夹同级
            CompressFolderToZIP(folderPath, $@"{savePath}\ElecXml\{ecSettlCertNo}.zip");
            //转换ZIP为Base64
            string base64 = ZipTobase64($@"{savePath}\ElecXml\{ecSettlCertNo}.zip");
            joData["ftfileCompac"] = base64;
            joData["filename"] = $@"{ecSettlCertNo}.zip";
            joData["elecSetlCertCnt"] = int.Parse(joData["elecSetlCertCnt"].ToString()) + 1;
            upldBchno = GetSeqNoBySecondStamp();
            joData["upldBchno"] = upldBchno;//上传日期年月日加5位顺序号
            //移除PDF和xml节点
            joData.Remove("xml");
            joData.Remove("pdfUrl");

            return joData;
        }
        #endregion

        #region 查询，反写数据库
        /// <summary>
        /// 查询患者电子发票
        /// </summary>
        /// <param name="joIn"></param>
        /// <returns></returns>
        public JObject QueryEcSettlCertList(JObject joIn)
        {
            //JoIn包含 起止时间，医院ID，接口ID，患者姓名，患者数电号
            JObject joHisRtn = invoker.invokeHISService(JsonHelper.setIrisInpar("05110040", joIn).ToString(), "查询某时间段内或某患者电子结算凭证清单");  //测试服为05110038
            string errMsg;
            if (JsonHelper.parseIrisRtnValue(joHisRtn, out errMsg) != 0)
            {
                return joHisRtn;
            }
            JArray jaData = JArray.Parse(JsonHelper.getDestValue(joHisRtn,"data"));
            JObject joInsuRtn = invoker.invokeInsuService(JsonHelper.setIrisInpar("09010128", jaData).ToString(), "根据传入的电子凭证记录匹配上传记录表");
            return joInsuRtn;
        }


        /// <summary>
        /// 查询患者电子发票
        /// </summary>
        /// <param name="joIn"></param>
        /// <returns></returns>
        public JObject MatchUploadRecord(JObject joIn)
        {
            //JoIn包含 起止时间，医院ID，接口ID，患者姓名，患者数电号
            JObject joRtn = invoker.invokeHISService(JsonHelper.setIrisInpar("05110040", joIn).ToString(), "查询某时间段内或某患者电子结算凭证清单");
            return joRtn;
        }



        /// <summary>
        /// 成功后更新记录表
        /// </summary>
        /// <param name="joIn"></param>
        /// <returns></returns>
        public JObject Update(JObject joIn)
        {
            //JoIn包含 起止时间，医院ID，接口ID，患者姓名，患者数电号
            JObject joInTmp = JsonHelper.setIrisInpar("02020007", joIn);
            joInTmp["session"][0]["userID"] = "166";
            joInTmp["session"][0]["hospID"] = Global.inf.hospitalDr;
            JObject joRtn = invoker.invokeInsuService(joInTmp.ToString(),"更新通用记录表");
            return joRtn;
        }


        #endregion

        #region 具体功能点封装

        /// <summary>
        /// 上传
        /// </summary>
        /// <param name="joIn"></param>
        /// <returns></returns>
        public JObject Upload(JObject joIn)
        {
            JObject joRtn = invoker.invokeCenterService("4901", JsonHelper.setCenterInpar("4901", joIn));
            return joRtn;
        }


        /// <summary>
        /// 重新上传
        /// </summary>
        /// <param name="joIn"></param>
        /// <returns></returns>
        public JObject ReUpload(JObject joIn)
        {
            JObject joRtn = invoker.invokeCenterService("4905", JsonHelper.setCenterInpar("4905", joIn));
            return joRtn;
        }


        /// <summary>
        /// 查询上传结果
        /// </summary>
        /// <param name="joIn"></param>
        /// <returns></returns>
        public JObject QueryUploadResult(JObject joIn)
        {
            JObject joRtn = invoker.invokeCenterService("4902", JsonHelper.setCenterInpar("4902", joIn));
            return joRtn;
        }

        /// <summary>
        /// 查询电子凭证上传状态
        /// </summary>
        /// <param name="joIn"></param>
        /// <returns></returns>
        public JObject QueryUploadStatus(JObject joIn)
        {
            JObject joRtn = invoker.invokeCenterService("5501", JsonHelper.setCenterInpar("5501", joIn));
            return joRtn;
        }
        #endregion

        #region 具体流程封装


        #endregion 
    }
}
