using AutoMapper;
using FLY.Thick.FilmCasting.Common;
using FLY.Thick.FilmCasting.IService;
using FLY.Thick.FilmCasting.Server;
using FLY.Thick.FilmCasting.Server.Model;
using Misc;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Threading;

namespace FLY.Thick.FilmCasting.UI.Server
{
    /// <summary>
    /// 图片历史
    /// </summary>
    public class PicHistory:INotifyPropertyChanged
    {

        public event PropertyChangedEventHandler PropertyChanged;

        #region 参数
        public bool Enable { get; set; }

        /// <summary>
        /// 图片文件夹路径
        /// </summary>
        public string RootPath { get; set; } = @"D:\film_casting_pic";

        /// <summary>
        /// 图片宽度
        /// </summary>
        public int PicWidth { get; set; } = 1024;

        /// <summary>
        /// 图片高度
        /// </summary>
        public int PicHeight { get; set; } = 768 / 3;

        /// <summary>
        /// 数据能保存的天数
        /// </summary>
        public int KeepDay { get; set; } = 360;


        /// <summary>
        /// X轴间隔
        /// </summary>
        public int XStep { get; set; } = 10;
        /// <summary>
        /// Y轴比例
        /// </summary>
        public double YRangePercent { get; set; } = 3;

        /// <summary>
        /// 图片保存时间间隔
        /// </summary>
        public double IntervalMin { get; set; } = 1;

        /// <summary>
        /// Y轴%显示
        /// </summary>
        public bool IsPercent { get; set; } = true;

        #endregion
        #region 状态
        /// <summary>
        /// 当前保存的数据天数
        /// </summary>
        public int CurrDays { get; private set; }
        /// <summary>
        /// 计数器， 大于 IntervalMin*60 就会触发 GetFrame
        /// </summary>
        public int CounterSec { get; private set; }
        #endregion

        /// <summary>
        /// 已经保存了数据的日期，
        /// </summary>
        private List<DateTime> dateInRootPath = new List<DateTime>();
        public ScanGraphVm scanGraphVm;
        IBulkDbService bulkDb;
        ScanWarning scanWarning;
        DispatcherTimer timer;
        long lastScanDataId;


        public PicHistory()
        {


        }
        public void Init(
            IBulkDbService bulkDb,
            ScanWarning scanWarning,
            FilmCastingProfileParam profileParam)
        {
            this.bulkDb = bulkDb;
            this.scanWarning = scanWarning;

            Load();
            InitKeepDay();

            lastScanDataId = bulkDb.LastScanDataId;


            this.scanGraphVm = new ScanGraphVm();
            scanGraphVm.Init(this, profileParam);


            this.PropertyChanged += PicHistory_PropertyChanged;

            //每分钟获取一次
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(1);
            timer.Tick += Timer_Tick;

            if (Enable)
                Start();
        }
        public void Start() 
        {
            timer.Start();
        }
        public void Stop()
        {
            timer.Stop();
        }
        private void PicHistory_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(IntervalMin))
            {
                timer.Interval = TimeSpan.FromMinutes(IntervalMin);
            }
            else if (e.PropertyName == nameof(Enable)) {
                timer.IsEnabled = Enable;
            }
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            CounterSec++;
            if (CounterSec < IntervalMin * 60)
                return;
            //触发！！！
            CounterSec = 0;

