using LiteDB;
using log4net;
using log4net.Repository.Hierarchy;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web.UI;
using VIZ.Framework.Core;
using VIZ.Package.Domain;
using VIZ.Package.Storage;

namespace VIZ.Package.Service
{
    /// <summary>
    /// 页服务
    /// </summary>
    public class PageService
    {
        /// <summary>
        /// 日志
        /// </summary>
        private readonly static ILog log = LogManager.GetLogger(typeof(PageService));

        /// <summary>
        /// 加载页模板集合
        /// </summary>
        /// <returns>节目模板集合</returns>
        public IList<PageTemplateModel> LoadPageTemplates()
        {
            List<PageTemplateModel> list = new List<PageTemplateModel>();

            foreach (var entity in ApplicationDomainEx.ProjectDbContext.PageTemplate.FindAll().ToList())
            {
                PageTemplateModel model = new PageTemplateModel();

                model.Scene = entity.Scene;
                model.ScenePath = entity.ScenePath;
                model.Remark = entity.Remark;
                model.Layer = entity.Layer;
                model.EngineType = entity.EngineType;
                model.PageType = entity.PageType;
                model.Order = entity.Order;
                model.TransitionLogic = entity.TransitionLogic;
                model.LayerIdentifier = entity.LayerIdentifier;
                model.StateIdentifier = entity.StateIdentifier;
                model.BackgroundScene = entity.BackgroundScene;
                model.TemplateID = entity.TemplateID;
                // 获取缩略图
                model.ThumbnailBitmap = this.GetSceneThumbnailFromDB(model);

                list.Add(model);
            }

            return list.OrderBy(p => p.Order).ToList();
        }

        /// <summary>
        /// 保存页模板集合
        /// </summary>
        /// <param name="pageTemplates">页模板集合</param>
        public void SavePageTemplates(IList<PageTemplateModel> pageTemplates)
        {
            // Step 1. 保存数据
            ApplicationDomainEx.ProjectDbContext.PageTemplate.DeleteAll();

            List<PageTemplateEntity> list = new List<PageTemplateEntity>();

            for (int i = 0; i < pageTemplates.Count; i++)
            {
                PageTemplateModel model = pageTemplates[i];
                PageTemplateEntity entity = new PageTemplateEntity();

                entity.Scene = model.Scene;
                entity.ScenePath = model.ScenePath;
                entity.Remark = model.Remark;
                entity.Layer = model.Layer;
                entity.EngineType = model.EngineType;
                entity.PageType = model.PageType;
                entity.Order = model.Order;
                entity.TransitionLogic = model.TransitionLogic;
                entity.LayerIdentifier = model.LayerIdentifier;
                entity.StateIdentifier = model.StateIdentifier;
                entity.BackgroundScene = model.BackgroundScene;
                entity.TemplateID = model.TemplateID;
                entity.Order = i;

                this.SaveSceneThumbnailToDB(model, model.ThumbnailBitmap);

                list.Add(entity);
            }

            ApplicationDomainEx.ProjectDbContext.PageTemplate.Insert(list);
        }

        /// <summary>
        /// 加载页分组集合
        /// </summary>
        /// <returns>页分组集合</returns>
        public IList<PageGroupModel> LoadPageGroups()
        {
            Dictionary<Guid, PageGroupModel> dic = new Dictionary<Guid, PageGroupModel>();

            // 页分组
            foreach (var entity in ApplicationDomainEx.ProjectDbContext.PageGroup.FindAll())
            {
                PageGroupModel model = new PageGroupModel();

                model.GroupID = entity.GroupID;
                model.GroupName = entity.GroupName;
                model.Order = entity.Order;

                dic[model.GroupID] = model;
            }

            // 页
            foreach (var entity in ApplicationDomainEx.ProjectDbContext.Page.FindAll().ToList())
            {
                if (!dic.TryGetValue(entity.PageGroupID, out PageGroupModel groupModel))
                    continue;

                PageModel model = new PageModel();

                model.Scene = entity.Scene;
                model.ScenePath = entity.ScenePath;
                model.Remark = entity.Remark;
                model.Layer = entity.Layer;
                model.EngineType = entity.EngineType;
                model.PageType = entity.PageType;
                model.Order = entity.Order;
                model.TransitionLogic = entity.TransitionLogic;
                model.LayerIdentifier = entity.LayerIdentifier;
                model.StateIdentifier = entity.StateIdentifier;
                model.BackgroundScene = entity.BackgroundScene;
                model.TemplateID = entity.TemplateID;
                model.PageID = entity.PageID;
                model.PageGroupID = entity.PageGroupID;
                model.TemplateID = entity.TemplateID;
                model.PluginID = entity.PluginID;
                model.Order = entity.Order;
                model.PluginName = ApplicationDomainEx.PluginInfos.FirstOrDefault(p => p.ID == entity.PluginID)?.Name;
                model.PageNum = entity.PageNum;
                model.ConnGroupID = entity.ConnGroupID;
                // 场景缩略图
                model.ThumbnailBitmap = this.GetSceneThumbnailFromDB(model);

                groupModel.Pages.Add(model);
            }

            // 页分组排序
            foreach (var kv in dic)
            {
                kv.Value.Pages = kv.Value.Pages.OrderBy(p => p.Order).ToObservableCollection();
            }

            return dic.Values.OrderBy(p => p.Order).ToList();
        }

