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.ModuleEnum;
using Siger.Middlelayer.Repository.Extensions;
using Siger.Middlelayer.Repository.Paged;
using Siger.Middlelayer.TpmRepository.Entities;
using Siger.Middlelayer.TpmRepository.Repositories.Interface;
using Siger.Middlelayer.TpmRepository.Request;
using Siger.Middlelayer.TpmRepository.Response;

namespace Siger.Middlelayer.TpmRepository.Repositories
{
    internal class SparepartAuditRepository : TpmRepositoryBase<siger_project_sparepart_audit>, ISparepartAuditRepository
    {
        private readonly ApiTpmDbContext _context;
        public SparepartAuditRepository(ApiTpmDbContext context) : base(context)
        {
            _context = context;
        }

        public IPagedCollectionResult<GetPagedAuditSparepartList> GetAuditPagedList(int sectionId, List<int> machineIds, string code, int approvalstatus, int category, int projectId, int page, int pagesize)
        {
            var query = from q in _context.siger_project_sparepart_audit
                        join u in _context.siger_project_user on q.creator_mid equals u.mid into uu
                        from temp in uu.DefaultIfEmpty()
                        where q.project_id == projectId && q.status == (int)RowState.Valid
                        select new GetPagedAuditSparepartList
                        {
                            id = q.id,
                            code = q.repair_id.ToString(),
                            apply_state = q.approval_status,
                            apply_time = q.create_time.ToString(ParameterConstant.DateTimeFormat),
                            user_mid = q.creator_mid,
                            user_name = temp == null ? "" : temp.name,
                            category = q.category,
                            mode = q.mode
                        };

            Expression<Func<GetPagedAuditSparepartList, bool>> sectionIdExpression = q => true;
            if (sectionId > 0)
            {
                //sectionIdExpression = q => machineIds.Contains(q.machine_id);
            }

            Expression<Func<GetPagedAuditSparepartList, bool>> stateExpression = q => true;
            if (approvalstatus > 0)
            {
                stateExpression = q => q.apply_state == approvalstatus;
            }
            Expression<Func<GetPagedAuditSparepartList, bool>> categoryExpression = q => true;
            if (category == (int)SparepartAuditCategory.Prepare)
            {
                categoryExpression = q => (q.category == SparepartAuditCategory.Prepare || q.apply_state == 2);
            }
            else
            {
                categoryExpression = q => q.category == SparepartAuditCategory.Audit;
            }

            var predicate = sectionIdExpression.And(stateExpression).And(categoryExpression);

            var totalCount = query.Count(predicate);
            var entities = query.Where(predicate).OrderByDescending(q => q.id).AsNoTracking().ToList();
            //.Skip((page - 1) * pagesize).Take(pagesize)

            foreach (var entity in entities)
            {
                if (entity.mode == 1) //维修
                {
                    var repair = _context.siger_project_repair.FirstOrDefault(f => f.id.ToStr() == entity.code);
                    if (repair != null)
                    {
                        var stationid = _context.siger_project_machine_attribution.FirstOrDefault(f => f.machine == repair.machineid && f.status != 0 && f.projectid == projectId)?.station ?? 0;
                        entity.machine_id = repair.machineid;
                        var stations = GetParentSelfLevelSections(stationid, projectId).OrderBy(o => o.id);
                        if (stations.Count() > 1)
                        {
                            var lastStation = stations.Reverse().Take(2).Reverse();
                            entity.location = string.Join("-", lastStation.Select(s => s.title));
                        }
                        entity.faultmode = _context.siger_project_machine_fault.FirstOrDefault(f => f.id == repair.real_faultid)?.title ?? "";
                        entity.work_order = repair.work_order;
                    }
                }
                else if (entity.mode == 2) //维护
                {
                    var repair = _context.siger_project_plan_item.FirstOrDefault(f => f.id.ToStr() == entity.code);
                    if (repair != null)
                    {
                        var stationid = _context.siger_project_machine_attribution.FirstOrDefault(f => f.machine == repair.machineid && f.status != 0 && f.projectid == projectId)?.station ?? 0;
                        entity.machine_id = repair.machineid;
                        var stations = GetParentSelfLevelSections(stationid, projectId).OrderBy(o => o.id);
                        if (stations.Count() > 1)
                        {
                            var lastStation = stations.Reverse().Take(2).Reverse();
                            entity.location = string.Join("-", lastStation.Select(s => s.title));
                        }
                        entity.faultmode = repair.content;
                        entity.work_order = $"P{repair.id}";
                    }
                }
            }
            if (machineIds.Any())
            {
                entities = entities.Where(f => machineIds.Contains(f.machine_id)).ToList();
            }
            if (!string.IsNullOrWhiteSpace(code))
            {
                var order = code;
                if (code.ToUpper().StartsWith("P"))
                {
                    order = order.TrimStart('P');
                }
                entities = entities.Where(f => f.work_order.Contains(order)).ToList();
            }
            return new PagedCollectionResult<GetPagedAuditSparepartList>(entities.Skip((page - 1) * pagesize).Take(pagesize).ToList(), entities.Count());
        }