            if (lastScanDataId != bulkDb.LastScanDataId)
            {
                lastScanDataId = bulkDb.LastScanDataId;
                GetFrame();
            }
        }
        void GetFrame()
        {
            bulkDb.GetFrame(
                new Pack_GetFrameRequest()
                {
                    Id = 0,
                    Mix = scanWarning.Mix,
                    TimeRange = TimeSpan.FromMinutes(5),
                    AvgRange = scanWarning.Target * scanWarning.TolerancePercent * 2
                },
                async (object asyncContext, object retData) =>
                {
                    Pack_GetFrameReponse reponse = retData as Pack_GetFrameReponse;
                    await Add(reponse);
                }, this);
        }

        string CreateCurrPath(DateTime time, bool isWarning)
        {
            //创建路径
            DateTime dt = time;
            string dirpath;
            if (isWarning)
            {
                dirpath = RootPath + @"\iswarning\" + dt.ToString(@"yyyy\\MM\\dd");
            }
            else
            {
                dirpath = RootPath + @"\all\" + dt.ToString(@"yyyy\\MM\\dd");
            }
            Directory.CreateDirectory(dirpath);
            return $@"{dirpath}\{dt:HH_mm_ss}.jpg";
        }
        public async void SavePic(string path) 
        {
            
            //一定要把 scangraph 放入容器， 且scangraph  Left,Top 对齐，margin=0
            //不然有黑框
            //整个scangraph 的尺寸是 Margin+(Width,Height)
            //Margin 是透明，也就是黑色
            var viewbox = new Viewbox();

            ScanGraph scanGraph = new ScanGraph
            {
                Width = PicWidth,
                Height = PicHeight,
                //HorizontalAlignment = System.Windows.HorizontalAlignment.Left,
                //VerticalAlignment = System.Windows.VerticalAlignment.Top,
                //Margin = new System.Windows.Thickness()
            };

            scanGraph.Init(scanGraphVm);
            viewbox.Child = scanGraph;

            viewbox.Measure(scanGraph.RenderSize);
            viewbox.Arrange(new System.Windows.Rect(new System.Windows.Point(0, 0), scanGraph.RenderSize));

            scanGraph.ChartUpdate();//强制使 livechart 刷新
            viewbox.UpdateLayout();


            ChartToImage.SaveToJpeg(scanGraph, path);
        }
        public async Task Add(Pack_GetFrameReponse reponse)
        {
            if (reponse.scanData == null)
                return;//没有数据

            double avg = reponse.scanData.Thicks.AverageNoNull();
            if (double.IsNaN(avg))
                return;//没有数据

            //报警判断
            var checkResult = scanWarning.Check(reponse.scanData.Thicks);
            bool isWarning = checkResult == ScanWarning.CheckResult.Warning;

            //ALL
            string path = CreateCurrPath(reponse.scanData.EndTime, false);

            App.Current.MainWindow.Dispatcher.Invoke(() =>
            {
                scanGraphVm.UpdateValue(reponse, isWarning);

                SavePic(path);
            });

            await Task.Factory.StartNew(() =>
            {
                try
                {
                    if (isWarning)
                    {
                        string path_iswarning = CreateCurrPath(reponse.scanData.EndTime, true);
                        File.Copy(path, path_iswarning, true);
                    }

                    Keep();
                }
                catch
                {
                    return;
                }
            });
        }


        #region 自动删数据
        private void InitKeepDay()
        {
            dateInRootPath.Clear();
            if (!Directory.Exists(RootPath + @"\all"))
            {
                Directory.CreateDirectory(RootPath + @"\all");
                return;
            }

            DirectoryInfo mydir = new DirectoryInfo(RootPath + @"\all");
            //年
            Regex regex_year = new Regex(@"\d{4}");
            Regex regex_month = new Regex(@"\d{2}");
            Regex regex_day = new Regex(@"\d{2}");

            var fsil_year = from fsi in mydir.GetFileSystemInfos()
                            where (fsi.Attributes == FileAttributes.Directory) && (regex_year.IsMatch(fsi.Name))
                            select fsi;

            foreach (var fsi_year in fsil_year)
            {
                var fsil_month =
                    from fsi in ((DirectoryInfo)fsi_year).GetFileSystemInfos()
                    where (fsi.Attributes == FileAttributes.Directory) && (regex_month.IsMatch(fsi.Name))
                    select fsi;

                foreach (var fsi_month in fsil_month)
                {
                    var fsil_day =
                        from fsi in ((DirectoryInfo)fsi_month).GetFileSystemInfos()
                        where (fsi.Attributes == FileAttributes.Directory) && (regex_day.IsMatch(fsi.Name))
                        select fsi;

                    foreach (var fsi_day in fsil_day)
                    {

                        DateTime dt = new DateTime(
                            int.Parse(fsi_year.Name),
                            int.Parse(fsi_month.Name),
                            int.Parse(fsi_day.Name));

                        //if (DateTime.TryParse(fsi_year.Name.ToString() + "-" + fsi_month.Name.ToString() + "-" + fsi_day.Name.ToString(), out dt)) 
                        {
                            dateInRootPath.Add(dt);
                        }
                    }
                }
            }
            dateInRootPath.Sort(new Comparison<DateTime>(
                delegate (DateTime t1, DateTime t2)
                {
                    if (t1 > t2)
                        return 1;
                    else if (t1 == t2)
                        return 0;
                    else
                        return -1;
                }));
            CurrDays = dateInRootPath.Count;
            Keep();
        }
        private void Keep()
        {
            while (dateInRootPath.Count > KeepDay)
            {
                string dirpath = RootPath + @"\all\" + dateInRootPath.First().ToString(@"yyyy\\MM\\dd");
                Directory.Delete(dirpath, true);

                dirpath = RootPath + @"\iswarning\" + dateInRootPath.First().ToString(@"yyyy\\MM\\dd");
                Directory.Delete(dirpath, true);

                dateInRootPath.RemoveAt(0);
            }
            CurrDays = dateInRootPath.Count;
        }


        #endregion




        string file_path = "pichistory.json";
        /// <summary>
        /// 加载历史数据
        /// </summary>
        /// <returns></returns>
        public bool Load()
        {
            return PicHistoryJsonDb.Load(this, file_path);
        }
        /// <summary>
        /// 保存
        /// </summary>
        public bool Save()
        {
            return PicHistoryJsonDb.Save(this, file_path);
        }
    }

    public class PicHistoryJsonDb
    {
        static Mapper Mapper { get; } = new AutoMapper.Mapper(new MapperConfiguration(c =>
        {
            c.CreateMap<PicHistory, PicHistoryJsonDb>().ReverseMap();
        }));

        public static bool Load(PicHistory src, string file_path)
        {
            try
            {
                if (File.Exists(file_path))
                {
                    string json = File.ReadAllText(file_path);
                    var p = JsonConvert.DeserializeObject<PicHistoryJsonDb>(json);
                    Mapper.Map(p, src);
                    return true;
                }
            }
            catch
            {
                //异常，没有json 解码失败
            }

            return false;
        }
        public static bool Save(PicHistory src, string file_path)
        {
            var p = Mapper.Map<PicHistoryJsonDb>(src);
            try
            {
                File.WriteAllText(file_path, JsonConvert.SerializeObject(p, Formatting.Indented));
                return true;
            }
            catch
            {
                //异常，没有json 编码失败

            }
            return false;

        }


        public bool Enable { get; set; }

        /// <summary>
        /// 图片文件夹路径
        /// </summary>
        public string RootPath { get; set; } = @"D:\film_casting_pic";

        /// <summary>
        /// 图片宽度
        /// </summary>
        public int PicWidth { get; set; } = 1024;

        /// <summary>
        /// 图片高度
        /// </summary>
        public int PicHeight { get; set; } = 768 / 3;

        /// <summary>
        /// 数据能保存的天数
        /// </summary>
        public int KeepDay { get; set; } = 360;



        /// <summary>
        /// Y轴比例
        /// </summary>
        public double YRangePercent { get; set; } = 3;

        /// <summary>
        /// 间隔时间
        /// </summary>
        public double IntervalMin { get; set; } = 1;

        /// <summary>
        /// Y轴%显示
        /// </summary>
        public bool IsPercent { get; set; } = true;
    }
}
