using FLY.FilmCasting.AutoDie.IService;
using FLY.OBJComponents.Server;
using FObjBase;
using SQLite;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;

namespace FLY.FilmCasting.AutoDie.Server.Model
{
    public class HistoryDb : IBulkDbService
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public long LastId { get; private set; }


        public BulkDbSQLite<Lc_ThickHeat, Db_ThickHeat> ThickHeatBuffer;
        public BufferError ErrorBuffer;

        DbModel dbModel;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dbModel"></param>
        public void Init(DbModel dbModel)
        {
            this.dbModel = dbModel;
            ThickHeatBuffer = new BulkDbSQLite<Lc_ThickHeat, Db_ThickHeat>();
            ThickHeatBuffer.Init(dbModel.TbThickHeat,
                (lc) => Lc_AutoMapperProfile.Mapper.Map<Db_ThickHeat>(lc),
                (db) => Lc_AutoMapperProfile.Mapper.Map<Lc_ThickHeat>(db)
                );
            ErrorBuffer = new OBJComponents.Server.BufferError();
            ErrorBuffer.Init(dbModel.TbError);

            LastId = this.dbModel.TbThickHeat.MaxID;
        }


        
        /// <summary>
        /// 
        /// </summary>
        public void AddThickHeat(
            Lc_ThickHeat thickHeat)
        {
            ThickHeatBuffer.Add(thickHeat);
            LastId = thickHeat.ID;
        }

        public void GetFrame(long Id, AsyncCBHandler asyncDelegate, object asyncContext)
        {
            GetFrameReponse reponse = new GetFrameReponse();
            reponse.Id = Id;

            Task.Factory.StartNew(() =>
            {
                List<Db_ThickHeat> db_thickHeats;
                if (Id <= 0)
                    db_thickHeats = dbModel.TbThickHeat.Find(
                        $"ORDER BY {nameof(Db_ThickHeat.ID)} DESC" +
                        $" LIMIT 1 OFFSET {-Id}");
                else
                    db_thickHeats = dbModel.TbThickHeat.Find(
                        $"WHERE {nameof(Db_ThickHeat.ID)} = {Id}");

                if (db_thickHeats.Count() == 0)
                {
                    return;
                }

                var lc_thickHeat = Lc_AutoMapperProfile.Mapper.Map<Lc_ThickHeat>(db_thickHeats.First());

                reponse.thickHeat = lc_thickHeat;
            }).Wait();


            asyncDelegate(asyncContext, reponse);
        }

        /// <summary>
        /// 获取一幅稳定的数据;
        /// </summary>
        /// <param name="Id">以Id为起始点, 向前或者向后或者最近稳定的一幅数据</param>
        /// <param name="isPre"></param>
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        public async void GetStableFrame(long id, bool isPre, AsyncCBHandler asyncDelegate, object asyncContext) 
        {
            var reponse = new GetStableFrameReponse();
            reponse.id = id;
            reponse.isPre = isPre;

            await Task.Factory.StartNew(() =>
            {
                if (id <= 0)
                {
                    string sql =
                        $"SELECT {nameof(Db_ThickHeat.ID)} FROM { dbModel.TbThickHeat.TableName}" +
                        $" ORDER BY {nameof(Db_ThickHeat.ID)} DESC" +
                        $" LIMIT 1 OFFSET {-id}";
                    var ret = dbModel.sqliteHelper.ExecuteScalar(sql);
                    if (ret == DBNull.Value)
                        return;

                    id = Convert.ToInt32(ret);
                }

                List<Db_ThickHeat> db_thickHeats = null;
                if (isPre)
                {
                    db_thickHeats = dbModel.TbThickHeat.Find(
                        $"WHERE {nameof(Db_ThickHeat.ID)} <= {id}" +
                        $" AND {nameof(Db_ThickHeat.IsStable)} = true" +
                        $" ORDER BY {nameof(Db_ThickHeat.ID)} DESC" +
                        $" LIMIT 1");
                }
                else {
                    db_thickHeats = dbModel.TbThickHeat.Find(
                        $"WHERE {nameof(Db_ThickHeat.ID)} >= {id}" +
                        $" AND {nameof(Db_ThickHeat.IsStable)} = true" +
                        $" ORDER BY {nameof(Db_ThickHeat.ID)}" +
                        $" LIMIT 1");
                }

                if (db_thickHeats.Count() == 0)
                {
                    return;
                }

                var lc_thickHeat = Lc_AutoMapperProfile.Mapper.Map<Lc_ThickHeat>(db_thickHeats.First());

                reponse.thickHeat = lc_thickHeat;
            });

            asyncDelegate(asyncContext, reponse);
        }

        /// <summary>
        /// 以Id为起始点, 向前或者向后获取最近通道改变时间不相同的数据 或 起效数据
        /// </summary>
        /// <param name="id"></param>
        /// <param name="isPre">向前</param>
        /// <param name="isTakeEffect">数据起效</param>
        /// <param name="isDiffCTime">加热不同</param>
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        //[Call(typeof(GetFrameReponse))]
        public async void GetFrameAdv(long id, bool isPre, bool isTakeEffect, bool isDiffCTime, AsyncCBHandler asyncDelegate, object asyncContext)
        {
            var reponse = new GetFrameReponse();
            reponse.Id = id;

            //会慢，需要分个线程独立做这事
            await Task.Factory.StartNew(() =>
            {
                if (id <= 0)
                {
                    //先获取真实ID
                    string sql =
                        $"SELECT ID FROM {dbModel.TbThickHeat.TableName}" +
                        $" ORDER BY ID DESC" +
                        $" LIMIT 1 OFFSET {-id}";
                    var ret = dbModel.sqliteHelper.ExecuteScalar(sql);
                    if (ret == DBNull.Value)
                        return;

                    id = Convert.ToInt32(ret);
                }

                string ctime_str = "";
                if (isDiffCTime)
                {
                    DateTime ctime;
                    //获取对应ID 的 通道改变时间
                    {
                        string sql =
                            $"SELECT {nameof(Db_ThickHeat.HTime)} FROM {dbModel.TbThickHeat.TableName}" +
                            $" WHERE ID={id}";
                        var ret = dbModel.sqliteHelper.ExecuteScalar(sql);
                        if (ret == DBNull.Value)
                            return;

                        ctime = Convert.ToDateTime(ret);
                    }
                    ctime_str = ctime.ToStringOfSQLiteFieldType();
                }

                List<Db_ThickHeat> db_thickHeats = null;
                {
                    string condition = "";
                    string symbol = isPre ? "<" : ">";
                    condition += $"WHERE ID{symbol}{id}";
                    if (isDiffCTime)
                        condition += $" AND {nameof(Db_ThickHeat.HTime)}<>{ctime_str}";

                    if (isTakeEffect)
                        condition += $" AND {nameof(Db_ThickHeat.IsStable)}=TRUE";

                    condition += $" ORDER BY ID";
                    if (isPre)
                        condition += " DESC";

                    condition += " LIMIT 1";

                    db_thickHeats = dbModel.TbThickHeat.Find(condition);
                }

                if (db_thickHeats.Count() == 0)
                {
                    return;
                }

                var lc_ThickHeat = Lc_AutoMapperProfile.Mapper.Map<Lc_ThickHeat>(db_thickHeats.First());

                reponse.thickHeat = lc_ThickHeat;
            });

            asyncDelegate(asyncContext, reponse);
        }
    }
}
