using FLY.Thick.FilmCasting.IService;
using FObjBase;
using FObjBase.Reflect;
using Misc;
using SQLite;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FLY.Thick.FilmCasting.Server.Model
{
    /// <summary>
    /// 提供接口，让别人获取 整理好的 当前生产，或之前生产的数据。
    /// 从LocalDb 获取数据， 或从 直接从数据获取数据
    /// 
    /// 与HistoryDb，成对。 
    /// HistoryDb 是写
    /// BulkDb 是读
    /// </summary>
    public class BulkDb : IBulkDbService
    {
        /// <summary>
        /// 本地数据库
        /// </summary>
        LocalDb localDb;
        DbModel dbModel;
        IShareDbService shareDb;

        /// <summary>
        /// 最后一条扫描数据Id
        /// </summary>
        public long LastScanDataId { get; private set; } = -1;
        /// <summary>
        /// 最后一条产品Id
        /// </summary>
        public long LastProfileId { get; private set; } = -1;
        /// <summary>
        /// 数据库最后一次被修改时间
        /// </summary>
        public DateTime LastTimestamp { get; private set; }


        /// <summary>
        /// 开始产生数据时间
        /// </summary>
        public DateTime StartTime { get; private set; }

        /// <summary>
        /// 最后产生数据时间
        /// </summary>
        public DateTime EndTime { get; private set; }

        /// <summary>
        /// 当前生产，已经结束，已经下辊了
        /// </summary>
        public bool IsFinished { get; private set; }

        /// <summary>
        /// 
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// 临时数据改变
        /// </summary>
        [Push(typeof(BulkDbTempFrameChangedEventArgs))]
        public event EventHandler TempFrameChanged;

        public Func<BulkDbTempFrameChangedEventArgs> GetTempFrameAction;

        /// <summary>
        /// 
        /// </summary>
        public BulkDb()
        {

        }

        /// <summary>
        /// 写入动态数据
        /// </summary>
        /// <param name="startIndex"></param>
        /// <param name="D"></param>
        public void SetTempFrame(DateTime time, DateTime endTime, int startIndex, double[] D)
        {
            TempFrameChanged?.Invoke(this, new BulkDbTempFrameChangedEventArgs() { Time = time, EndTime = endTime, StartIndex = startIndex, D = D });
        }

        /// <summary>
        /// 获取临时数据
        /// </summary>
        /// <param name="request"></param>
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        [Call(typeof(BulkDbTempFrameChangedEventArgs))]
        public void GetTempFrame(
            AsyncCBHandler asyncDelegate, object asyncContext)
        {
            BulkDbTempFrameChangedEventArgs e;
            if (GetTempFrameAction != null)
                e = GetTempFrameAction();
            else
                e = new BulkDbTempFrameChangedEventArgs();
            asyncDelegate?.Invoke(asyncContext, e);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="shareDb"></param>
        /// <param name="localDb"></param>
        /// <param name="dbModel"></param>
        public void Init(IShareDbService shareDb,
             LocalDb localDb, DbModel dbModel)
        {
            this.localDb = localDb;

            this.dbModel = dbModel;
            this.shareDb = shareDb;

            LocalDBLoad();


            Misc.BindingOperations.SetBinding(localDb, nameof(localDb.ProfileStartTime), this, nameof(StartTime));
            Misc.BindingOperations.SetBinding(localDb, nameof(localDb.ProfileEndTime), this, nameof(EndTime));
            Misc.BindingOperations.SetBinding(localDb, nameof(localDb.IsProfileFinished), this, nameof(IsFinished));

            this.shareDb.ProfileChanged += ShareDB_ProfileChanged;
            this.shareDb.ScanDataAdded += ShareDB_ScanDataAdded;

        }

        private void ShareDB_ProfileChanged(object sender, EventArgs _e)
        {
            ProfileChangedEventArgs e = (ProfileChangedEventArgs)_e;

            var profile = e.profile;

            LastProfileId = profile.ID;
            LastTimestamp = DateTime.Now;
        }

        private void ShareDB_ScanDataAdded(object sender, EventArgs _e)
        {
            ScanDataAddedEventArgs e = (ScanDataAddedEventArgs)_e;

            LastScanDataId = e.scandata.ID;
            LastTimestamp = DateTime.Now;
        }

        /// <summary>
        /// 加载数据库中最后1次订单数据到 本地
        /// </summary>
        void LocalDBLoad()
        {
            var reponse = dbModel.sqliteHelper.ExecuteScalar($"SELECT MAX(ID) FROM {dbModel.TbProfile.TableName}");
            if (reponse is DBNull)
                return;

            long maxid = System.Convert.ToInt64(reponse);
            var profile = dbModel.TbProfile.Find($"WHERE ID = {maxid}").First();


            reponse = dbModel.sqliteHelper.ExecuteScalar($"SELECT MAX(ID) FROM {dbModel.TbScanData.TableName}");
            if (!(reponse is DBNull))
            {
                maxid = System.Convert.ToInt64(reponse);
                LastScanDataId = maxid;
            }

            LastProfileId = profile.ID;
        }

        /// <summary>
        /// 获取profile
        /// </summary>
        /// <param name="request"></param>
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        [Call(typeof(Pack_GetProfileReponse))]
        public async void GetProfile(
            Pack_GetProfileRequest request,
            AsyncCBHandler asyncDelegate, object asyncContext)
        {
            Pack_GetProfileReponse reponse = new Pack_GetProfileReponse();
            reponse.Request = request;

            await Task.Factory.StartNew(() =>
            {
                List<Db_Profile> db_profiles = dbModel.TbProfile.Find($"WHERE ID = {request.Id}");

                if (db_profiles.Count() == 0)
                    return;

                reponse.profile = db_profiles.First();
            });

            asyncDelegate(asyncContext, reponse);
        }


        /// <summary>
        /// 获取N幅数据,需要异步
        /// </summary>
        /// <param name="request"></param>
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        public async void GetFrame(Pack_GetFrameRequest request, AsyncCBHandler asyncDelegate, object asyncContext)
        {
            var reponse = new Pack_GetFrameReponse();
            reponse.Request = request;
            if (request.Mix > 100)//数量限制，避免死机
                request.Mix = 100;
            else if (request.Mix < 1)
                request.Mix = 1;

            await Task.Factory.StartNew(() =>
            {
                List<Db_ScanData> db_scandatas;
                if (request.Id <= 0)
                {
                    db_scandatas = dbModel.TbScanData.Find(
                        $"ORDER BY ID DESC" +
                        $" LIMIT {request.Mix} OFFSET {-request.Id}");
                }
                else
                    db_scandatas = dbModel.TbScanData.Find(
                        $"WHERE ID <= {request.Id}" +
                        $" ORDER BY ID DESC" +
                        $" LIMIT {request.Mix}");

                //数据是 从 后 到 前 排列的
                if (db_scandatas.Count() == 0)
                    return;
                

                var lc_scanDatas = Lc_AutoMapperProfile.Mapper.Map<List<Db_ScanData>, List<Lc_ScanData>>(db_scandatas);
                var newest_scanData = lc_scanDatas.First();//这个是最新的一幅图
                

                if (lc_scanDatas.Count() > 1)
                {
                    //把时间 与 最新的一幅图 的时间 偏差 大于 request.TimeRange 删除
                    if (request.TimeRange > TimeSpan.Zero) {
                        List<Lc_ScanData> lc_scanDatas2 = new List<Lc_ScanData>();
                        lc_scanDatas2.Add(newest_scanData);

                        for (int i = 1; i < lc_scanDatas.Count(); i++) {
                            var scanData = lc_scanDatas[i];
                            if (newest_scanData.Time - scanData.Time > request.TimeRange) {
                                break;
                            }
                            lc_scanDatas2.Add(scanData);
                        }
                        lc_scanDatas = lc_scanDatas2;
                    }

                    //把 均值与 最新的一幅图 的均值 偏差 大于 request.AvgRange 删除
                    if (request.AvgRange > 0)
                    {
                        List<Lc_ScanData> lc_scanDatas2 = new List<Lc_ScanData>();
                        lc_scanDatas2.Add(newest_scanData);
                        var newest_avg = newest_scanData.Thicks.AverageNoNull();
                        if (!double.IsNaN(newest_avg))
                        {
                            for (int i = 1; i < lc_scanDatas.Count(); i++)
                            {
                                var scanData = lc_scanDatas[i];
                                var avg = scanData.Thicks.AverageNoNull();
                                if (double.IsNaN(avg))
                                    break;
                                
                                if (Math.Abs(newest_avg - avg) > request.AvgRange)
                                    break;
                                
                                lc_scanDatas2.Add(scanData);
                            }
                        }

                        lc_scanDatas = lc_scanDatas2;
                    }

                    if (lc_scanDatas.Count() > 1)
                    {
                        //求均值
                        newest_scanData.Thicks = GetMixScanData(lc_scanDatas, 0, lc_scanDatas.Count());
                        request.Mix = lc_scanDatas.Count();
                    }
                }

                reponse.scanData = newest_scanData;
                // Last() 就是最早的数据
                reponse.scanData.Time = lc_scanDatas.Last().Time;
                request.Mix = lc_scanDatas.Count();
            });

            asyncDelegate(asyncContext, reponse);
        }


        /// <summary>
        /// 获取N幅数据 与 profile,需要异步 
        /// </summary>
        /// <param name="request"></param>
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        public async void GetFrame2(Pack_GetFrameRequest request, AsyncCBHandler asyncDelegate, object asyncContext)
        {
            var reponse = new Pack_GetFrame2Reponse();
            reponse.Request = request;
            if (request.Mix > 100)//数量限制，避免死机
                request.Mix = 100;
            else if (request.Mix < 1)
                request.Mix = 1;

            await Task.Factory.StartNew(() =>
            {
                List<Db_ScanData> db_scandatas;
                if (request.Id <= 0)
                {
                    db_scandatas = dbModel.TbScanData.Find(
                        $"ORDER BY ID DESC" +
                        $" LIMIT {request.Mix} OFFSET {-request.Id}");
                }
                else
                    db_scandatas = dbModel.TbScanData.Find(
                        $"WHERE ID <= {request.Id}" +
                        $" ORDER BY ID DESC" +
                        $" LIMIT {request.Mix}");

                //数据是 从 后 到 前 排列的
                if (db_scandatas.Count() == 0)
                    return;


                var lc_scanDatas = Lc_AutoMapperProfile.Mapper.Map<List<Db_ScanData>, List<Lc_ScanData>>(db_scandatas);
                var newest_scanData = lc_scanDatas.First();//这个是最新的一幅图


                if (lc_scanDatas.Count() > 1)
                {
                    //把时间 与 最新的一幅图 的时间 偏差 大于 request.TimeRange 删除
                    if (request.TimeRange > TimeSpan.Zero)
                    {
                        List<Lc_ScanData> lc_scanDatas2 = new List<Lc_ScanData>();
                        lc_scanDatas2.Add(newest_scanData);

                        for (int i = 1; i < lc_scanDatas.Count(); i++)
                        {
                            var scanData = lc_scanDatas[i];
                            if (newest_scanData.Time - scanData.Time > request.TimeRange)
                            {
                                break;
                            }
                            lc_scanDatas2.Add(scanData);
                        }
                        lc_scanDatas = lc_scanDatas2;
                    }

                    //把 均值与 最新的一幅图 的均值 偏差 大于 request.AvgRange 删除
                    if (request.AvgRange > 0)
                    {
                        List<Lc_ScanData> lc_scanDatas2 = new List<Lc_ScanData>();
                        lc_scanDatas2.Add(newest_scanData);
                        var newest_avg = newest_scanData.Thicks.AverageNoNull();
                        if (!double.IsNaN(newest_avg))
                        {
                            for (int i = 1; i < lc_scanDatas.Count(); i++)
                            {
                                var scanData = lc_scanDatas[i];
                                var avg = scanData.Thicks.AverageNoNull();
                                if (double.IsNaN(avg))
                                    break;

                                if (Math.Abs(newest_avg - avg) > request.AvgRange)
                                    break;

                                lc_scanDatas2.Add(scanData);
                            }
                        }

                        lc_scanDatas = lc_scanDatas2;
                    }

                    if (lc_scanDatas.Count() > 1)
                    {
                        //求均值
                        newest_scanData.Thicks = GetMixScanData(lc_scanDatas, 0, lc_scanDatas.Count());
                        request.Mix = lc_scanDatas.Count();
                    }
                }

                reponse.scanData = newest_scanData;
                // Last() 就是最早的数据
                reponse.scanData.Time = lc_scanDatas.Last().Time;
                request.Mix = lc_scanDatas.Count();

                //查找 profile
                var db_profiles = dbModel.TbProfile.Find($"WHERE ID = {newest_scanData.ProfileID}");
                if (db_profiles.Count() == 0)
                    return;//没有数据
                reponse.profile = db_profiles.First();
            });

            asyncDelegate(asyncContext, reponse);
        }


        /// <summary>
        /// 获取近期的大量数据
        /// </summary>
        /// <param name="request"></param>
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        [Call(typeof(Pack_GetRecentFramesReponse))]
        public async void GetRecentFrames(
            Pack_GetRecentFramesRequest request,
            AsyncCBHandler asyncDelegate, object asyncContext)
        {
            var reponse = new Pack_GetRecentFramesReponse();
            reponse.Request = request;
            if (request.Count > 100)//数量限制，避免死机
                request.Count = 100;
            else if (request.Count < 1)
                request.Count = 1;

            await Task.Factory.StartNew(() =>
            {
                List<Db_ScanData> db_scandatas;

                if (request.Id <= 0)
                    db_scandatas = dbModel.TbScanData.Find(
                        $"ORDER BY ID DESC" +
                        $" LIMIT {request.Count} OFFSET {-request.Id}");
                
                else
                    db_scandatas = dbModel.TbScanData.Find(
                        $"WHERE ID <= {request.Id}" +
                        $" ORDER BY ID DESC" +
                        $" LIMIT {request.Count}");

                //数据是 从 后 到 前 排列的
                if (db_scandatas.Count() == 0)
                    return;

                //把时间不对的，删除
                if (request.FromTime > DateTime.MinValue) {
                    int index = db_scandatas.FindLastIndex(db_scandata => db_scandata.Time <= request.FromTime);
                    if (index >= 0) {//把它后面的全部删除
                        db_scandatas.RemoveRange(index, db_scandatas.Count() - index);
                    }
                }

                if (db_scandatas.Count() == 0)
                    return;

                //反向排序
                db_scandatas.Reverse();

                var lc_scanDatas = Lc_AutoMapperProfile.Mapper.Map<List<Db_ScanData>, List<Lc_ScanData>>(db_scandatas);

                //导出的数据， ID从小排到大
                reponse.scanDatas = lc_scanDatas;
            });

            asyncDelegate(asyncContext, reponse);
        }


        /// <summary>
        /// 获取纵向趋势图
        /// </summary>
        /// <param name="request"></param>
        /// <param name="AsyncDelegate"></param>
        /// <param name="AsyncContext"></param>
        public async void GetTrend(Pack_GetTrendRequest request, AsyncCBHandler asyncDelegate, object asyncContext)
        {
            //TODO 需要异步
            Pack_GetTrendReponse reponse = new Pack_GetTrendReponse();
            reponse.Request = request;

            if (request.Count > 400)//数量限制，避免死机
                request.Count = 400;
            else if (request.Count < 1)
                request.Count = 1;

            if (request.Mix > 10)//数量限制，避免死机
                request.Mix = 10;
            else if (request.Mix < 1)
                request.Mix = 1;

            if (request.Interval < 1)//避免 /0
                request.Interval = 1;


            await Task.Factory.StartNew(() =>
            {
                List<Db_ScanData> db_scandatas = null;
                if (!request.IsSearchByTime)
                {
                    if (request.Id <= 0)
                        db_scandatas = dbModel.TbScanData.Find(
                            $"WHERE ID % {request.Interval} = 0" +
                            $" ORDER BY ID DESC" +
                            $" LIMIT {request.Mix + request.Count - 1} OFFSET {-request.Id}");
                    else
                        db_scandatas = dbModel.TbScanData.Find(
                            $"WHERE (ID <= {request.Id})" +
                            $" AND ( ID % {request.Interval} = 0)" +
                            $" ORDER BY ID DESC" +
                            $" LIMIT {request.Mix + request.Count - 1}");
                }
                else
                {
                    db_scandatas = dbModel.TbScanData.Find(
                            $"WHERE ({nameof(Db_ScanData.Time)} <= {request.Time.ToStringOfSQLiteFieldType()})" +
                            $" AND ( ID % {request.Interval} = 0)" +
                            $" ORDER BY ID DESC" +
                            $" LIMIT {request.Mix + request.Count - 1}");
                }


                if (db_scandatas.Count() == 0)
                    return;

                //从尾向前排的！！！！
                var lc_scanDatas = Lc_AutoMapperProfile.Mapper.Map<List<Db_ScanData>, List<Lc_ScanData>>(db_scandatas);

                reponse.Values = ToTrend(lc_scanDatas, request.Count, request.Mix);

                var lc_scanData = lc_scanDatas.First();
                reponse.ScanDataId = lc_scanData.ID;


            });

            asyncDelegate(asyncContext, reponse);
        }

        double[] GetMixScanData(List<Lc_ScanData> lc_scanDatas, int offset, int mix)
        {

            var lc_scanData = lc_scanDatas[offset];
            //求均值
            double[] thks = new double[lc_scanData.Thicks.Count()];
            int[] cnt = new int[thks.Count()];
            for (int j = offset; j < offset + mix && j < lc_scanDatas.Count(); j++)
            {
                int index = j;
                if (lc_scanDatas[index].Thicks.Count() != thks.Count())
                {
                    //结束，异常
                    break;
                }

                for (int i = 0; i < thks.Count(); i++)
                {
                    var v = lc_scanDatas[index].Thicks[i];
                    if (!double.IsNaN(v))
                    {
                        thks[i] += v;
                        cnt[i]++;
                    }
                }
            }
            for (int i = 0; i < thks.Count(); i++)
            {
                if (cnt[i] > 0)
                    thks[i] /= cnt[i];
                else
                    thks[i] = double.NaN;
            }

            return thks;
        }
        List<TrendValue> ToTrend(List<Lc_ScanData> lc_scanDatas, int count, int mix)
        {

            if (mix == 1)
            {
                return lc_scanDatas.Select(sd =>
                {
                    double avg = sd.Thicks.AverageNoNull();
                    double sigma = sd.Thicks.Sigma();
                    return new TrendValue()
                    {
                        ScanDataID = sd.ID,
                        ProfileID = sd.ProfileID,
                        Sigma = sigma,
                        Value = avg,
                        Time = sd.Time
                    };
                }).ToList();
            }

            List<TrendValue> trendValues = new List<TrendValue>();

            for (int i = 0; i < lc_scanDatas.Count() && i < count; i++)
            {
                var sd = lc_scanDatas[i];
                //求均值
                double[] thks = GetMixScanData(lc_scanDatas, i, mix);
                double avg = thks.AverageNoNull();
                double sigma = thks.Sigma();

                trendValues.Add(new TrendValue()
                {
                    ScanDataID = sd.ID,
                    ProfileID = sd.ProfileID,
                    Sigma = sigma,
                    Value = avg,
                    Time = lc_scanDatas[i].Time
                });
            }
            return trendValues;
        }



        /// <summary>
        /// 完成
        /// </summary>
        public void Finish()
        {
            shareDb.FinishProfile();
        }

    }
}
