using FLY.Thick.FilmCasting.Server.Model;
using FLY.Thick.FilmCasting.UI.DbViewer.Db;
using MahApps.Metro.Controls;
using MahApps.Metro.Controls.Dialogs;
using Misc;
using OfficeOpenXml;
using OfficeOpenXml.Drawing;
using OfficeOpenXml.Drawing.Chart;
using OfficeOpenXml.Table;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace FLY.Thick.FilmCasting.UI.DbViewer.Core
{
    public class ExcelOuput : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public double Progress {
            get {
                if (TotalRow > 0)
                {
                    if (CurrRow < TotalRow)
                    {
                        return 1.0 * CurrRow / TotalRow;
                    }
                    else
                    {
                        return 1;
                    }
                }
                else {
                    return 1;
                }
            }
        }
        public string Msg { get; private set; }

        protected int TotalRow { get; private set; } = 1;
        protected int CurrRow { get; private set; }
        const int CurrRowGrowUpStep = 500;
        public async Task SaveToXlsx(string filepath, DbProfilePack profilePack)
        {
            await SaveToXlsxNoTemplate(filepath, profilePack);
        }

        /// <summary>
        /// 没有模板导出数据
        /// </summary>
        /// <param name="filepath"></param>
        async Task SaveToXlsxNoTemplate(string filepath, DbProfilePack profilePack)
        {
            await Task.Run(() =>
            {

                using (ExcelPackage p = new ExcelPackage(new FileInfo(filepath)))
                {
                    CurrRowInit(profilePack.ScanDatas.Count());
                    
                    SaveToXlsxThk(p, profilePack);

                    Msg = "写入文件";
                    p.Save();

                }
            });
        }


        ExcelWorksheet GetSheet(ExcelPackage p, string sheet_name)
        {

            ExcelWorksheet sheet = p.Workbook.Worksheets[sheet_name];
            if (sheet == null)
            {
                sheet = p.Workbook.Worksheets.Add(sheet_name);
            }
            return sheet;
        }


        void SaveToXlsxThk(ExcelPackage p, DbProfilePack profilePack)
        {
            if (profilePack.ScanDatas == null || profilePack.ScanDatas.Count() == 0)
                return;//没有数据

            Msg = "导出扫描数据记录";
            int boltCnt = 0;
            int sampleCnt = 0;
            {
                var scanData = profilePack.ScanDatas.Last();
                boltCnt = scanData.Thicks.Count();
                if (scanData.SampleADs != null && scanData.SampleADs.Count() > 0)
                    sampleCnt = scanData.SampleADs.Count();
            }

            ExcelWorksheet sheet = GetSheet(p, "扫描数据");


            var columnInfos = new List<ColumnInfo<Lc_ScanData>>
            {
                new ColumnInfo<Lc_ScanData>("开始时间", typeof(double), "yyyy-MM-dd HH:mm:ss", (sender)=>sender.Time.ToOADate()),
                new ColumnInfo<Lc_ScanData>("结束时间", typeof(double), "yyyy-MM-dd HH:mm:ss", (sender)=>sender.EndTime.ToOADate()),
                new ColumnInfo<Lc_ScanData>("目标值", typeof(double), "0.00", (sender)=>sender.Target),
                new ColumnInfo<Lc_ScanData>("规格线%", typeof(double), "0.0", (sender)=>sender.TolerancePercent),
                new ColumnInfo<Lc_ScanData>("斜率补偿", typeof(double), "0.000", (sender)=>sender.K),
                new ColumnInfo<Lc_ScanData>("平移补偿", typeof(double), "0.00", (sender)=>sender.B),

                new ColumnInfo<Lc_ScanData>("纵向位置(m)", typeof(double), "0.000", (sender)=>sender.FilmPosition),
                new ColumnInfo<Lc_ScanData>("线速度(m/min)", typeof(double), "0.0" , (sender)=>sender.FilmVelocity),
                new ColumnInfo<Lc_ScanData>("膜宽度(mm)", typeof(double), "0" , (sender)=>sender.FilmWidth),

                new ColumnInfo<Lc_ScanData>("平均值(um)", typeof(double), "0.00" , (sender)=>sender.Avg),
                new ColumnInfo<Lc_ScanData>("2σ(%)", typeof(double), "0.0", (sender)=>{

                    double avg = sender.Avg;
                    double sigma = sender.Thicks.Sigma();
                    if (avg > 0)
                    {
                        double sigma2p = sigma / avg * 2 * 100;
                        return sigma2p;
                    }
                    else{
                        return double.NaN;
                    }
                }),
                new ColumnInfo<Lc_ScanData>((i)=>$"分区{i + 1}(um)", typeof(double), "0.00" ,boltCnt,(sender,i)=>{
                    if(i<sender.Thicks.Count())
                        return sender.Thicks[i];
                    else
                        return null;
                }),
                new ColumnInfo<Lc_ScanData>((i)=>$"样品{i}AD", typeof(double), "0" ,sampleCnt,(sender,i)=>{
                    if(i<sender.SampleADs.Count())
                        return sender.SampleADs[i];
                    else
                        return null;
                }),
            };


            CurrRowGrowUpReady();

            DataTable dataTable = CreateDataTable(columnInfos, "table_thk", profilePack.ScanDatas, CurrRowGrowUping);
            CurrRowGrowUpFinish(profilePack.ScanDatas.Count());

            ToSheet(sheet, dataTable);
        }

        void CurrRowInit(int totalRow)
        {
            TotalRow = totalRow;
            CurrRow = 0;
        }
        int _currRow = 0;
        void CurrRowGrowUpReady()
        {
            _currRow = CurrRow;
        }
        void CurrRowGrowUping(int i)
        {
            if (i % CurrRowGrowUpStep == 0)
                CurrRow = _currRow + i;
        }
        void CurrRowGrowUpFinish(int cnt)
        {
            CurrRow = _currRow + cnt;
        }


        #region 填表格辅助工具
        class ColumnInfo<T>
        {
            public string ColumnName;
            public Type DataType;
            public string Format;
            public delegate object GetValueHanlder(T sender, int itemIdx);
            GetValueHanlder getValue;
            public bool IsArray;
            public int ItemCount;
            public delegate string GetColumnNameHanlder(int itemIdx);
            GetColumnNameHanlder getColumnName;

            public ColumnInfo(string columnName, Type dataType, string format, Func<T, object> getValue)
            {
                ColumnName = columnName;
                DataType = dataType;
                Format = format;
                this.getValue = (s, i) => getValue(s);
            }
            public ColumnInfo(string columnName, Type dataType, string format, GetValueHanlder getValue)
            {
                ColumnName = columnName;
                DataType = dataType;
                Format = format;
                this.getValue = getValue;
            }
            public ColumnInfo(GetColumnNameHanlder getColumnName, Type dataType, string format, int itemCount, GetValueHanlder getValue)
            {
                IsArray = true;
                ItemCount = itemCount;
                this.getColumnName = getColumnName;
                DataType = dataType;
                Format = format;
                this.getValue = getValue;
            }
            public DataColumn CreateDataColumn()
            {
                return new DataColumn() { ColumnName = ColumnName, DataType = DataType, Caption = Format };
            }
            public DataColumn CreateDataColumn(int itemIdx)
            {
                return new DataColumn() { ColumnName = getColumnName(itemIdx), DataType = DataType, Caption = Format };
            }
            public object GetValue(T sender)
            {
                return getValue(sender, 0);
            }
            public object GetValue(T sender, int index)
            {
                return getValue(sender, index);
            }
            public string GetColumnName(int index)
            {
                return getColumnName(index);
            }
            public string GetColumnName()
            {
                return ColumnName;
            }


        }
        DataTable CreateDataTable<T>(List<ColumnInfo<T>> columnInfos, string tableName, IEnumerable<T> senders, Action<int> progressEvent = null)
        {
            DataTable dataTable = new DataTable(tableName);
            for (int i = 0; i < columnInfos.Count(); i++)
            {
                var columnInfo = columnInfos[i];
                if (!columnInfo.IsArray)
                {
                    dataTable.Columns.Add(columnInfo.CreateDataColumn());
                }
                else
                {
                    for (int k = 0; k < columnInfo.ItemCount; k++)
                    {
                        dataTable.Columns.Add(columnInfo.CreateDataColumn(k));
                    }
                }
            }

            int j = 0;
            foreach (var sender in senders)
            {
                var dataRow = dataTable.NewRow();

                for (int i = 0; i < columnInfos.Count(); i++)
                {
                    var columnInfo = columnInfos[i];
                    if (!columnInfo.IsArray)
                    {
                        string columnName = columnInfo.GetColumnName();
                        var value = columnInfo.GetValue(sender);
                        if (value != null)
                            dataRow[columnName] = value;
                    }
                    else
                    {
                        for (int k = 0; k < columnInfo.ItemCount; k++)
                        {
                            string columnName = columnInfo.GetColumnName(k);
                            var value = columnInfo.GetValue(sender, k);
                            if (value != null)
                                dataRow[columnName] = value;
                        }
                    }
                }

                dataTable.Rows.Add(dataRow);
                progressEvent?.Invoke(j);
                j++;
            }
            return dataTable;
        }
        void ToSheet(ExcelWorksheet sheet, DataTable dataTable)
        {
            int from_row = 1;
            int row = from_row;
            //添加标题
            for (int i = 0; i < dataTable.Columns.Count; i++)
            {
                int col = i + 1;
                sheet.Cells[row, col].Value = dataTable.Columns[i].ColumnName;
                //格式
                sheet.Column(col).Style.Numberformat.Format = dataTable.Columns[i].Caption;
            }

            row++;
            for (int i = 0; i < dataTable.Rows.Count; i++)
            {
                for (int j = 0; j < dataTable.Columns.Count; j++)
                {
                    int col = j + 1;
                    sheet.Cells[row, col].Value = dataTable.Rows[i][j];
                }
                row++;
            }

            //int colcnt = dataTable.Columns.Count;
            //int rowcnt = dataTable.Rows.Count;
            //var range = sheet.Cells[from_row, 1, from_row + rowcnt, colcnt];

            //var tbl = sheet.Tables.Add(range, dataTable.TableName);
            //tbl.TableStyle = TableStyles.Medium9;
            //sheet.Cells[sheet.Dimension.Address].AutoFitColumns();
        }
        #endregion
    }
}
