using DevExpress.XtraEditors;
using DevExpress.XtraSplashScreen;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using NPOI.SS.Util;
using DeviceRepair.Models;
using DeviceRepairAndOptimization.Models.Enum;
using DeviceRepairAndOptimization.Biz;
using DeviceRepairAndOptimization.Common;

namespace DeviceRepairAndOptimization.Pages.Plan
{
    public partial class page_PlanExcelImport : Form
    {
        #region 函数

        public page_PlanExcelImport()
        {
            InitializeComponent();
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer,
                true);
        }

        #endregion

        #region 属性

        Dictionary<string, string> keyValuePairs;

        StringBuilder logs = new StringBuilder();

        string[] Keys = { "Monthly", "Annual", "Quarterly", "Semi-an" };

        #endregion

        #region 事件

        /// <summary>
        /// 底部panel控件 - 添加边框
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void panel_bottom_Paint(object sender, PaintEventArgs e) =>
            (sender as Control).ControlBoardPoint(e, Direction.Up);

        /// <summary>
        /// 底部panel控件 - 添加边框
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void panel_top_Paint(object sender, PaintEventArgs e) =>
            (sender as Control).ControlBoardPoint(e, Direction.Down);

        /// <summary>
        /// 页面加载完成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void page_PlanExcelImport_Load(object sender, EventArgs e)
        {
            EditYear.ToYearStyle();
            this.Invalidate();
            this.FormBoardPoint(Direction.Left, Direction.Up, Direction.Right, Direction.Down);
            this.EditYear.Properties.NullValuePrompt = DateTime.Today.Year + "";
        }

        /// <summary>
        /// 窗口关闭
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Close_Click(object sender, EventArgs e) => this.Close();

