using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Windows.Forms.DataVisualization.Charting;
using System.Net;

using System.Threading;
using System.IO;

using FLY.Thick.Base.IService;
using FLY.Thick.Base.Client;
using FObjBase;
using Unity;
using CommunityToolkit.Mvvm.Input;
using LiveCharts;
using Misc;
using LiveCharts.Configurations;
using OfficeOpenXml;
using Microsoft.Win32;
using System.Threading.Tasks;
using System.Data;
using OfficeOpenXml.Table;

namespace FLY.Thick.Base.UI
{
    /// <summary>
    /// Page_Reject.xaml 的交互逻辑
    /// </summary>
    public partial class PgReject : Page
    {
        IRejectService rejectService;
        IInitParamService initParamService;
        PgRejectVm viewModel;

        public PgReject()
        {
            InitializeComponent();
        }


        [InjectionMethod]
        public void Init(
            IUnityContainer container,
            IRejectService rejectService, 
            IInitParamService initParamService)
        {
            container.BuildUp(mircoGage);
            viewModel = new PgRejectVm();
            viewModel.Init(rejectService, initParamService);
            this.DataContext = this.viewModel;
        }
    }

    public class PgRejectVm : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;


        #region 曲线
        public Func<double, string> YFormatter { get; private set; }

        [PropertyChanged.DependsOn(nameof(PosOfGrid), nameof(Mmpp))]
        public Func<double, string> XFormatter { get; private set; }

        public CartesianMapper<XY> Mapper { get; set; }

        /// <summary>
        /// X轴最小范围
        /// </summary>
        public double XMin => 0;
        /// <summary>
        /// X轴最大范围
        /// </summary>
        public double XMax => PosLength / PosOfGrid;

        public ChartValues<XY> FilterDatas { get; } = new ChartValues<XY>();
        public ChartValues<XY> RejectDatas { get; } = new ChartValues<XY>();
        #endregion

        #region 状态
        public double Threshold { get; set; } = double.NaN;
        public double UpperLimit { get; set; } = double.NaN;
        public double LowerLimit { get; set; } = double.NaN;

        #endregion


        /// <summary>
        /// 使能
        /// </summary>
        public bool Enable { get; set; }
        /// <summary>
        /// 剔除阈值，低于 ThresholdRatio*Target 都要被删除
        /// </summary>
        public double ThresholdRatio { get; set; }

        /// <summary>
        ///  规格范围，Math.Abs(value-Target) > UpperLimitRatio*Target 都要被删除
        /// </summary>
        public double LimitRangeRatio { get; set; }

        /// <summary>
        /// 滤波范围，单位脉冲
        /// </summary>
        public int SmoothRange { get; set; }
        /// <summary>
        /// 当前数据需要剔除，那么它的前后Range2个脉冲的数据都是删除，单位脉冲
        /// </summary>
        public int RejectRange { get; set; }

        /// <summary>
        /// 机架总长，脉冲
        /// </summary>
        public int PosLength { get; set; } = 8000;

        /// <summary>
        /// 1个grid = N个pos
        /// </summary>
        public int PosOfGrid { get; set; } = 10;

        /// <summary>
        /// 比例
        /// </summary>
        public double Mmpp { get; set; } = 0.1;


        public DateTime DebugUpdateTime { get; set; }
        public RelayCommand ApplyCmd { get; }

        public RelayCommand SaveCmd { get; }

        IRejectService rejectService;
        public IInitParamService InitParamService { get; private set; }
        Page page;
        public PgRejectVm() 
        {
            Mapper = Mappers.Xy<XY>()
                .X((value, index) => value.X)
                .Y(value => value.Y);


            XFormatter = (x) =>
            {
                //x 是 grid
                int pos = (int)(x * PosOfGrid);
                int mm = (int)(pos * Mmpp);
                return $"{pos}\n{mm}mm";
            };
            YFormatter = (y) =>
            {
                return $"{ y:F1}";
            };

            ApplyCmd = new RelayCommand(Apply);
            SaveCmd = new RelayCommand(SaveXlsx);
        }
        public void Init(
            IRejectService rejectService,
            IInitParamService initParamService)
        {
            this.rejectService = rejectService;
            this.InitParamService = initParamService;

            Misc.BindingOperations.SetBinding(rejectService, nameof(rejectService.Enable), this, nameof(Enable));
            Misc.BindingOperations.SetBinding(rejectService, nameof(rejectService.ThresholdRatio), this, nameof(ThresholdRatio));
            Misc.BindingOperations.SetBinding(rejectService, nameof(rejectService.LimitRangeRatio), this, nameof(LimitRangeRatio));
            
            Misc.BindingOperations.SetBinding(rejectService, nameof(rejectService.LimitRangeRatio), this, nameof(LimitRangeRatio));
            Misc.BindingOperations.SetBinding(rejectService, nameof(rejectService.SmoothRange), this, nameof(SmoothRange));
            Misc.BindingOperations.SetBinding(rejectService, nameof(rejectService.RejectRange), this, nameof(RejectRange));

            Misc.BindingOperations.SetBinding(rejectService, nameof(rejectService.DebugUpdateTime), this, nameof(DebugUpdateTime));

            Misc.BindingOperations.SetBinding(initParamService, nameof(initParamService.Encoder1_mmpp), this, nameof(Mmpp));
            Misc.BindingOperations.SetBinding(initParamService, nameof(initParamService.PosLength), this, nameof(PosLength));
            Misc.BindingOperations.SetBinding(initParamService, nameof(initParamService.PosOfGrid), this, nameof(PosOfGrid));

            this.rejectService.PropertyChanged += new PropertyChangedEventHandler(mRejectService_PropertyChanged);
            Download();
        }


