using DevExpress.Xpf.Grid;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using VIZ.Package.Domain;
using VIZ.Package.Storage;

namespace VIZ.Package.Service
{
    /// <summary>
    /// 底飞服务
    /// </summary>
    public class ScrollElementService
    {
        /// <summary>
        /// Viz命令控制对象服务
        /// </summary>
        private VizCommandControlObjectService vizCommandControlObjectService = new VizCommandControlObjectService();

        /// <summary>
        /// 保存底飞数据包
        /// </summary>
        /// <param name="pageBase">底飞页</param>
        /// <param name="templatePageBase">底飞选用的模板页</param>
        /// <param name="templatePageBaseScrollElementField">底飞页ScrollElement字段</param>
        /// <param name="scrollElementFields">选用的模板页字段集合</param>
        /// <returns>底飞数据包</returns>
        public ScrollElementPackageEntity GetScrollElementPackage(PageModelBase pageBase, PageModelBase templatePageBase, ControlFieldNodeModel templatePageBaseScrollElementField, List<ControlFieldNodeModel> scrollElementFields)
        {
            ScrollElementPackageEntity package = new ScrollElementPackageEntity();

            package.TemplateOrPageID = pageBase.GetTemplateIdOrPageId();
            package.TemplateScenePath = templatePageBase.ScenePath;
            package.FieldIdentifier = templatePageBaseScrollElementField.FieldIdentifier;

            if (scrollElementFields != null && scrollElementFields.Count != 0)
            {
                foreach (ControlFieldNodeModel field in scrollElementFields)
                {
                    ControlFieldEntity entity = new ControlFieldEntity();
                    entity.PageID = package.TemplateOrPageID;
                    entity.FieldIdentifier = field.FieldIdentifier;
                    entity.Value = field.Value;
                    entity.Type = field.Type;
                    entity.FieldDetail = field.FieldDetail;
                    entity.IsCustom = field.IsCustom;

                    package.TemplateFields.Add(entity);
                }
            }

            return package;
        }

        /// <summary>
        /// 保存底飞数据包
        /// </summary>
        /// <param name="package">底飞数据包</param>
        public void SaveScrollElementPackageToDB(ScrollElementPackageEntity package)
        {
            // 删除
            ApplicationDomainEx.ProjectDbContext.ScrollElementPackage.DeleteMany(p => p.TemplateOrPageID == package.TemplateOrPageID && p.FieldIdentifier == package.FieldIdentifier);

            // 插入
            ApplicationDomainEx.ProjectDbContext.ScrollElementPackage.Insert(package);
        }

        /// <summary>
        /// 获取底飞数据包
        /// </summary>
        /// <param name="pageBase">底飞页</param>
        /// <param name="templatePageBaseScrollElementField">底飞页ScrollElement字段</param>
        /// <returns></returns>
        public ScrollElementPackageEntity GetScrollElementPackageFromDB(PageModelBase pageBase, ControlFieldNodeModel templatePageBaseScrollElementField)
        {
            Guid templateOrPageId = pageBase.GetTemplateIdOrPageId();
            ScrollElementPackageEntity package = ApplicationDomainEx.ProjectDbContext.ScrollElementPackage.Find(p => p.TemplateOrPageID == templateOrPageId &&
                                                                                                                     p.FieldIdentifier == templatePageBaseScrollElementField.FieldIdentifier).FirstOrDefault();

            return package;
        }

        /// <summary>
        /// 获取动态对象列信息
        /// </summary>
        /// <param name="pageBase">页或模板</param>
        /// <param name="controlObject">控制对象</param>
        /// <param name="scrollElementFields">选用的模板页字段集合</param>
        /// <returns>动态对象列信息</returns>
        public List<GridColumnScrollElementFieldDefinition> GetDynamicColumns(PageModelBase pageBase, ControlObjectModel controlObject, List<ControlFieldNodeModel> scrollElementFields)
        {
            List<GridColumnScrollElementFieldDefinition> columns = new List<GridColumnScrollElementFieldDefinition>();

            // 索引
            GridColumnScrollElementFieldDefinition index = new GridColumnScrollElementFieldDefinition();
            index.Header = "序号";
            index.AllowEditing = false;
            index.AllowResizing = true;
            index.Width = new GridColumnWidth(30, GridColumnUnitType.Pixel);
            index.MinWidth = 40;
            index.Type = VizControlFieldType.system_index;
            columns.Add(index);

            if (pageBase == null || scrollElementFields == null || scrollElementFields.Count == 0)
                return columns;

            foreach (ControlFieldNodeModel field in scrollElementFields)
            {
                GridColumnScrollElementFieldDefinition column = new GridColumnScrollElementFieldDefinition();

                column.Header = (field.FieldIdentifier == field.Description) ? field.FieldIdentifier : $"({field.Description}){field.FieldIdentifier}";
                column.FieldName = field.FieldIdentifier;
                column.AllowEditing = !VizCommandControlObjectService.ALLOW_EDITING_FALSE_TYPES.Contains(field.Type);
                column.MinWidth = 320;
                column.PageBase = pageBase;
                column.ControlObject = controlObject;
                column.ControlField = field;
                column.Type = field.Type;

                columns.Add(column);
            }

            return columns;
        }