        /// <summary>
        /// 重写窗口拖动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                ReleaseCapture();
                PostMessage((int)this.Handle, WM_SysCommand, OneMsgNum, 0);
            }
        }

        /// <summary>
        /// 取消
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Exit_Click(object sender, EventArgs e)
        {
            this.Close();
        }


        DateTime ClickTime;

        private void EditFilePath_Properties_Click(object sender, EventArgs e)
        {
            if (ClickTime == null || (DateTime.Now - ClickTime).TotalSeconds > 2)
            {
                //扩展 - 自定义待选择文件类型
                OpenFileDialog ofd = new OpenFileDialog();
                //自定义待选择文件类型
                ofd.Filter = "Excel文件|*.xls;*.xlsx;*.xlsm;";
                if (ofd.ShowDialog() == DialogResult.OK)
                {
                    EditFilePath.Text = ofd.FileName;
                }
            }

            ClickTime = DateTime.Now;
        }

        /// <summary>
        /// 查看导入报错日志
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lb_logs_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (logs.Length == 0)
            {
                XtraMessageBox.Show("当前没有日志信息！", "信息");
            }
            else
            {
                new page_XtraFormLog("日志信息", logs).ShowDialog();
            }
        }

        /// <summary>
        /// 导入的事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Import_Click(object sender, EventArgs e)
        {
            logs.Clear();
            SplashScreenManager.ShowDefaultWaitForm("Excel导入中...", "请稍等...");

            string filePath = EditFilePath.Text;
            DataTable dataTable = new DataTable();
            if (string.IsNullOrEmpty(filePath))
            {
                XtraMessageBox.Show("请选择待导入的文件", "错误");
                return;
            }

            try
            {
                int CurrentMaintenanceYear = Convert.ToInt32(!string.IsNullOrWhiteSpace(EditYear.Text)
                                            ? EditYear.Text
                                            : DateTime.Today.Year + "");

                APIResponseData apiResponseData = DeviceManager.Instance.GetQuery("");
                if (!apiResponseData.IsSuccess)
                    throw new Exception(apiResponseData.Message);

                List<DeviceInformationInfo> driveLst = apiResponseData.ToDeserializeObject<List<DeviceInformationInfo>>();

                logs.AppendLine("正在打开Excel文件");
                using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                {
                    IWorkbook workbook;
                    if (Path.GetExtension(filePath) == ".xls")
                    {
                        logs.AppendLine("处理.xls文件");
                        workbook = new HSSFWorkbook(fs); // 处理.xls文件
                    }
                    else if (Path.GetExtension(filePath) == ".xlsx")
                    {
                        logs.AppendLine("处理.xlsx文件");
                        workbook = new XSSFWorkbook(fs); // 处理.xlsx文件
                    }
                    else
                    {
                        logs.AppendLine("不支持的文件格式");
                        SetWaitFormDescription(null, "操作失败，请重试");
                        Thread.Sleep(500);
                        // 关闭等待窗口
                        SplashScreenManager.CloseDefaultWaitForm();
                        return;
                    }

                    logs.AppendLine("正在读取文件内容");
                    SetWaitFormDescription(null, "正在读取文件内容");


                    ISheet sheet = workbook.GetSheetAt(0); // 获取第一个工作表
                    logs.AppendLine("获取第一个工作表");

                    logs.AppendLine("读取表头（第一行）并将其添加到 DataTable 中");

                    // 读取表头（第一行）并将其添加到 DataTable 中
                    IRow headerRow = sheet.GetRow(0);
                    for (int i = 0; i < headerRow.LastCellNum; i++)
                    {
                        ICell headerCell = headerRow.GetCell(i);
                        if (headerCell != null)
                        {
                            dataTable.Columns.Add(headerCell.ToString());
                        }
                    }

                    SetWaitFormDescription(null, "文件读取完成");
                    Thread.Sleep(200);
                    SetWaitFormDescription(null, "映射关系建立中");

                    bool hasError = false;
                    logs.AppendLine("读取数据行并将其添加到 DataTable 中");
                    // 读取数据行并将其添加到 DataTable 中
                    for (int rowIndex = 1; rowIndex <= sheet.LastRowNum; rowIndex++)
                    {
                        try
                        {
                            IRow dataRow = sheet.GetRow(rowIndex);
                            if (dataRow != null)
                            {
                                DataRow newRow = dataTable.NewRow();

                                if (dataRow.GetCell(0) == null)
                                    continue;

                                for (int colIndex = 0; colIndex < dataRow.LastCellNum; colIndex++)
                                {
                                    ICell cell = dataRow.GetCell(colIndex);
                                    if (cell != null)
                                    {
                                        if (cell.CellType == CellType.Numeric && DateUtil.IsCellDateFormatted(cell))
                                        {
                                            // 将单元格值转换为日期
                                            DateTime dateValue = cell.DateCellValue;
                                            newRow[colIndex] = dateValue;
                                        }
                                        else
                                        {
                                            newRow[colIndex] = cell.ToString();
                                        }
                                    }
                                }


                                #region 校验设备信息

                                DeviceInformationInfo di = driveLst.Where(x => x.EquipmentID == (newRow[0] + "")).FirstOrDefault();
                                if (di == null)
                                {
                                    hasError = true;
                                    throw new Exception($"不存在设备编号为：{(newRow[0] + "")}的设备！");
                                }
                                #endregion

                                #region 校验计划是否冲突

                                apiResponseData = PlanManager.Instance.GetPlanRecordProgress(di.AutoID, CurrentMaintenanceYear);
                                if (apiResponseData.IsSuccess)
                                {
                                    List<PlanProgress> progress = apiResponseData.ToDeserializeObject<List<PlanProgress>>();
                                    if (progress != null && progress.Count > 0)
                                    {
                                        foreach (PlanProgress item in progress)
                                        {
                                            if (newRow[Enum.Parse(typeof(enumMonth), item.PlanMonth + "") + ""] + "" != item.PlanType)
                                            {
                                                hasError = true;
                                                throw new Exception($"设备编号为：{(newRow[0] + "")}的设备中，存在已保养{Enum.Parse(typeof(enumMonth), item.PlanMonth + "")}月份的年度数据，无法修改！");
                                            }
                                        }
                                    }
                                }

                                #endregion


                                dataTable.Rows.Add(newRow);
                            }
                        }
                        catch (Exception ex)
                        {
                            logs.AppendLine($"行{rowIndex}出现错误:{ex.Message}");
                        }
                    }

                    if (hasError)
                    {
                        throw new Exception("导入的数据存在错误！");
                    }

                    //读取键值对
                    KeyValuePairsBind();

                    List<DriveMaintencePlanInfo> lst = new List<DriveMaintencePlanInfo>();
                    logs.AppendLine("数据对应关系映射开始...");

                    int NotFoundCount = 0;
                    foreach (DataRow item in dataTable.Rows)
                    {
                        string EquipmentID = item[keyValuePairs["EquipmentID"]] + "";
                        DeviceInformationInfo di = driveLst.Where(x => x.EquipmentID == EquipmentID).FirstOrDefault();
                        if (lst.Any(x => x.EquipmentID == di.AutoID))
                        {
                            //logs.AppendLine($"设备编号为:{EquipmentID}的设备数据,在表格中存在多条！");
                            throw new Exception($"设备编号为:{EquipmentID}的设备数据,在表格中存在多条！");
                        }

                        if (di != null)
                        {
                            foreach (KeyValuePair<string, string> kvp in keyValuePairs)
                            {
                                enumMonth em;
                                if (Enum.TryParse(kvp.Value, out em)
                                    //&& !string.IsNullOrEmpty(item[kvp.Value] + "")
                                    )
                                {
                                    DriveMaintencePlanInfo itemModel = new DriveMaintencePlanInfo
                                    {
                                        EquipmentID = di.AutoID,
                                        CompleteDate = null,
                                        MaintenanceYear = Convert.ToInt32(!string.IsNullOrWhiteSpace(EditYear.Text)
                                            ? EditYear.Text
                                            : DateTime.Today.Year + ""),
                                        MaintenanceMonth = (int)em,
                                        MaintenanceType = item[kvp.Value] + "",
                                        Remarks = item[keyValuePairs["Comment"]] + "",
                                        PMStartMonth = DateTime.Now,
                                        CreatDate = DateTime.Today,
                                        CreatUser = GlobalInfo.CurrentUser.AutoID,
                                        ChangeDate = DateTime.Today,
                                        ChangeUser = GlobalInfo.CurrentUser.AutoID
                                    };

                                    DateTime pMStartMonth = DateTime.Now;
                                    if (DateTime.TryParse((item[keyValuePairs["StartMonth"]] + ""), out pMStartMonth))
                                    {
                                        itemModel.PMStartMonth = pMStartMonth;
                                    }

                                    lst.Add(itemModel);
                                }
                            }
                        }
                        else
                        {
                            NotFoundCount++;
                            logs.AppendLine($"程序中不存在设备编号为:{EquipmentID}的设备数据.");
                        }
                    }

                    SetWaitFormDescription(null, "开始保存！");

                    if (lst.Count == 0 && NotFoundCount > 0)
                        throw new Exception("导入的设备编号不存在！");
                    else if (lst.Count == 0)
                        throw new Exception("导入的数据为空！");

                    apiResponseData = PlanManager.Instance.InsertDatas(lst);

                    if (apiResponseData.IsSuccess)
                    {
                        SplashScreenManager.Default.SetWaitFormCaption("操作成功");
                        SplashScreenManager.Default.SetWaitFormDescription("");
                        Thread.Sleep(800);
                        SplashScreenManager.CloseDefaultWaitForm();
                        DialogResult = DialogResult.OK;
                        this.Close();
                    }
                    else
                    {
                        throw new Exception(apiResponseData.Message);
                    }
                }
            }
            catch (Exception ex)
            {
                HasErrorAndExitAction(ex.Message);
                logs.AppendLine(ex.Message);
                XtraMessageBox.Show(ex.Message, "错误");
            }
        }

        /// <summary>
        /// 模板下载
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lb_DownLoadTemplate_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dlg = new FolderBrowserDialog();
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    OutExcel(dlg.SelectedPath.ToString());
                    XtraMessageBox.Show("导出成功！", "信息");
                }
                catch (Exception ex)
                {
                    XtraMessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }

        }

        #endregion


        #region 拖动窗口

        #region WinAPI

        private const int WM_SysCommand = 0x0112;
        private const int OneMsgNum = 0xf017;

        [DllImport("user32")]
        private static extern bool ReleaseCapture();

        [DllImport("user32")]
        private static extern bool PostMessage(int hWnd, int Mwg, int wParam, int lParam);

        #endregion

        #endregion 拖动窗口

        #region 方法

        /// <summary>
        /// 设置等待窗口文字
        /// </summary>
        /// <param name="caption"></param>
        /// <param name="content"></param>
        void SetWaitFormDescription(string caption, string content)
        {
            Invoke(new Action(() =>
            {
                if (!string.IsNullOrWhiteSpace(caption))
                    SplashScreenManager.Default.SetWaitFormCaption(caption);
                if (!string.IsNullOrWhiteSpace(content))
                    SplashScreenManager.Default.SetWaitFormDescription(content);
            }));
        }

        void HasErrorAndExitAction(string Content)
        {
            SplashScreenManager.Default.SetWaitFormCaption("导入出错:");
            SplashScreenManager.Default.SetWaitFormDescription(Content);
            Thread.Sleep(800);
            // 关闭等待窗口
            SplashScreenManager.CloseDefaultWaitForm();
            lb_logs.Visible = true;
        }

        /// <summary>
        /// 反射model类键值对
        /// </summary>
        void KeyValuePairsBind()
        {
            if (keyValuePairs == null || keyValuePairs.Count == 0)
            {
                if (keyValuePairs == null)
                    keyValuePairs = new Dictionary<string, string>();

                PropertyInfo[] properties = typeof(DriveMaintenancePlanExcelModel).GetProperties();
                foreach (PropertyInfo item in properties)
                {
                    DisplayNameAttribute[] attrs =
                        (DisplayNameAttribute[])item.GetCustomAttributes(typeof(DisplayNameAttribute), true);
                    keyValuePairs.Add(item.Name, attrs[0].DisplayName);
                }
            }
        }

        /// <summary>
        /// 导出模板
        /// </summary>
        /// <param name="savePath"></param>
        void OutExcel(string savePath)
        {
            // 创建Excel工作簿和工作表
            IWorkbook workbook = new XSSFWorkbook();
            ISheet sheet = workbook.CreateSheet($"OEM设备PM计划");
            ISheet sheet2 = workbook.CreateSheet($"选项列表");

            //读取Model属性生成键值对
            KeyValuePairsBind();

            // 写入表头
            IRow headerRow = sheet.CreateRow(0);
            int index = 0;

            // 创建一个下拉框选项列表
            string[] options = new string[] { "", "Monthly", "Annual", "Quarterly", "Semi-an" };
            // 设置下拉框选项为字符串类型
            IRow row = sheet2.CreateRow(0);
            for (int i = 0; i < options.Length; i++)
            {
                ICell cell = row.CreateCell(i);
                cell.SetCellValue(options[i]);
            }

            // 创建下拉框选项列表
            var validationHelper = sheet.GetDataValidationHelper();
            IDataValidationConstraint constraint = validationHelper.CreateExplicitListConstraint(options);

            int StartCellIndex = 0, EndCellIndex = 0;
            foreach (KeyValuePair<string, string> item in keyValuePairs)
            {
                if (item.Key == "Jan")
                    StartCellIndex = index;
                else if (item.Key == "Dec")
                    EndCellIndex = index;

                headerRow.CreateCell(index).SetCellValue(item.Value);
                index++;
            }

            CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(1, 1048575, StartCellIndex, EndCellIndex); // 从第二行开始到最后一行，第一列
            IDataValidation dataValidation = validationHelper.CreateValidation(constraint, cellRangeAddressList);
            dataValidation.ShowErrorBox = true;
            // 将下拉框数据验证对象应用到整列的每个单元格
            sheet.AddValidationData(dataValidation);

            // 删除选项sheet
            workbook.RemoveSheetAt(workbook.GetSheetIndex(sheet2));

            // 保存Excel文件
            using (FileStream fs =
                   new FileStream(Path.Combine(savePath, $"保养计划模板-{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.xlsx"),
                       FileMode.Create, FileAccess.Write))
            {
                workbook.Write(fs);
            }
        }

        #endregion
    }
}