        private async void SaveXlsx()
        {
            //下载数据
            string strDesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);

            string filename = $"剔除_{DateTime.Now:yyyyMMddHHmmss}.xlsx";
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = "xlsx files (*.xlsx)|*.xlsx";
            sfd.InitialDirectory = strDesktopPath;
            sfd.FileName = filename;
            if (sfd.ShowDialog() == true)
            {
                filename = sfd.FileName;

                await Task.Factory.StartNew(() =>
                {
                    SaveToXlsx(filename);
                });

                FLY.ControlLibrary.Window_Tip.Show("成功", $"导出到{filename}", TimeSpan.FromSeconds(2));
            }
        }

        private void SaveToXlsx(string filepath)
        {
            if (FilterDatas.Count() == 0)
            {
                return;
            }

            if (File.Exists(filepath))
            {
                File.Delete(filepath);
            }
            using (ExcelPackage p = new ExcelPackage(new FileInfo(filepath)))
            {
                ExcelWorksheet sheet = p.Workbook.Worksheets.Add("剔除");
                DataTable dataTable = new DataTable("table_reject");
                dataTable.Columns.Add(new DataColumn() { ColumnName = "序号", DataType = typeof(double), Caption = "0" });
                dataTable.Columns.Add(new DataColumn() { ColumnName = "脉冲", DataType = typeof(double), Caption = "0" });
                dataTable.Columns.Add(new DataColumn() { ColumnName = "mm", DataType = typeof(double), Caption = "0.0" });
                dataTable.Columns.Add(new DataColumn() { ColumnName = "滤波", DataType = typeof(double), Caption = "0.00" });
                dataTable.Columns.Add(new DataColumn() { ColumnName = "剔除后", DataType = typeof(double), Caption = "0.00" });
                
                    XY data = FilterDatas.First();
                    int start_grid = (int)data.X;
                    for (int i = 0; i < start_grid; i++)
                    {
                        try
                        {
                            var dataRow = dataTable.NewRow();
                            dataRow["序号"] = i;
                            dataRow["脉冲"] = i * PosOfGrid;
                            dataRow["mm"] = i * PosOfGrid * Mmpp;
                            dataTable.Rows.Add(dataRow);
                        }
                        catch
                        {
                            break;
                        }
                    }
                
                for (int i = 0; i < FilterDatas.Count() && i< RejectDatas.Count(); i++)
                {
                    try
                    {
                        var dataRow = dataTable.NewRow();
                        int index = start_grid + i;
                        dataRow["序号"] = index;
                        dataRow["脉冲"] = index * PosOfGrid;
                        dataRow["mm"] = index * PosOfGrid * Mmpp;
                        dataRow["滤波"] = FilterDatas[i].Y;
                        dataRow["剔除后"] = RejectDatas[i].Y;
                        dataTable.Rows.Add(dataRow);
                    }
                    catch
                    {
                        break;
                    }
                }

                ToSheet(sheet, dataTable);

                p.Save();

            }

        }
        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();
        }

        private void Apply()
        {
            if (!WdPassword.Authorize("Reject"))
                return;

            rejectService.Enable = this.Enable;
            rejectService.ThresholdRatio = this.ThresholdRatio;
            rejectService.LimitRangeRatio = this.LimitRangeRatio;
            rejectService.SmoothRange = this.SmoothRange;
            rejectService.RejectRange = this.RejectRange;

            rejectService.Apply();
            FLY.ControlLibrary.Window_Tip.Show("应用成功",
                null,
                TimeSpan.FromSeconds(2));
            
        }


        void mRejectService_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {

            if (e.PropertyName == nameof(rejectService.DebugUpdateTime))
            {
                //下载
                Download();
            }
            else if (e.PropertyName == nameof(FObjBase.FObjServiceClient.IsConnected)) {
                var client = rejectService as FObjBase.FObjServiceClient;
                if (client.IsConnected) {
                    Download();
                }
            }
        }

        void Download() 
        {
            rejectService.GetDebugData((asyncContext, retData) =>
            {
                var reponse = retData as RejectDebugData;

                FilterDatas.Clear();
                RejectDatas.Clear();
                if (reponse == null) {
                    //无数据
                    Threshold = double.NaN;
                    UpperLimit = double.NaN;
                    LowerLimit = double.NaN;
                    return;
                }

                if (reponse.filterDatas != null && reponse.filterDatas.Count() > 0) {
                    
                    FilterDatas.AddRange(reponse.filterDatas.Select((d,i) => new XY() {
                        X = reponse.start_grid+i,
                        Y = d
                    }));
                }
                if (reponse.rejectDatas != null && reponse.rejectDatas.Count() > 0)
                {
                    RejectDatas.AddRange(reponse.rejectDatas.Select((d, i) => new XY()
                    {
                        X = reponse.start_grid+i,
                        Y = d
                    }));
                }

                Threshold = reponse.target * rejectService.ThresholdRatio;
                UpperLimit = reponse.target * (1+rejectService.LimitRangeRatio);
                LowerLimit = reponse.target * (1-rejectService.LimitRangeRatio);

            }, this);
        }

    }
}