        /// <summary>
        /// 保存页分组集合
        /// </summary>
        /// <param name="pageGroups">页分组集合</param>
        public void SavePageGroups(IList<PageGroupModel> pageGroups)
        {
            List<PageGroupEntity> groups = new List<PageGroupEntity>();
            List<PageEntity> pages = new List<PageEntity>();

            for (int i = 0; i < pageGroups.Count; i++)
            {
                PageGroupModel groupModel = pageGroups[i];

                // 分组
                PageGroupEntity groupEntity = new PageGroupEntity();

                groupEntity.GroupID = groupModel.GroupID;
                groupEntity.GroupName = groupModel.GroupName;
                groupEntity.Order = i;

                groups.Add(groupEntity);

                // 页
                for (int j = 0; j < groupModel.Pages.Count; j++)
                {
                    PageModel pageModel = groupModel.Pages[j];

                    PageEntity pageEntity = new PageEntity();

                    pageEntity.Scene = pageModel.Scene;
                    pageEntity.ScenePath = pageModel.ScenePath;
                    pageEntity.Remark = pageModel.Remark;
                    pageEntity.Layer = pageModel.Layer;
                    pageEntity.EngineType = pageModel.EngineType;
                    pageEntity.PageType = pageModel.PageType;
                    pageEntity.Order = pageModel.Order;
                    pageEntity.TemplateID = pageModel.TemplateID;
                    pageEntity.PageID = pageModel.PageID;
                    pageEntity.PageGroupID = pageModel.PageGroupID;
                    pageEntity.TemplateID = pageModel.TemplateID;
                    pageEntity.PluginID = pageModel.PluginID;
                    pageEntity.PageNum = pageModel.PageNum;
                    pageEntity.ConnGroupID = pageModel.ConnGroupID;
                    pageEntity.Order = j;
                    pageEntity.TransitionLogic = pageModel.TransitionLogic;
                    pageEntity.LayerIdentifier = pageModel.LayerIdentifier;
                    pageEntity.StateIdentifier = pageModel.StateIdentifier;
                    pageEntity.BackgroundScene = pageModel.BackgroundScene;
                    // 保存缩略图
                    this.SaveSceneThumbnailToDB(pageModel, pageModel.ThumbnailBitmap);

                    pages.Add(pageEntity);
                }
            }

            ApplicationDomainEx.ProjectDbContext.PageGroup.DeleteAll();
            ApplicationDomainEx.ProjectDbContext.Page.DeleteAll();

            ApplicationDomainEx.ProjectDbContext.PageGroup.Insert(groups);
            ApplicationDomainEx.ProjectDbContext.Page.Insert(pages);
        }

        /// <summary>
        /// 从缓存获取场景缩略图
        /// </summary>
        /// <param name="pageBase">页基类</param>
        /// <returns>场景缩略图</returns>
        private System.Drawing.Bitmap GetSceneThumbnailFromDB(PageModelBase pageBase)
        {
            try
            {
                Guid id = Guid.Empty;
                if (pageBase is PageTemplateModel template)
                {
                    id = template.TemplateID;
                }
                else if (pageBase is PageModel page)
                {
                    id = page.PageID;
                }
                else
                {
                    return null;
                }

                LiteFileInfo<Guid> img = ApplicationDomainEx.ProjectDbContext.SceneThumbnailCache.FindById(id);
                if (img == null)
                    return null;

                using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
                {
                    img.CopyTo(ms);

                    return new System.Drawing.Bitmap(ms);
                }
            }
            catch (Exception ex)
            {
                log.Error(ex);

                return null;
            }
        }

        /// <summary>
        /// 保存缩略图至缓存
        /// </summary>
        /// <param name="pageBase">页基类</param>
        /// <param name="bmp">场景缩略图</param>
        private void SaveSceneThumbnailToDB(PageModelBase pageBase, System.Drawing.Bitmap bmp)
        {
            if (bmp == null)
                return;

            try
            {
                Guid id = Guid.Empty;
                if (pageBase is PageTemplateModel template)
                {
                    id = template.TemplateID;
                }
                else if (pageBase is PageModel page)
                {
                    id = page.PageID;
                }
                else
                {
                    return;
                }

                using (Bitmap dest = new Bitmap(bmp.Width, bmp.Height, bmp.PixelFormat))
                using (Graphics g = Graphics.FromImage(dest))
                {
                    g.DrawImage(bmp, 0, 0);

                    using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
                    {
                        dest.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                        ms.Position = 0;

                        ApplicationDomainEx.ProjectDbContext.SceneThumbnailCache.Upload(id, $"{id}", ms);
                    }
                }

            }
            catch (Exception ex)
            {
                log.Error(ex);
            }
        }
    }
}