        /// <summary>
        /// 获取动态对象列表
        /// </summary>
        /// <param name="scrollElementFields">选用的模板页字段集合</param>
        /// <param name="scrollElementValue">底飞元素值</param>
        /// <returns>动态对象列表</returns>
        public List<ExpandoObject> GetDynamicList(List<ControlFieldNodeModel> scrollElementFields, string scrollElementValue)
        {
            List<ExpandoObject> list = new List<ExpandoObject>();
            if (scrollElementFields == null || scrollElementFields.Count == 0 || string.IsNullOrWhiteSpace(scrollElementValue))
                return list;

            ControlObject_Entry_Node entry = new ControlObject_Entry_Node();
            using (System.IO.MemoryStream ms = new System.IO.MemoryStream(Encoding.UTF8.GetBytes(scrollElementValue)))
            {
                XElement element = XElement.Load(ms);
                entry.FromXmlElement(element);
            }

            for (int i = 0; i < entry.Elements.Count; i++)
            {
                ControlObject_Element_Node row = entry.Elements[i];

                IDictionary<string, object> item = new ExpandoObject();

                ControlObject_Entry_Node data = row.Entrys.FirstOrDefault(p => p.Name == "data");
                if (data == null)
                    continue;

                foreach (ControlObject_Entry_Node cell in data.Entrys)
                {
                    if (string.IsNullOrWhiteSpace(cell.Name))
                        continue;

                    item[cell.Name] = cell.Value;
                }

                list.Add(item as ExpandoObject);
            }

            return list;
        }

        /// <summary>
        /// 获取底飞值
        /// </summary>
        /// <param name="templateScenePath">模板场景路径</param>
        /// <param name="templateFields">模板场景字段信息</param>
        /// <param name="items"></param>
        /// <param name="tag">根节点标志</param>
        /// <returns></returns>
        public string GetScrollElementValue(string templateScenePath, List<ControlFieldEntity> templateFields, IList<ExpandoObject> items, VizScrollElementRootTag tag)
        {
            XElement root = new XElement(tag.ToString());

            if (string.IsNullOrWhiteSpace(templateScenePath) || templateFields == null || templateFields.Count == 0 || items == null || items.Count == 0)
                return root.ToString(SaveOptions.DisableFormatting);

            for (int i = 0; i < items.Count; i++)
            {
                IDictionary<string, object> item = items[i];

                ControlObject_Element_Node element = new ControlObject_Element_Node();

                element.Complete = true;
                element.Name = i.ToString();
                element.Scene = templateScenePath;

                // viz
                ControlObject_Entry_Node viz = new ControlObject_Entry_Node();
                viz.Name = "viz";
                viz.Entrys.Add(new ControlObject_Entry_Node { Name = "location" });
                viz.Entrys.Add(new ControlObject_Entry_Node
                {
                    Name = "front",
                    Entrys = { new ControlObject_Entry_Node { Name = "scene", Value = templateScenePath } }
                });
                viz.Entrys.Add(new ControlObject_Entry_Node { Name = "load", Value = "scene" });
                viz.Entrys.Add(new ControlObject_Entry_Node { Name = "viz_layer" });
                viz.Entrys.Add(new ControlObject_Entry_Node { Name = "use_all_directors", Value = "yes" });

                element.Entrys.Add(viz);

                // schema
                ControlObject_Schema_Node schema = new ControlObject_Schema_Node();
                foreach (ControlFieldEntity field in templateFields)
                {
                    ControlFieldNodeModel fieldModel = this.vizCommandControlObjectService.CreateControlFieldNodeModeFromEntity(field);

                    ControlObject_Field_node field_node = new ControlObject_Field_node();
                    field_node.Name = fieldModel.FieldIdentifier;
                    field_node.Description = fieldModel.Description;
                    field_node.Type = field.Type.ToString().Replace("@", string.Empty);
                    field_node.Location = "";

                    schema.Fields.Add(field_node);
                }

                element.Schemas.Add(schema);

                // data
                ControlObject_Entry_Node data = new ControlObject_Entry_Node();
                data.Name = "data";
                foreach (var kv in item)
                {
                    data.Entrys.Add(new ControlObject_Entry_Node { Name = kv.Key, Value = kv.Value?.ToString() });
                }

                element.Entrys.Add(data);

                root.Add(element.ToXmlElement());
            }

            return root.ToString(SaveOptions.DisableFormatting);
        }
    }
}
