using System;
using System.Collections.Generic;
using System.Linq;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.QmsRepository.Entities;
using Siger.Middlelayer.Repository;
using Siger.Middlelayer.Repository.Entities;
using Siger.Middlelayer.Repository.Response;

namespace Siger.Middlelayer.QmsRepository.Repositories
{
    internal abstract class QMSRepositoryBase<TEntity> : RepositoryBase<TEntity> where TEntity : QmsEntityBase
    {
        private readonly ApiQmsDbContext _context;
        protected QMSRepositoryBase(ApiQmsDbContext context) : base(context)
        {
            _context = context;
        }

        public string GetDictValue(int projectId, string cat, string dkey)
        {
            var accdict = new AccDictCost();
            var propertyInfo = accdict.GetType().GetField(cat);
            var dict = propertyInfo == null ?
                _context.siger_tr_dict.FirstOrDefault(f => f.cat == cat && f.dkey == dkey && f.status == (int)RowState.Valid) :
                _context.siger_tr_dict.FirstOrDefault(f => f.projectId == projectId && f.cat == cat && f.dkey == dkey && f.status == (int)RowState.Valid);
            if (dict == null)
                return "";
            return dict.dval;
        }

        public string GetLevelSectionTitleBySectionId(int sectionId, int projectId)
        {
            var query = _context.siger_project_level_section.FirstOrDefault(t => t.id == sectionId && t.status == (int)RowState.Valid && t.projectid == projectId);
            return query != null ? query.title : "";
        }

        public string GetProductNameByCode(string productCode, int projectId)
        {
            var query = _context.siger_project_product.FirstOrDefault(t => t.code == productCode && t.status == (int)RowState.Valid && t.projectid == projectId);
            return query != null ? query.name : "";
        }

        public SigerTrRoutingEventNo GetEventNoByResult(string result, int projectId)
        {
            return _context.siger_tr_routing_eventno.FirstOrDefault(t => t.projectid == projectId &&
                t.status == (int)RowState.Valid && t.Descr == result);
        }

        public SigerTrRoutingOutStation GetOutStationByEventNo(int eventno, int sectionId, int projectId)
        {
            return _context.siger_tr_routing_outstation.FirstOrDefault(t => t.projectid == projectId &&
                t.status == (int)RowState.Valid && t.EventNo == eventno && t.Station == sectionId);
        }

        public IEnumerable<ResponseIdName> GetSectionRouteList(string productcode, int sectionid, int projectid)
        {
            var query = from o in _context.siger_tr_routing_outstation
                        join i in _context.siger_tr_routing_instation on o.ResultStatus equals i.ResultStatus
                        join r in _context.siger_project_product_route on i.ProcessId equals r.id
                        where o.projectid == projectid && i.projectid == projectid && o.status == (int)RowState.Valid && i.status == (int)RowState.Valid
                        && i.ProductId == productcode && i.Station == sectionid && r.status == (int)RowState.Valid
                        select new ResponseIdName
                        {
                            id = r.id,
                            name = r.name
                        };
            return query;
        }

        public ResponseIdName GetMachineBySectionId(int sectionId, int projectId)
        {
            var query = _context.siger_project_machine_attribution.FirstOrDefault(q =>
                q.station == sectionId && q.status == (int)RowState.Valid && q.attribution == (int)MachineAttributionEnum.equipment);
            if (query == null)
            {
                return null;
            }

            var machine = _context.siger_project_machine.FirstOrDefault(q =>
                q.projectid == projectId && q.status == (int)RowState.Valid
                                         && q.id == query.machine);
            if (machine == null)
            {
                return null;
            }

            return new ResponseIdName { id = machine.id, name = machine.title };
        }

        public IEnumerable<ResponseSonMaterials> GetSonMaterialsByProductId(int projectId, int productId)
        {
            var list = new List<ResponseSonMaterials>();
            var structure = _context.siger_project_product_structure.FirstOrDefault(f => f.projectid == projectId
                && f.itemid == productId && f.itemtype == ComboxItem.Product);
            if (structure == null)
            {
                return list;
            }

            var query = from ps in _context.siger_project_product_structure
                        join m in _context.siger_tr_materials on ps.itemid equals m.id
                        where ps.projectid == projectId && ps.itemtype == ComboxItem.Material
                        && ps.status == (int)RowState.Valid
                        && ps.parent_id == structure.id
                        select new ResponseSonMaterials
                        {
                            structureid = ps.id,
                            id = m.id,
                            name = m.name,
                            pn = m.pn,
                            spec = m.spec
                        };            
            foreach (var q in query.ToList())
            {
                list.Add(q);
                var sons = GetSonMaterialsByParentId(q.structureid, projectId).ToList();
                list.AddRange(sons);
            }

            return list;
        }

