using Microsoft.EntityFrameworkCore;
using NPOI.OpenXmlFormats.Dml;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Repository.Entities;
using Siger.Middlelayer.Repository.Extensions;
using Siger.Middlelayer.Repository.Repositories.Interface;
using Siger.Middlelayer.Repository.Response;
using Siger.Middlelayer.Utility.ExcelImport;
using Siger.Middlelayer.Utility.ImportEntities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace Siger.Middlelayer.Repository.Repositories
{
    internal class SigerProjectMachineAttributionRepository : ApiConfigRepositoryBase<siger_project_machine_attribution>, ISigerProjectMachineAttributionRepository
    {
        private readonly ApiConfigDbContext _context;
        public SigerProjectMachineAttributionRepository(ApiConfigDbContext context) : base(context)
        {
            _context = context;
        }

        public List<ResponseGetSectionTree> GetSectionChildren(int pid, int parentid, List<siger_project_level_section> sections, int lastLevel, List<siger_project_machine_attribution> attrs,int attribution = 0)
        {
            var response = new List<ResponseGetSectionTree>();
            var model = sections.Where(f => f.parentid.Equals(parentid));
            if (!model.Any())
            {
                return GetAttributionTreeData(pid, 0, parentid, attrs, attribution);
            }
            foreach (var item in model)
            {
                var data = new ResponseGetSectionTree
                {
                    disabled = true,
                    expand = true,
                    label = item.title,
                    value = item.id,
                    levelid = item.levelid
                };
                var isAny = sections.Any(f => f.parentid.Equals(item.id));
                if (!isAny)
                {
                    if (data.levelid.Equals(lastLevel))
                    {
                        data.attrubution = 1;
                    }
                }
                var children = GetSectionChildren(pid, item.id, sections, lastLevel, attrs, attribution);
                if (children.Any())
                {
                    data.children = children;
                }
                response.Add(data);
            }
            return response;
        }

        private List<ResponseGetSectionTree> GetAttributionTreeData(int pid, int parentid, int station, List<siger_project_machine_attribution> attrs, int attribution = 0)
        {
            var response = new List<ResponseGetSectionTree>();
            var models = attrs.Where(f => f.parent.Equals(parentid) && f.station.Equals(station));
            if(attribution > 0)
            {
                models = models.Where(t => t.attribution == attribution);
            }

            if (!models.Any())
            {
                return response;
            }
            foreach (var item in models)
            {
                var machine = _context.siger_project_machine.FirstOrDefault(f => f.id == item.machine);
                var mcode = machine != null ? machine.code : "";
                response.Add(new ResponseGetSectionTree
                {
                    disabled = false,
                    expand = false,
                    label =$"{item.name}({mcode})",
                    value = item.id,
                    attrubution = item.attribution + 1,
                    children = GetAttributionTreeData(pid, item.id, station, attrs, attribution)
                });
            }
            return response;
        }

        public List<ResponseGetSectionTree> GetAttributionTreeDataBySection(int pid, int parentid, List<int> stations, bool isShowSparepart = false)
        {
            var response = new List<ResponseGetSectionTree>();
            Expression<Func<siger_project_machine_attribution, bool>> funCommon = f => f.parent.Equals(parentid) && f.projectid.Equals(pid) && f.status == (int)RowState.Valid && stations.Contains(f.station);
            Expression<Func<siger_project_machine_attribution, bool>> funAttr = f => true;
            if (!isShowSparepart)
            {
                funAttr = f => f.attribution < 4;
            }
            var predicate = funCommon.And(funAttr);
            var model = _context.siger_project_machine_attribution.Where(predicate);
            if (!model.Any())
            {
                return response;
            }
            foreach (var item in model)
            {
                response.Add(new ResponseGetSectionTree
                {
                    label = item.name,
                    value = item.machine,
                    children = GetAttributionTreeDataBySection(pid, item.id, stations)
                });
            }
            return response;
        }

        /// <summary>
        /// 不要多人同时导入设备属性！！
        /// </summary>
        /// <param name="levelmachine"></param>
        /// <param name="projectId"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        //public CommonImportResult ImportData(IEnumerable<MachineAttribution> data, int projectId, int userId)
        public CommonImportResult ImportData(IEnumerable<LevelSectionEntity> levelmachine, int projectId, int userId)
        {
            var errors = new List<string>();
            var projectLevelIds = GetSonLevels(0, projectId).Select(m => m.id).Distinct().OrderBy(q => q).ToList();
            if (!projectLevelIds.Any())
            {
                errors.Add(EnumHelper.GetEnumDesc(ConfigEnum.UserLevelNull));
                return new CommonImportResult(0, string.Join(";", errors));
            }
            var totalLevel = projectLevelIds.Count;
            var entities = new List<siger_project_machine_attribution>();
            var rowIndex = 1;
            foreach (var lvm in levelmachine)
            {
                if (lvm.Levels.Count()< totalLevel)
                {
                    errors.Add($"{rowIndex},{EnumHelper.GetEnumDesc(ConfigEnum.UserLevelNull)}");
                    continue;
                }

                var levelParent = 0;
                var levelSectionParentTxt = string.Empty;
                var levelId = 0; //最后一级
                var levelTxt = string.Empty; //最后一级
                var machineCode = string.Empty;
                for(int i=0;i< projectLevelIds.Count();i++)
                {
                    levelTxt = lvm.Levels[i];
                    levelId = projectLevelIds[i];
                    var levelObj = _context.siger_project_level_section.FirstOrDefault(f => f.projectid == projectId && f.title == levelTxt);
                    if (levelObj == null)
                    {
                        errors.Add($"{rowIndex},{levelTxt}");
                        continue;
                    }
                    if (i!= 0)
                    {
                        levelParent = projectLevelIds[i -1];
                        levelSectionParentTxt = lvm.Levels[i-1];
                    }
                }
              
                var levelSectionParent = _context.siger_project_level_section.FirstOrDefault(f => f.projectid == projectId && f.levelid == levelParent && f.title == levelSectionParentTxt);
                if (levelSectionParent==null)
                {
                    errors.Add($"{rowIndex},{levelSectionParentTxt}-{EnumHelper.GetEnumDesc(ConfigEnum.UserLevelNull)}");
                    continue;
                }
                var levelSection = _context.siger_project_level_section.FirstOrDefault(f => f.projectid == projectId && f.parentid== levelSectionParent.id && f.levelid == levelId && f.title == levelTxt);
                if (levelSection==null)
                {
                    errors.Add($"{rowIndex},{levelSectionParentTxt}-{levelTxt}-{EnumHelper.GetEnumDesc(ConfigEnum.UserLevelNull)}");
                    continue;
                }
                machineCode = lvm.Levels[lvm.Levels.Count - 1];

                var machineObj = _context.siger_project_machine.FirstOrDefault(f => f.projectid == projectId && f.code == machineCode && f.status==(int)RowState.Valid);
                if (machineObj==null)
                {
                    errors.Add($"{rowIndex},{EnumHelper.GetEnumDesc(ConfigEnum.MachineNotFound)}");
                    continue;
                }
                var attrimachine = _context.siger_project_machine_attribution.FirstOrDefault(f => f.projectid == projectId && f.machine == machineObj.id && f.station== levelSection.id && f.status == (int)RowState.Valid);
                if (attrimachine!=null)
                {
                    errors.Add($"{rowIndex},{EnumHelper.GetEnumDesc(ConfigEnum.MachineAlreadyBind)}");
                    continue;
                }
                entities.Add(new siger_project_machine_attribution
                {
                     projectid=projectId,
                     attribution=1,
                     station= levelSection.id,
                     machine=machineObj.id,
                     createtime=UnixTimeHelper.GetNow(),
                     creator=userId,
                     sparepart_id=0,
                     status=1,
                     name=machineObj.title
                });
            }
            if (errors.Any())
            {
                return new CommonImportResult(0, string.Join(";", errors));
            }
            try
            {
                _context.siger_project_machine_attribution.AddRange(entities);
                _context.SaveChanges();
                return new CommonImportResult(1, "1");
            }
            catch
            {
                throw;
            }

            //var errors = new List<string>();
            //var entities = new List<siger_project_machine_attribution>();
            //var rowIndex = 1;
            //var dataList = data.ToList();

            //var machines = _context.siger_project_machine.Where(q => q.projectid == projectId && q.status == (int)RowState.Valid).ToList();
            //var allsections = _context.siger_project_level_section.Where(q => q.projectid == projectId && q.status == (int)RowState.Valid).ToList();
            //var machineattributions = _context.siger_project_machine_attribution.Where(f => f.projectid == projectId && f.status == (int)RowState.Valid).ToList();

            //var list = data.Distinct().ToList();
            //if(list.Count != data.Count())
            //{
            //    errors.Add($"{rowIndex},{Convert.ToString((int)RequestEnum.RepeatBoxListCodeExsit)}");
            //}
            //foreach (var item in dataList)
            //{
            //    rowIndex++;
            //    var machine = machines.FirstOrDefault(q => q.id == item.machine);
            //    if (machine == null)
            //    {
            //        errors.Add($"{rowIndex},{Convert.ToString((int)ConfigEnum.MachineNotFound)}");
            //        continue;
            //    }
            //    //工站唯一性校验
            //    var groupdata = allsections.FirstOrDefault(q => q.title.Equals(item.group));
            //    if (groupdata == null)
            //    {
            //        errors.Add($"{rowIndex},{Convert.ToString((int)ConfigEnum.StationNotFound)}");
            //        continue;
            //    }
            //    var factorydata = allsections.FirstOrDefault(q => q.title.Equals(item.factory) && q.parentid == groupdata.id);
            //    if (factorydata == null)
            //    {
            //        errors.Add($"{rowIndex},{Convert.ToString((int)ConfigEnum.StationNotFound)}");
            //        continue;
            //    }
            //    var channeldata = allsections.FirstOrDefault(q => q.title.Equals(item.channel) && q.parentid == factorydata.id);
            //    if (channeldata == null)
            //    {
            //        errors.Add($"{rowIndex},{Convert.ToString((int)ConfigEnum.StationNotFound)}");
            //        continue;
            //    }
            //    var stationdata = allsections.FirstOrDefault(q => q.title.Equals(item.station) && q.parentid == channeldata.id);
            //    if (stationdata == null)
            //    {
            //        errors.Add($"{rowIndex},{Convert.ToString((int)ConfigEnum.StationNotFound)}");
            //        continue;
            //    }
            //    var attribution = EnumHelper.EnumToList<MachineAttributionEnum>().FirstOrDefault(f => f.Description.Equals(item.attribution_name));
            //    if (attribution == null)
            //    {
            //        errors.Add($"{rowIndex},{Convert.ToString((int)ConfigEnum.MachineAttributionNotFound)}");
            //    }
            //    if (!machine.attribution.Equals(attribution.EnumValue))
            //    {
            //        errors.Add($"{rowIndex},{Convert.ToString((int)ConfigEnum.MachineAttributionError)}");
            //    }
            //    if (attribution.EnumValue < 4 && attribution.EnumValue > 0)
            //    {
            //        var attrData = machineattributions.Where(f => f.machine.Equals(machine.id) && f.attribution.Equals(attribution.EnumValue));
            //        if (attrData.Any())
            //        {
            //            errors.Add($"{rowIndex},{Convert.ToString((int)ConfigEnum.MachineAlreadyBind)}");
            //        }
            //        var importData = data.Count(f => f.attribution_name.Equals(item.attribution_name) && f.machine.Equals(item.machine));
            //        if (importData > 2)
            //        {
            //            errors.Add($"{rowIndex},{Convert.ToString((int)ConfigEnum.MachineAttributionInvalid)}");
            //        }
            //    }
            //    if (item.parent_machine != 0)
            //    {
            //        var parent = machines.FirstOrDefault(q => q.id == item.parent_machine);
            //        if (parent == null)
            //        {
            //            errors.Add($"{rowIndex},{Convert.ToString((int)ConfigEnum.ParentMachineNotFound)}");
            //        }
            //        var attr = machineattributions.Where(f => f.machine.Equals(parent.id) && f.station.Equals(stationdata.id) && f.attribution.Equals(attribution.EnumValue - 1));
            //        if (attr == null)
            //        {
            //            var inparent = dataList.Where(f => f.machine.Equals(item.machine) && f.station.Equals(item.station));//watch out
            //            if (inparent == null)
            //            {
            //                errors.Add($"{rowIndex},{Convert.ToString((int)ConfigEnum.ParentMachineNotFound)}");
            //            }
            //        }
            //    }
            //}
            //if (errors.Any())
            //{
            //    return new CommonImportResult(0, string.Join(";", errors));
            //}
            //var startid = machineattributions.Any() ? machineattributions.Max(m => m.id) + 1 : 1;
            //foreach (var item in dataList)
            //{
            //    var attribution = EnumHelper.EnumToList<MachineAttributionEnum>().FirstOrDefault(f => f.Description.Equals(item.attribution_name));
            //    var machine = machines.FirstOrDefault(q => q.id == item.machine);
            //    var parent = machines.FirstOrDefault(q => q.id == item.machine);

            //    var groupdata = allsections.FirstOrDefault(q => q.title.Equals(item.group));
            //    var factorydata = allsections.FirstOrDefault(q => q.title.Equals(item.factory) && q.parentid == groupdata.id);
            //    var channeldata = allsections.FirstOrDefault(q => q.title.Equals(item.channel) && q.parentid == factorydata.id);
            //    var station = allsections.FirstOrDefault(q => q.title.Equals(item.station) && q.parentid == channeldata.id);
            //    var entity = new siger_project_machine_attribution
            //    {
            //        attribution = attribution.EnumValue,
            //        machine = machine.id,
            //        name = machine.title,
            //        parent = entities.FirstOrDefault(f => f.machine.Equals(parent?.id ?? 0) && f.station.Equals(station.id))?.id ?? 0,
            //        projectid = projectId,
            //        station = station.id,
            //        creator = userId,
            //        id = startid
            //    };
            //    entities.Add(entity);
            //    startid++;
            //}
            //try
            //{
            //    _context.siger_project_machine_attribution.AddRange(entities);
            //    _context.SaveChanges();
            //    return new CommonImportResult(1, "1");
            //}
            //catch
            //{
            //    throw;
            //}
        }
        
        public List<siger_project_sparepart_ex> Getsparepart(int projectid)
        {
            var query = from c in _context.siger_project_sparepart
                        where c.projectid == projectid && c.status == (int)RowState.Valid && c.is_substitute == 1
                        select c;

            return query.ToList();
        }

        public List<ResponseGetSectionTree> GetSectionTreeChildrens(int pid, int parentid, int attribution = 0, string machineLevel = "")
        {
            var sectionList = _context.siger_project_level_section.Where(f => f.projectid == pid && f.status != 0).AsNoTracking().ToList();
            var attributionList = _context.siger_project_machine_attribution.Where(f => f.projectid == pid && f.status != 0).AsNoTracking().ToList();
            var machineList = _context.siger_project_machine.Where(f => f.projectid == pid && f.status != 0).AsNoTracking().ToList();
            if (!string.IsNullOrEmpty(machineLevel))
            {
                var machineLevelList = machineLevel.Split(',').ToList();
                machineList = machineList.Where(f => machineLevelList.Contains(f.machinelevel.ToStr())).ToList();
            }
            return GetSectionTreeData(sectionList, attributionList, machineList, parentid, attribution);
        }
        private List<ResponseGetSectionTree> GetMachineAttributionTreeData(int pid, int parentid, int station, int attribution = 0)
        {

            var response = new List<ResponseGetSectionTree>();
            var model = _context.siger_project_machine_attribution.Where(f => f.parent.Equals(parentid) && f.projectid.Equals(pid) && f.status == (int)RowState.Valid && f.station.Equals(station));
            if (attribution > 0)
            {
                model = model.Where(t => t.attribution == attribution);
            }

            if (!model.Any())
            {
                return response;
            }
            foreach (var item in model)
            {
                response.Add(new ResponseGetSectionTree
                {
                    disabled = false,
                    expand = false,
                    label = item.name,
                    value = attribution ==1 ? item.machine : item.id,
                    attrubution = item.attribution + 1,
                    children = GetMachineAttributionTreeData(pid, item.id, station, attribution)
                });
            }
            return response;
        }
        /// <summary>
        /// 获取设备产线结构树（速度改进版）
        /// </summary>
        /// <param name="list"></param>
        /// <param name="parentid"></param>
        /// <param name="station"></param>
        /// <param name="attribution"></param>
        /// <returns></returns>
        private List<ResponseGetSectionTree> GetMachineAttributionTreeData(List<siger_project_machine_attribution> list, int parentid, int station, int attribution = 0)
        {
            var response = new List<ResponseGetSectionTree>();
            var entities = list.Where(f => f.parent == parentid && f.status == (int)RowState.Valid && f.station == station);
            if (attribution > 0)
            {
                entities = entities.Where(t => t.attribution == attribution);
            }
            if (!entities.Any())
            {
                return response;
            }
            foreach (var item in entities)
            {
                response.Add(new ResponseGetSectionTree
                {
                    disabled = false,
                    expand = false,
                    label = item.name,
                    value = attribution == 1 ? item.machine : item.id,
                    attrubution = item.attribution + 1,
                    children = GetMachineAttributionTreeData(list, item.id, station, attribution),
                });
            }
            return response;
        }

        private List<ResponseGetSectionTree> GetMachineAttributionTreeData(List<siger_project_machine_attribution> list, List<siger_project_machine> machineList, int parentid, int station, int attribution = 0)
        {
            var response = new List<ResponseGetSectionTree>();
            var entities = list.Where(f => f.parent == parentid && f.status == (int)RowState.Valid && f.station == station);
            if (attribution > 0)
            {
                entities = entities.Where(t => t.attribution == attribution);
            }
            if (!entities.Any())
            {
                return response;
            }
            foreach (var item in entities)
            {
                if (!machineList.Any(f => f.id == item.machine))
                {
                    continue;
                }
                response.Add(new ResponseGetSectionTree
                {
                    disabled = false,
                    expand = false,
                    label = item.name,
                    value = attribution == 1 ? item.machine : item.id,
                    attrubution = item.attribution + 1,
                    children = GetMachineAttributionTreeData(list, machineList, item.id, station, attribution),
                    machinelevel = machineList.FirstOrDefault(f => f.id == item.machine)?.machinelevel ?? 0,
                    machineid = item.machine
                });
            }
            return response;
        }

        /// <summary>
        /// 获取产线结构树（速度改进版）
        /// </summary>
        /// <param name="sectionList"></param>
        /// <param name="attributionList"></param>
        /// <param name="parentid"></param>
        /// <param name="attribution"></param>
        /// <param name="machineList"></param>
        /// <returns></returns>
        public List<ResponseGetSectionTree> GetSectionTreeData(List<siger_project_level_section> sectionList, List<siger_project_machine_attribution> attributionList, List<siger_project_machine> machineList, int parentid, int attribution = 0)
        {
            var response = new List<ResponseGetSectionTree>();
            var model = sectionList.Where(f => f.parentid == parentid && f.status == (int)RowState.Valid);
            if (!model.Any())
            {
                return GetMachineAttributionTreeData(attributionList, machineList, 0, parentid, attribution);
            }
            foreach (var item in model)
            {
                var data = new ResponseGetSectionTree
                {
                    disabled = true,
                    expand = true,
                    label = item.title,
                    value = item.id,
                    levelid = item.levelid
                };
                var isAny = sectionList.Any(f => f.parentid == item.id && f.status == (int)RowState.Valid);
                if (!isAny)
                {
                    var lastLevel = sectionList.Where(f => f.status == (int)RowState.Valid).Max(m => m.id);
                    if (data.levelid == lastLevel)
                    {
                        data.attrubution = 1;
                    }
                }
                data.children = GetSectionTreeData(sectionList, attributionList, machineList, item.id, attribution);
                response.Add(data);
            }
            return response;
        }

        private IEnumerable<siger_project_level> GetSonLevels(int parentid, int projectid)
        {
            var query = from c in _context.siger_project_level
                        where c.parentid == parentid && c.projectid == projectid && c.status == (int)RowState.Valid
                        select c;

            return query.OrderBy(q => q.levelid).ToList().Concat(query.ToList().SelectMany(t => GetSonLevels(t.id, projectid)));
        }
    }
}