        public IPagedCollectionResult<GetPagedAuditSparepartList> GetReplcaePagedList(int sectionId, List<int> machineIds, string code, int approvalstatus, int projectId, int page, int pagesize)
        {
            var query = from q in _context.siger_project_sparepart_audit_detail
                        join a in _context.siger_project_sparepart_audit on q.audit_id equals a.id
                        join r in _context.siger_project_repair on a.repair_id equals r.id
                        join f in _context.siger_project_machine_fault on r.real_faultid equals f.id
                        join m in _context.siger_project_machine on r.machineid equals m.id
                        join u in _context.siger_project_user on a.creator_mid equals u.mid into uu
                        from temp in uu.DefaultIfEmpty()
                        where a.project_id == projectId && q.status == (int)RowState.Valid
                              && q.replace_category >= 0
                        select new GetPagedAuditSparepartList
                        {
                            id = q.id,
                            machine_id = r.machineid,
                            location = m.title,
                            code = r.id.ToString(),
                            apply_state = q.replace_category,
                            apply_time = a.create_time.ToString(ParameterConstant.DateTimeFormat),
                            user_mid = a.creator_mid,
                            user_name = temp == null ? "" : temp.name,
                            faultmode = f.title,
                            qrcode = q.qrcode
                        };

            Expression<Func<GetPagedAuditSparepartList, bool>> sectionIdExpression = q => true;
            if (sectionId > 0)
            {
                sectionIdExpression = q => machineIds.Contains(q.machine_id);
            }
            Expression<Func<GetPagedAuditSparepartList, bool>> idExpression = q => true;
            if (!string.IsNullOrWhiteSpace(code))
            {
                idExpression = q => q.code.Contains(code);
            }
            Expression<Func<GetPagedAuditSparepartList, bool>> stateExpression = q => true;
            if (approvalstatus > 0)
            {
                if (approvalstatus == 1) //未替换
                {
                    stateExpression = q => q.apply_state == 0;
                }
                else if (approvalstatus == 2) //已替换
                {
                    stateExpression = q => q.apply_state > 0;
                }
            }

            var predicate = sectionIdExpression.And(idExpression).And(stateExpression);

            var totalCount = query.Count(predicate);
            var entities = query.Where(predicate).OrderByDescending(q => q.apply_time).Skip((page - 1) * pagesize).Take(pagesize).AsNoTracking().ToList();

            return new PagedCollectionResult<GetPagedAuditSparepartList>(entities, totalCount);
        }