        private IEnumerable<ResponseSonMaterials> GetSonMaterialsByParentId(int parentId, int projectId)
        {
            var querylist = _context.siger_project_product_structure.Where(t => t.parent_id == parentId &&
                t.status == (int)RowState.Valid && t.projectid == projectId && t.itemtype == Common.ModuleEnum.ComboxItem.Material);
            var query = from q in querylist
                        join m in _context.siger_tr_materials on q.itemid equals m.id
                        select new ResponseSonMaterials
                        {
                            structureid = q.id,
                            id = m.id,
                            name = m.name,
                            pn = m.pn,
                            spec = m.spec
                        };

            return query.ToList().Concat(query.ToList().SelectMany(t => GetSonMaterialsByParentId(t.structureid, projectId))).ToList();
        }

        public bool InsertKpiTaskList(SigerProjectKpiTasklist entity)
        {
            _context.siger_project_kpi_tasklist.Add(entity);
            return _context.SaveChanges() > 0;
        }

        public bool UpdateKpiTaskList(SigerProjectKpiTasklist item)
        {
            var entity = _context.siger_project_kpi_tasklist.FirstOrDefault(t =>
                t.Section == item.Section && t.ItemId == item.ItemId &&
                t.cycle == item.cycle && t.projectid == item.projectid && t.status == (int) RowState.Valid);
            if (entity != null)
            {
                entity.ActVal = item.ActVal;
                entity.TargetVal = item.TargetVal;
                entity.AddVal = item.AddVal;
                entity.cycle = item.cycle;
                entity.Result = item.Result;
                _context.siger_project_kpi_tasklist.Update(entity);
                return _context.SaveChanges() > 0;
            }

            return true;
        }

        public SigerProjectKpiItem GetKpiItem(string item, int projectid)
        {
            return _context.siger_project_kpi_item.FirstOrDefault(t => t.projectid == projectid && t.status == (int)RowState.Valid &&
                t.Item == item);
        }

        public int GetKpiTaskCount(int section, int itemid, string cycle, DateTime stime, DateTime etime, int projectid)
        {
            var item =
                _context.siger_project_kpi_tasklist.Where(t => t.Section == section &&
                                                                        t.ItemId == itemid && t.cycle == cycle &&
                                                                        t.Busidate <= etime &&
                                                                        t.Busidate >= stime &&
                                                                        t.projectid == projectid &&
                                                                        t.status == (int)RowState.Valid)
                .OrderByDescending(t => t.AddVal).FirstOrDefault();
            return item == null ? 0 : item.ActVal.ToStr().ToInt();
            
        }

        /// <summary>
        /// 工单生成器
        /// </summary>
        /// <param name="projectid"></param>
        /// <returns></returns>
        public string WorkOrderGenerator(int projectid)
        {
            var ret = string.Empty;
            var time = $"A{DateTime.Now.ToString("yyyyMMdd")}";
            var infomodel = _context.siger_andon_info.Where(f => f.projectid.Equals(projectid) && f.work_order.StartsWith(time));
            var no = 1;
            if (infomodel.Any())
            {
                var maxid = infomodel.Max(m => m.id);
                var max = _context.siger_andon_info.First(f => f.id == maxid).work_order;
                var maxparams = max.Split('_');
                if (maxparams.Length == 2)
                {
                    no = maxparams[1].ToInt() + 1;
                }
            }
            ret = $"{time}_{no}";
            return ret;
        }

        public siger_andon_expection_type GetAndonExceptionType(string exceptionType, int parentid, int projectid)
        {
            if(parentid > 0)
            {
                return _context.siger_andon_expection_type.FirstOrDefault(t => t.projectid == projectid &&
                    t.status == (int)RowState.Valid && t.name == exceptionType && t.parent == parentid);
            }
            else
            {
                return _context.siger_andon_expection_type.FirstOrDefault(t => t.projectid == projectid &&
                    t.status == (int)RowState.Valid && t.name == exceptionType);
            }
        }

        public bool InsertAndonInfo(siger_andon_info entity)
        {
            _context.siger_andon_info.Add(entity);
            return _context.SaveChanges() > 0;
        }

        public bool InsertAndonDetailInfo(siger_andon_info_detail entity)
        {
            _context.siger_andon_info_detail.Add(entity);
            return _context.SaveChanges() > 0;
        }
        public IEnumerable<siger_project_level_section> GetParentSelfLevelSections(int parentid, int projectid, IEnumerable<siger_project_level_section> levelSections)
        {
            var query = from c in levelSections
                        where c.id == parentid && c.status == (int)RowState.Valid
                        select c;

            return query.ToList().Concat(query.ToList().SelectMany(t => GetParentLevelSections(t.parentid, projectid, levelSections)));
        }
        public IEnumerable<siger_project_level_section> GetParentLevelSections(int id, int projectid, IEnumerable<siger_project_level_section> levelSections)
        {
            var query = from c in levelSections
                        where c.id == id && c.status == (int)RowState.Valid
                        select c;

            return query.ToList().Concat(query.ToList().SelectMany(t => GetParentLevelSections(t.parentid, projectid, levelSections)));
        }
    }
}
