using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Repository.Extensions;
using Siger.Middlelayer.Repository.Paged;
using Siger.Middlelayer.Repository.Response;
using Siger.Middlelayer.TpmRepository.Entities;
using Siger.Middlelayer.TpmRepository.Repositories.Interface;
using Siger.Middlelayer.TpmRepository.Request;
using Siger.Middlelayer.TpmRepository.Response;
using Siger.Middlelayer.Utility.ImportEntities;

namespace Siger.Middlelayer.TpmRepository.Repositories
{
    internal class SparepartRepository : TpmRepositoryBase<siger_project_sparepart>, ISparepartRepository
    {
        private readonly ApiTpmDbContext _context;
        public SparepartRepository(ApiTpmDbContext context) : base(context)
        {
            _context = context;
        }
        public IPagedCollectionResult<ResponseGetSparepart> GetPagedList(int machinetype1, int machinetype2, string keyword,
            string s_is_standard, string s_is_substitute, string s_report, int lastCheckValsparepart, IEnumerable<int> lastCheckVal,
            int charger, int projectId, int page, int pagesize, string key, string order, bool paged = true)
        {
            var query = _context.siger_project_sparepart.Where(q => q.projectid == projectId && q.status == (int)RowState.Valid);
            var querylist = from q in query
                            join ma1 in _context.siger_project_sparepart_machine on q.id equals ma1.sparepartid into machine1
                            from ma1 in machine1.DefaultIfEmpty()
                            join ty1 in _context.siger_project_sparepart_type on q.typeid equals ty1.id into type1
                            from ty1 in type1.DefaultIfEmpty()
                            select new ResponseGetSparepart
                            {
                                id = q.id,
                                brand = q.brand,
                                code = q.code,
                                description = q.description,
                                delivery_time = q.delivery_time,
                                image = q.image,
                                material = q.material,
                                max_sku = q.max_sku,
                                mini_sku = q.mini_sku,
                                price = q.price,
                                param = q.param,
                                purchase_status = q.purchase_status,
                                remark = q.remark,
                                sku = q.sku,
                                supplier = q.supplier,
                                is_standard = q.is_standard,
                                is_substitute = q.is_substitute,
                                is_common = q.is_common,
                                title = q.title,
                                unit = q.unit,
                                warehouse = q.warehouse,
                                sku_report_mid = q.sku_report_mid,
                                typeid = q.typeid,
                                repair_upperlimit = q.repair_upperlimit,
                                typeTitle = ty1.title,
                            };

            Expression<Func<ResponseGetSparepart, bool>> standardExpression = q => true;
            if (!string.IsNullOrWhiteSpace(s_is_standard))
            {
                var value = s_is_standard.ToInt();
                standardExpression = q => q.is_standard == value;
            }

            Expression<Func<ResponseGetSparepart, bool>> substituteExpression = q => true;
            if (!string.IsNullOrWhiteSpace(s_is_substitute))
            {
                var value = s_is_substitute.ToInt();
                substituteExpression = q => q.is_substitute == value;
            }

            Expression<Func<ResponseGetSparepart, bool>> stockExpression = q => true;
            if (!string.IsNullOrWhiteSpace(s_report))
            {
                var value = s_report.ToInt();
                if (value == 2) //报警
                {
                    stockExpression = q => q.sku < q.mini_sku;
                }
                else if (value == 1) //正常
                {
                    stockExpression = q => q.sku >= q.mini_sku;
                }
                else //采购中
                {
                    stockExpression = q => q.purchase_status == 1;
                }
            }

            Expression<Func<ResponseGetSparepart, bool>> sparepartExpression = q => true;
            if (lastCheckValsparepart != 0)
            {
                sparepartExpression = q => q.typeid == lastCheckValsparepart;
            }

            Expression<Func<ResponseGetSparepart, bool>> keywordExpression = q => true;
            if (!string.IsNullOrEmpty(keyword))
            {
                keywordExpression = q => (q.title.Contains(keyword) || q.code.Contains(keyword) || q.param.Contains(keyword) || q.brand.Contains(keyword) || q.warehouse.Contains(keyword));
            }

            Expression<Func<ResponseGetSparepart, bool>> chargerExpression = q => true;
            if (charger != 0)
            {
                chargerExpression = q => q.sku_report_mid == charger.ToString();
            }
            var expression = keywordExpression.And(sparepartExpression).And(stockExpression).And(substituteExpression)
                .And(standardExpression).And(chargerExpression);
            if (paged)
            {
                var totalCount = querylist.Count(expression);
                if (string.IsNullOrEmpty(key))
                {
                    var entities = querylist.OrderBy(o=>o.sort).Where(expression).Skip((page - 1) * pagesize).Take(pagesize).AsNoTracking()
                    .ToList();
                    return new PagedCollectionResult<ResponseGetSparepart>(entities, totalCount);
                }
                else
                {
                    var isDesc = order == "desc";
                    var entities = querylist.Where(expression).OrderBy(o => o.sort).OrderByPropertyName(key, isDesc).Skip((page - 1) * pagesize).Take(pagesize).AsNoTracking()
                    .ToList();
                    return new PagedCollectionResult<ResponseGetSparepart>(entities, totalCount);
                }
            }
            else
            {
                var entities = querylist.Where(expression).AsNoTracking().ToList();
                return new PagedCollectionResult<ResponseGetSparepart>(entities, 0);
            }
        }