        public IPagedCollectionResult<GetPagedAuditSparepartList> GetRepairPagedList(string code, string sparepart, int repair_category, int status, int projectId, int page,
            int pagesize, int toexcel)
        {
            var query = from q in _context.siger_project_sparepart_audit_detail
                        join c in _context.siger_project_sparepart_code on new { spid = q.sparepart_id, code = q.qrcode } equals new { spid = c.sparepart_id, code = c.sparepart_code }
                        join a in _context.siger_project_sparepart_audit on q.audit_id equals a.id
                        join sp in _context.siger_project_sparepart on q.sparepart_id equals sp.id
                        join r in _context.siger_project_repair on a.repair_id equals r.id
                        join f in _context.siger_project_machine_fault on r.real_faultid equals f.id
                        join m in _context.siger_project_machine on r.machineid equals m.id
                        join u in _context.siger_project_user on a.creator_mid equals u.mid into uu
                        from temp in uu.DefaultIfEmpty()
                        where a.project_id == projectId && q.status == (int)RowState.Valid
                              && q.replace_category >= 2
                        select new GetPagedAuditSparepartList
                        {
                            id = q.id,
                            machine_id = r.machineid,
                            location = m.title,
                            code = r.id.ToString(),
                            apply_state = q.replace_category,
                            apply_time = a.create_time.ToString(ParameterConstant.DateTimeFormat),
                            user_mid = a.creator_mid,
                            user_name = temp == null ? "" : temp.name,
                            faultmode = f.title,
                            qrcode = q.qrcode,
                            repair_status = q.repair_status,
                            spname = sp.title,
                            spcode = sp.code,
                            repair_count = c.repair_count,
                            repair_upper = sp.repair_upperlimit.HasValue ? sp.repair_upperlimit.Value : 0
                        };

            Expression<Func<GetPagedAuditSparepartList, bool>> idExpression = q => true;
            if (!string.IsNullOrWhiteSpace(code))
            {
                idExpression = q => q.code.Contains(code);
            }
            Expression<Func<GetPagedAuditSparepartList, bool>> sparepartExpression = q => true;
            if (!string.IsNullOrWhiteSpace(sparepart))
            {
                sparepartExpression = q => (q.spname.Contains(sparepart) || q.spcode.Contains(sparepart));
            }
            Expression<Func<GetPagedAuditSparepartList, bool>> stateExpression = q => true;
            if (repair_category > 0)
            {
                stateExpression = q => q.apply_state == repair_category;
            }
            Expression<Func<GetPagedAuditSparepartList, bool>> statusExpression = q => true;
            if (status > 0)
            {
                stateExpression = q => q.repair_status == status;
            }

            var predicate = sparepartExpression.And(idExpression).And(stateExpression).And(statusExpression);

            if (toexcel == 0)
            {
                var totalCount = query.Count(predicate);
                var entities = query.Where(predicate).OrderByDescending(q => q.apply_time).Skip((page - 1) * pagesize).Take(pagesize).AsNoTracking().ToList();

                return new PagedCollectionResult<GetPagedAuditSparepartList>(entities, totalCount);
            }
            else
            {
                var entities = query.Where(predicate).OrderByDescending(q => q.apply_time).AsNoTracking().ToList();
                return new PagedCollectionResult<GetPagedAuditSparepartList>(entities, 0);
            }
        }

        public IEnumerable<GetAuditSparepartList> GetAuditSparepartList(int auditId)
        {
            var query = from d in _context.siger_project_sparepart_audit_detail
                        join sp in _context.siger_project_sparepart on d.sparepart_id equals sp.id
                        where d.status == (int)RowState.Valid && d.audit_id == auditId
                        select new GetAuditSparepartList
                        {
                            id = d.id,
                            apply_count = d.apply_count,
                            code = sp.code,
                            name = sp.title,
                            sku = sp.sku,
                            qrcode = d.qrcode,
                            sparepart_type = sp.is_substitute,
                            location = sp.warehouse
                        };
            return query.AsEnumerable();
        }

        public int AddPrepareSpareparts(RequestSubmitSpareparts request, int project_id, int user_id, bool need_audit)
        {
            var audit = new siger_project_sparepart_audit
            {
                repair_id = request.repair_id,
                approval_status = need_audit ? 1 : 2, //不需要审核时，审批状态为备货中
                category = need_audit ? SparepartAuditCategory.Audit : SparepartAuditCategory.Prepare,
                project_id = project_id,
                creator_mid = user_id,
                create_time = DateTime.Now,
                mode = 1
            };
            _context.siger_project_sparepart_audit.Add(audit);
            if (_context.SaveChanges() < 0)
            {
                return 0;
            }
            foreach (var info in request.spareparts)
            {
                var detail = new siger_project_sparepart_audit_detail
                {
                    audit_id = audit.id,
                    apply_count = info.apply_count,
                    sparepart_id = info.sparepart_id,
                };
                _context.siger_project_sparepart_audit_detail.Add(detail);
            }

            return _context.SaveChanges();
        }