        public CommonImportResult ImportSparepart(IEnumerable<SparepartListForImport> list, int projectId, int userId)
        {
            var errors = new List<string>();
            var rowIndex = 1;
            foreach (var sparepart in list)
            {
                rowIndex++;
                var entity = _context.siger_project_sparepart.FirstOrDefault(q => q.code == sparepart.Code && q.projectid == projectId
                                                                                  && q.status == (int)RowState.Valid);
                if (entity != null)
                {
                    errors.Add($"{rowIndex},{300055}");
                }
                //备件类型
                var type = _context.siger_project_sparepart_type.FirstOrDefault(q =>
                    q.title == sparepart.Type && q.projectid == projectId
                                              && q.status == (int)RowState.Valid);
                if (type == null)
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.SparepartTypeNotFound}");
                }

                var user = _context.siger_user.FirstOrDefault(t => (t.nickname == sparepart.UserCode || t.realname == sparepart.UserCode)
                                                                && t.status == (int)RowState.Valid);
                if (user == null)
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.UserNotFound}");
                }

                if (!string.IsNullOrWhiteSpace(sparepart.ApprovalUser))
                {
                    var approval = _context.siger_user.FirstOrDefault(t => (t.nickname == sparepart.ApprovalUser || t.realname == sparepart.ApprovalUser)
                                                                       && t.status == (int)RowState.Valid);
                    if (approval == null)
                    {
                        errors.Add($"{rowIndex},{(int)RequestEnum.UserNotFound}");
                    }
                }

                if (errors.Any())
                {
                    return new CommonImportResult(0, string.Join(";", errors));
                }
            }

            try
            {
                var sparepartEntities = list.ToList();
                for (int i = 0; i < sparepartEntities.Count; i++)
                {
                    var sparepart = sparepartEntities[i];
                    var type = _context.siger_project_sparepart_type.FirstOrDefault(q =>
                        q.title == sparepart.Type && q.projectid == projectId
                                                  && q.status == (int)RowState.Valid);

                    var user = _context.siger_user.FirstOrDefault(t => (t.nickname == sparepart.UserCode || t.realname == sparepart.UserCode)
                                                                && t.status == (int)RowState.Valid);
                    var mid = 0;
                    if (!string.IsNullOrWhiteSpace(sparepart.ApprovalUser))
                    {
                        var approvaluser = _context.siger_user.FirstOrDefault(t => (t.nickname == sparepart.ApprovalUser || t.realname == sparepart.ApprovalUser)
                                                                                   && t.status == (int)RowState.Valid);
                        if (approvaluser != null)
                        {
                            mid = approvaluser.id;
                        }
                    }

                    var entity = new siger_project_sparepart
                    {
                        code = sparepart.Code,
                        brand = sparepart.Brand,
                        create_mid = userId,
                        projectid = projectId,
                        create_ip = "0.0.0.1",
                        description = sparepart.Description,
                        delivery_time = sparepart.DeliveryDay.ToInt(),
                        material = sparepart.Material,
                        max_sku = sparepart.MaxSku,
                        mini_sku = sparepart.MinSku,
                        price = sparepart.Price.ToInt(),
                        param = sparepart.Param,
                        purchase_status = 0,
                        remark = sparepart.Remark,
                        sku = sparepart.Sku,
                        supplier = sparepart.Supplier,
                        is_standard = 1,
                        is_substitute = sparepart.IsExchange,
                        is_common = 1,
                        title = sparepart.Name,
                        time = UnixTimeHelper.GetNow(),
                        unit = sparepart.Unit,
                        warehouse = sparepart.Location,
                        typeid = type.id,
                        sku_report_mid = user.id.ToString(),
                        repair_upperlimit = sparepart.RepairUpperLimit.ToDouble(),
                        sku_limit = sparepart.MinOrder.ToInt(),
                        approvaluser_mid = mid
                    };
                    _context.siger_project_sparepart.Add(entity);
                }
                _context.SaveChanges();
                return new CommonImportResult(1, "1");
            }
            catch
            {
                throw;
            }
        }

        public IEnumerable<RepsonseGetSparepartList> GetSparepartListByMachineId(int machineId, int projectid)
        {
            var query = _context.siger_project_sparepart.Where(q => q.projectid == projectid && q.status == (int)RowState.Valid);
            var querylist = from q in query
                            join ma1 in _context.siger_project_sparepart_machine on q.id equals ma1.sparepartid into machine1
                            from ma1 in machine1.DefaultIfEmpty()
                            join ty1 in _context.siger_project_sparepart_type on q.typeid equals ty1.id into type1
                            from ty1 in type1.DefaultIfEmpty()
                            where q.sku > 0 //&& ma1.machineid == machineId
                            select new RepsonseGetSparepartList
                            {
                                sparepartid = q.id,
                                stitle = q.title,
                                sku = q.sku,
                                record_code = q.code,
                                price = q.price
                            };

            var queryGroupby = querylist.GroupBy(t => t.record_code).ToList();
            var res = new List<RepsonseGetSparepartList>();
            foreach (var item in queryGroupby)
            {
                foreach (var item1 in item)
                {
                    res.Add(item1);
                }
            }
            return res;
        }

        public IEnumerable<RepsonseGetSparepartList> GetReplaceSparepartsByMachineId(IEnumerable<int> spids, int projectid)
        {
            var querylist = from s in _context.siger_project_sparepart
                            where spids.Contains(s.id) && s.projectid == projectid && s.status == (int)RowState.Valid
                            select new RepsonseGetSparepartList
                            {
                                sparepartid = s.id,
                                stitle = s.title,
                                sku = s.sku,
                                record_code = s.code,
                                price = s.price,
                            };

            var queryGroupby = querylist.GroupBy(t => t.record_code).ToList();
            var res = new List<RepsonseGetSparepartList>();
            foreach (var item in queryGroupby)
            {
                foreach (var item1 in item)
                {
                    res.Add(item1);
                }
            }
            return res;
        }

        public IPagedCollectionResult<ResponseSparepartInfo> GetSparepartListInfo(RequestSparepartInfo condition, int pid)
        {
            //Expression<Func<ResponseSparepartInfo, bool>> funcName = f => true;
            //if (!string.IsNullOrEmpty(condition.code))
            //{
            //    funcName = f => f.title.Contains(condition.code);
            //}
            Expression<Func<ResponseSparepartInfo, bool>> funcCode = f => true;
            if (!string.IsNullOrEmpty(condition.code))
            {
                funcCode = f => f.code.Contains(condition.code) || f.title.Contains(condition.code);
            }
            Expression<Func<ResponseSparepartInfo, bool>> funcBrand = f => true;
            if (!string.IsNullOrEmpty(condition.brand))
            {
                funcBrand = f => f.brand.Equals(condition.brand);
            }
            Expression<Func<ResponseSparepartInfo, bool>> funcType = f => true;
            if (condition.typeid != 0)
            {
                funcType = f => f.type_id.Equals(condition.typeid);
            }
            Expression<Func<ResponseSparepartInfo, bool>> funcMid = f => true;
            if (condition.mid != 0)
            {
                funcMid = f => f.mid.Equals(condition.mid);
            }
            var cycle = _context.siger_project_procurement_process.FirstOrDefault(f => f.status == (int)RowState.Valid && f.projectid == pid)?.cycle ?? 0;
            var query = _context.siger_project_sparepart.Where(f => f.projectid.Equals(pid) && f.status == (int)RowState.Valid);
            var querylist = from q in query
                            join ty1 in _context.siger_project_sparepart_type on q.typeid equals ty1.id into type1
                            from ty1 in type1.DefaultIfEmpty()
                            select new ResponseSparepartInfo
                            {
                                brand = q.supplier,
                                code = q.code,
                                max_sku = q.max_sku,
                                mini_sku = q.mini_sku,
                                sku = q.sku,
                                sku_limit = q.sku_limit,
                                title = q.title,
                                type_id = q.typeid,
                                type = ty1.title,
                                mid = ty1.userId,
                                id = q.id,
                                last_order_time = q.order_time,
                                count = q.sku_limit//库存采购量
                            };
            var predicate = funcType.And(funcBrand).And(funcMid).And(funcCode).And(f => f.sku - f.last_month < f.mini_sku);
            var count = querylist.Count(predicate);
            var entities = querylist.Where(predicate).AsNoTracking().ToList();
            foreach (var item in entities)
            {
                item.mid_name = GetUserByMid(item.mid)?.name ?? "";
                var start = item.last_order_time == 0 ? UnixTimeHelper.GetNow() : item.last_order_time;
                var end = start + 86400 * cycle;
                item.last_week = GetSparepartCount(item.id, (int)start, (int)end, 2, pid);
                item.last_month = GetSparepartCount(item.id, UnixTimeHelper.GetMouthUnix(), UnixTimeHelper.GetMouthUnix() + 86400 * 30, 2, pid);
            }
            entities = entities.Skip((condition.page - 1) * condition.pagesize).Take(condition.pagesize).ToList();
            return new PagedCollectionResult<ResponseSparepartInfo>(entities, count);
        }

        private int GetSparepartCount(int sparepartId, int startTime, int endTime, int type, int pid)
        {
            //type=>1 出库 type=>2入库
            var count = _context.siger_project_sparepart_record.Where(q => q.sparepartid == sparepartId && q.type == type
                                                                                    && q.create_time >= startTime && q.create_time < endTime
                                                                                    && q.projectid == pid && q.status == (int)RowState.Valid)
                .Sum(q => q.number);

            return count;
        }

        public IEnumerable<RsponseAlarmSparepart> GetAlarmSpareparts(int projectId)
        {
            var spars = from q in _context.siger_project_sparepart
                join ty1 in _context.siger_project_sparepart_type on q.typeid equals ty1.id into type1
                from ty1 in type1.DefaultIfEmpty()
                where (q.sku < q.mini_sku || q.sku > q.max_sku) && q.projectid == projectId && q.status == (int) RowState.Valid
                select new RsponseAlarmSparepart
                {
                    id = q.id,
                    max_sku = q.max_sku,
                    mini_sku = q.mini_sku,
                    sku = q.sku,
                    title = q.title,
                    typename = ty1 == null ? "" : ty1.title,
                    warehouse = q.warehouse
                };
            return spars.AsEnumerable();
        }

        public bool InsertList(List<siger_project_sparepart> list)
        {
            InsertList(list);
            if (_context.SaveChanges()>0)
            {
                return true;
            }
            return false;
        }
    }
}