        public int AddPlanPrepareSpareparts(Dictionary<int, int> sps, int planitemId, int project_id, int user_id, bool need_audit)
        {
            var audit = new siger_project_sparepart_audit
            {
                repair_id = planitemId,
                approval_status = need_audit ? 1 : 2, //不需要审核时，审批状态为备货中
                category = need_audit ? SparepartAuditCategory.Audit : SparepartAuditCategory.Prepare,
                project_id = project_id,
                creator_mid = user_id,
                create_time = DateTime.Now,
                mode = 2
            };
            _context.siger_project_sparepart_audit.Add(audit);
            if (_context.SaveChanges() < 0)
            {
                return 0;
            }
            foreach (var info in sps)
            {
                var detail = new siger_project_sparepart_audit_detail
                {
                    audit_id = audit.id,
                    apply_count = info.Value,
                    sparepart_id = info.Key,
                };
                _context.siger_project_sparepart_audit_detail.Add(detail);
            }

            return 1;
        }

        public int AddReplcaeSpareparts(RequestSubmitPrepare request, int userid, int auditId)
        {
            var auditdetails = _context.siger_project_sparepart_audit_detail.Where(q => q.audit_id == auditId
                                             && q.status == (int)RowState.Valid).ToList();
            if (auditdetails.Any())
            {
                foreach (var detail in auditdetails)
                {
                    var sp = request.spareparts.FirstOrDefault(q => q.sparepartid == detail.sparepart_id);
                    if (sp == null)
                    {
                        continue;
                    }

                    detail.apply_count = sp.apply_count;
                    detail.qrcode = sp.qrcode;
                    detail.update_time = DateTime.Now;
                    detail.updator_mid = userid;
                    //添加替换
                    if (!string.IsNullOrWhiteSpace(sp.qrcode))
                    {
                        detail.replace_category = 0;
                    }
                    _context.siger_project_sparepart_audit_detail.Update(detail);

                    //扣库存
                    var spart = _context.siger_project_sparepart.FirstOrDefault(q => q.id == detail.sparepart_id);
                    if (spart != null)
                    {
                        spart.sku -= sp.apply_count;
                        _context.siger_project_sparepart.Update(spart);
                    }
                }
            }

            return _context.SaveChanges();
        }

        public siger_project_sparepart_audit_detail GetAuditDetail(int id)
        {
            return _context.siger_project_sparepart_audit_detail.Find(id);
        }

        public int UpdateAuditDetail(RequestReplaceSparepart request, int userId)
        {
            foreach (var audit in request.replace_spareparts)
            {
                var detail = GetAuditDetail(audit.id);
                if (detail != null)
                {
                    //达到维修上限的，自动报废
                    var sp = _context.siger_project_sparepart.Find(detail.sparepart_id);
                    if (sp?.repair_upperlimit == null)
                    {
                        continue;
                    }

                    var code = _context.siger_project_sparepart_code.FirstOrDefault(q =>
                        q.sparepart_code == sp.code && q.sparepart_id == sp.id
                                                    && q.status == (int)RowState.Valid);
                    if (sp.repair_upperlimit >= code?.repair_count)
                    {
                        detail.replace_category = 1; //报废
                    }
                    else
                    {
                        detail.replace_category = audit.replace_state;
                    }
                    detail.update_time = DateTime.Now;
                    detail.updator_mid = userId;
                    _context.siger_project_sparepart_audit_detail.Update(detail);
                }
            }

            return _context.SaveChanges();
        }

        public int UpdateAuditDetailById(string ids)
        {
            var aids = ids.Split(',');
            foreach (var aid in aids)
            {
                var detail = GetAuditDetail(aid.ToInt());
                if (detail != null)
                {
                    detail.repair_status = 1;
                    _context.siger_project_sparepart_audit_detail.Update(detail);

                    //加库存
                    var sps = _context.siger_project_sparepart.Find(detail.sparepart_id);
                    if (sps != null)
                    {
                        sps.sku += 1;
                        _context.siger_project_sparepart.Update(sps);
                    }
                }
            }

            return _context.SaveChanges();
        }
    }
}
