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

namespace Siger.Middlelayer.EsopRepository.Repositories
{
    internal class EsopDocumentCreateRepository : EsopRepositoryBase<siger_project_esop_document>, IEsopDocumentCreateRepository
    {
        private readonly ApiEsopDbContext _context;
        public EsopDocumentCreateRepository(ApiEsopDbContext context) : base(context)
        {
            _context = context;
        }

        public IPagedCollectionResult<ResponseGetEsopDocumentList> GetDocumentPagedList(string starttime, string endtime, int status, int type,
            string keyword, int project_id, int user_id, int page, int pagesize)
        {
            var query = from q in _context.siger_project_esop_document
                        join ty in _context.siger_project_esop_document_set on q.type_id equals ty.id
                        join process in _context.siger_project_esop_process on ty.process_id equals process.id into proc
                        from proces in proc.DefaultIfEmpty()
                        join his in _context.siger_project_esop_document_history on q.id equals his.document_id
                        join u in _context.siger_project_user on his.updator_mid equals u.mid
                        join p in _context.siger_project_product on q.product_id equals p.id into pp
                        from pro in pp.DefaultIfEmpty()
                        join m in _context.siger_project_machine on q.machine_id equals m.id into mm
                        from mach in mm.DefaultIfEmpty()
                        join s in _context.siger_project_section on q.section_id equals s.id into ss
                        from ls in ss.DefaultIfEmpty()
                        where q.project_id == project_id && q.status == (int)RowState.Valid && his.is_valid == 1 orderby q.create_time descending
                        select new ResponseGetEsopDocumentList
                        {
                            id = q.id,
                            name = q.name,
                            type_id = q.type_id,
                            type_name = ty.name,
                            process_id = proces != null ? proces.id : 0,
                            process_name = proces != null ? proces.name : "",
                            approval_status = Convert.ToInt32(q.approval_status),
                            time = his.update_time,
                            create_time = his.update_time.ToString("yyyy-MM-dd"),
                            creator_mid = his.updator_mid,
                            creator_name = u.name,
                            file_name = his.file_name ?? "",
                            file_url = his.file_url,
                            machine_id = mach != null ? mach.id : 0,
                            machine_name = mach != null ? mach.title : "",
                            product_id = pro != null ? pro.id : 0,
                            product_name = pro != null ? pro.name : "",
                            version = "V" + his.version,
                            section_id = q.section_id,
                            section_name = ls != null ? ls.title : "",
                            remark = q.remark,
                            default_display= his.default_display,
                            version_name = his.version_name,
                            usergroups=ty.usergroup_ids.Split(',').ToList()
                        };

            Expression<Func<ResponseGetEsopDocumentList, bool>> startExpression = q => true;
            if (!string.IsNullOrWhiteSpace(starttime))
            {
                startExpression = q => q.time >= DateTime.Parse(starttime) && q.time <= DateTime.Parse(endtime).AddDays(1).AddSeconds(-1);
            }
            Expression<Func<ResponseGetEsopDocumentList, bool>> statusExpression = q => true;
            if (status > 0)
            {
                statusExpression = q => q.approval_status == status;
            }
            Expression<Func<ResponseGetEsopDocumentList, bool>> typeExpression = q => true;
            if (type > 0)
            {
                typeExpression = q => q.type_id == type;
            }
            Expression<Func<ResponseGetEsopDocumentList, bool>> keywordExpression = q => true;
            if (!string.IsNullOrWhiteSpace(keyword))
            {
                keywordExpression = q => (q.name.Contains(keyword) || q.product_name.Contains(keyword) || q.file_name.Contains(keyword));
            }

            //var entities = query.Where(predicate).AsNoTracking().ToList();
            //var responses = new List<ResponseGetEsopDocumentList>();

            var userinfo = _context.siger_project_user.FirstOrDefault(q => q.mid == user_id && q.status == (int)RowState.Valid);
            Expression<Func<ResponseGetEsopDocumentList, bool>> userGroupExpression = q => true;
            if (userinfo!=null)
            {
                //不是管理员
                if (!string.IsNullOrEmpty(userinfo.usergroupid))
                {
                    userGroupExpression = f => f.usergroups.Contains(userinfo.usergroupid);
                }
            }
            var predicate = startExpression.And(statusExpression).And(typeExpression).And(keywordExpression).And(userGroupExpression);
            //if (userinfo != null && userinfo.type == (int)UserType.User)
            //{
            //    //创建人或者审核人
            //    foreach (var entity in entities)
            //    {
            //        if (entity.creator_mid == user_id || GetApprovalUsers(entity.process_id).Contains(user_id))
            //        {
            //            responses.Add(entity);
            //        }
            //    }
            //}
            //else //管理员
            //{
            //    foreach (var entity in entities)
            //    {
            //        responses.Add(entity);
            //    }
            //}

            var totalCount = query.Where(predicate).Count();
            var result = query.Where(predicate).Skip((page - 1) * pagesize).Take(pagesize);
            return new PagedCollectionResult<ResponseGetEsopDocumentList>(result, totalCount);
        }

        public IPagedCollectionResult<ResponseGetEsopDocumentList> GetDocumentAuditPagedList(int user_id, int project_id, int page, int pagesize)
        {
            var query = from q in _context.siger_project_esop_document
                        join ty in _context.siger_project_esop_document_set on q.type_id equals ty.id
                        join process in _context.siger_project_esop_process on ty.process_id equals process.id
                        join his in _context.siger_project_esop_document_history on q.id equals his.document_id
                        join u in _context.siger_project_user on his.updator_mid equals u.mid
                        join p in _context.siger_project_product on q.product_id equals p.id into pp
                        from pro in pp.DefaultIfEmpty()
                        join m in _context.siger_project_machine on q.machine_id equals m.id into mm
                        from mach in mm.DefaultIfEmpty()
                        join s in _context.siger_project_section on q.section_id equals s.id into ss
                        from ls in ss.DefaultIfEmpty()
                        where q.project_id == project_id && q.status == (int)RowState.Valid && his.is_valid == 1 
                        //&& mach.category == (int)MachineCategory.NC 
                        && q.approval_status!=DocumentApprovalStatus.ApprovalPass orderby q.create_time descending
                        select new ResponseGetEsopDocumentList
                        {
                            id = q.id,
                            name = q.name,
                            type_id = q.type_id,
                            type_name = ty.name,
                            process_id = process.id,
                            process_name = process.name,
                            approval_status = (int)q.approval_status,
                            time = his.update_time,
                            create_time = his.update_time.ToString("yyyy-MM-dd"),
                            creator_mid = his.updator_mid,
                            creator_name = u.name,
                            file_name = his.file_name ?? "",
                            file_url = his.file_url ?? "",
                            machine_id = mach != null ? mach.id : 0,
                            machine_name = mach != null ? mach.title : "",
                            product_id = pro != null ? pro.id : 0,
                            product_name = pro != null ? pro.name : "",
                            version = "V" + his.version,
                            section_id = q.section_id,
                            section_name = ls != null ? ls.title : "",
                            remark = q.remark,
                            usergroups = ty.usergroup_ids.Split(',').ToList()
                        };


            //var entities = query.AsNoTracking().ToList();
            //var responses = new List<ResponseGetEsopDocumentList>();

            //var userinfo = _context.siger_user.FirstOrDefault(q => q.id == user_id && q.status == (int)RowState.Valid);
            //if (userinfo != null && userinfo.type == (int)UserType.User)
            //{
            //    //创建人或者审核人
            //    foreach (var entity in entities)
            //    {
            //        if (entity.creator_mid == user_id || GetApprovalUsers(entity.process_id).Contains(user_id))
            //        {
            //            responses.Add(entity);
            //        }
            //    }
            //}
            //else //管理员
            //{
            //    foreach (var entity in entities)
            //    {
            //        responses.Add(entity);
            //    }
            //}
            var userinfo = _context.siger_project_user.FirstOrDefault(q => q.mid == user_id && q.status == (int)RowState.Valid);
            Expression<Func<ResponseGetEsopDocumentList, bool>> userGroupExpression = q => true;
            if (userinfo != null)
            {
                //不是管理员
                if (!string.IsNullOrEmpty(userinfo.usergroupid))
                {
                    userGroupExpression = f => f.usergroups.Contains(userinfo.usergroupid);
                }
            }
            var totalCount = query.Where(userGroupExpression).Count();
            var result = query.Where(userGroupExpression).Skip((page - 1) * pagesize).Take(pagesize).ToList();
            return new PagedCollectionResult<ResponseGetEsopDocumentList>(result, totalCount);
        }

        public bool AddDocument(RequestAddDocumentCreate request, int projectId, int userId)
        {
            var entity = new siger_project_esop_document
            {
                project_id = projectId,
                create_time = DateTime.Now,
                creator_mid = userId,
                name = request.name,
                type_id = request.type_id,
                machine_id = request.machine_id,
                section_id = request.section_id,
                product_id = request.product_id,
                remark = request.remark != null ? request.remark : "",

                approval_status = DocumentApprovalStatus.UnApproval
            };
            //无需审批
            var type = _context.siger_project_esop_document_set.FirstOrDefault(q => q.id == request.type_id && q.project_id == projectId && q.status == (int)RowState.Valid);
            if (type == null || type.process_id == 0)
            {
                entity.approval_status = DocumentApprovalStatus.ApprovalPass;
            }
            _context.siger_project_esop_document.Add(entity);
            if (_context.SaveChanges() < 0)
            {
                return false;
            }

            var his = new siger_project_esop_document_history
            {
                document_id = entity.id,
                file_name = request.file_name,
                file_url = request.file_url,
                is_valid = 1,
                update_time = DateTime.Now,
                updator_mid = userId,
                default_display = request.default_display,
                version = 1,
                version_name=request.name
            };

            _context.siger_project_esop_document_history.Add(his);
            if (_context.SaveChanges() < 0)
            {
                return false;
            }

            return true;
        }
    
        public bool AddApprovalHistory(RequestApprovalDocument request, int userId)
        {
            var entity = new siger_project_esop_document_approval
            {
                document_id = request.id,
                approval_result = request.ispass,
                create_time = DateTime.Now,
                creator_mid = userId,
            };
            _context.siger_project_esop_document_approval.Add(entity);
            if (_context.SaveChanges() < 0)
            {
                return false;
            }

            return true;
        }

        public EsopApprovalResult ApprovalDocument(IEnumerable<ResponseGetProcessFlow> flows, int document_id, int process_id, int ispass, int user_id)
        {
            //先检查审批的步骤号
            var currentStepNumber = GetCurrentStepNumber(document_id, process_id);

            //当前审批步骤
            var currentStep = _context.siger_project_esop_process_set.FirstOrDefault(q => q.process_id == process_id && q.status == (int)RowState.Valid
                                                                                          && q.step_number == currentStepNumber);
            if (currentStep == null)
            {
                return EsopApprovalResult.CurrentApprovalStepNotFound;
            }

            var approvalUsers = GetApprovalUsers(currentStep);
            if (!approvalUsers.approval_userids.Contains(user_id))
            {
                return EsopApprovalResult.HaveNoRight;
            }

            var approvalList = _context.siger_project_esop_document_approval.Where(q => q.document_id == document_id && q.status == (int)RowState.Valid).OrderByDescending(m => m.step_number).ThenByDescending(d=>d.id);
            //var hasApproval = approvalList.FirstOrDefault(q => q.creator_mid == user_id && q.document_id == document_id && q.step_number == currentStepNumber);

            //if (hasApproval != null)
            //{
            //    if (hasApproval.approval_result != 0)
            //    {
            //        return EsopApprovalResult.CannotApprovalAgain;
            //    }
            //}
            var document = _context.siger_project_esop_document.FirstOrDefault(f => f.id == document_id);
            if (document.approval_status== DocumentApprovalStatus.ApprovalPass)
            {
                return EsopApprovalResult.CannotApprovalAgain;
            }
            if (ispass == 0) // 不通过
            {
                //修改文档状态
                UpdateDocumentStatus(document_id, DocumentApprovalStatus.ApprovalDeny);
                //添加审批记录
                AddApprovalHistory(document_id, ispass, user_id, currentStepNumber);

                return EsopApprovalResult.Success;
            }

            UpdateDocumentStatus(document_id, DocumentApprovalStatus.InProcess);

            if (currentStep.approval_type == 1) //会审，大家全部审核过
            {
                //计算步骤号
                var hasApprovalUserIds = approvalList.Where(q => q.step_number == currentStepNumber).Select(q => q.creator_mid).Distinct().Count();
                //if (hasApprovalUserIds == approvalUsers.approval_userids.Count - 1)
                //{
                //    //添加审批记录
                //    AddApprovalHistory(document_id, ispass, user_id, currentStepNumber);

                //    //判断流程是否结束
                //    FinishApproval(document_id, process_id, currentStepNumber);
                //}
                //else
                //{
                //    AddApprovalHistory(document_id, ispass, user_id, currentStepNumber);
                //}
                //添加审批记录
                AddApprovalHistory(document_id, ispass, user_id, currentStepNumber);
                FinishApproval(document_id, process_id, currentStepNumber);
            }
            else //任意
            {
                //添加审批记录
                AddApprovalHistory(document_id, ispass, user_id, currentStepNumber);

                FinishApproval(document_id, process_id, currentStepNumber);
            }

            return EsopApprovalResult.Success;
        }

        private int GetCurrentStepNumber(int document_id, int process_id)
        {
            //先检查审批的步骤号
            var currentStepNumber = 1;
            var approvalList = _context.siger_project_esop_document_approval.Where(q => q.document_id == document_id && q.status == (int)RowState.Valid).OrderByDescending(m => m.step_number).ThenBy(d=>d.id);
            if (approvalList.Any())
            {
                var lastApproval = approvalList.Last();
                if (lastApproval.approval_result==0)
                {
                    return lastApproval.step_number;
                }    
                currentStepNumber =lastApproval.step_number;
            }

            //当前审批步骤
            var currentStep = _context.siger_project_esop_process_set.FirstOrDefault(q => q.process_id == process_id && q.status == (int)RowState.Valid
                                                                                                                     && q.step_number == currentStepNumber);
            if (currentStep == null)
            {
                return 0;
            }

            //审批类型为任意的时候，到下一步
            if (currentStep.approval_type == 1) //会审
            {
                var approvalUsers = GetApprovalUsers(currentStep);

                var hasApprovalUserIds = approvalList.Where(q => q.step_number == currentStepNumber).Select(q => q.creator_mid).Count();
                if (hasApprovalUserIds == approvalUsers.approval_userids.Count)
                {
                    return currentStepNumber + 1;
                }
            }
            else //任意
            {
                var hasApprovalUser = approvalList.FirstOrDefault(q => q.step_number == currentStepNumber);
                if (hasApprovalUser != null)
                {
                    return currentStepNumber + 1;
                }
            }

            return currentStepNumber;
        }

        private void AddApprovalHistory(int document_id, int ispass, int user_id, int step_number)
        {
            var entity = new siger_project_esop_document_approval
            {
                document_id = document_id,
                approval_result = ispass,
                create_time = DateTime.Now,
                creator_mid = user_id,
                step_number = step_number
            };
            _context.siger_project_esop_document_approval.Add(entity);
            _context.SaveChanges();
        }

        private void FinishApproval(int document_id, int process_id, int currentStepNumber)
        {
            //判断流程是否结束
            var lastStepNumber = _context.siger_project_esop_process_set.Where(q => q.process_id == process_id && q.status == (int)RowState.Valid)
                .Max(m => m.step_number);
            if (currentStepNumber == lastStepNumber) //流程结束
            {
                UpdateDocumentStatus(document_id, DocumentApprovalStatus.ApprovalPass);
            }
        }

        private void UpdateDocumentStatus(int id, DocumentApprovalStatus status)
        {
            var document = _context.siger_project_esop_document.FirstOrDefault(q => q.id == id && q.status == (int)RowState.Valid);
            if (document != null && document.approval_status != status)
            {
                document.approval_status = status;
                document.approval_time = DateTime.Now;
                _context.siger_project_esop_document.Update(document);
                _context.SaveChanges();
            }
        }

        private IEnumerable<int> GetApprovalUsers(int process_id)
        {
            var result = new List<int>();

            var processs = _context.siger_project_esop_process_set.Where(q =>
                q.process_id == process_id && q.status == (int)RowState.Valid);
            foreach (var set in processs.ToList())
            {
                var userIds = GetApprovalUsers(set);
                foreach (var userId in userIds.approval_userids)
                {
                    if (!result.Contains(userId))
                    {
                        result.Add(userId);
                    }
                }
            }

            return result;
        }

        private ProcessFlow GetApprovalUsers(siger_project_esop_process_set step)
        {
            var response = new ProcessFlow
            {
                process_id = step.process_id,
                step_number = step.step_number
            };
            var ids = step.approval_usergroupid.Split(',');
            if (ids?.Length > 0)
            {
                foreach (var id in ids)
                {
                    if (step.approval_usertype == 1) //岗位
                    {
                        var users = _context.siger_project_user.Where(q => q.usergroupid == id && q.status == (int)RowState.Valid);
                        foreach (var projectUser in users)
                        {
                            response.approval_userids.Add(projectUser.mid);
                        }
                    }
                    else //人员
                    {
                        response.approval_userids.Add(id.ToInt());
                    }
                }
            }

            return response;
        }

        public IEnumerable<ResponseGetApprovalList> GetApprovalLists(int doc_id)
        {
            var query = from q in _context.siger_project_esop_document_approval
                        join u in _context.siger_project_user on q.creator_mid equals u.mid
                        where q.document_id == doc_id
                        select new ResponseGetApprovalList
                        {
                            id = q.id,
                            creator_name = u.name,
                            datetime = q.create_time.ToString("yyyy-MM-dd"),
                            result = q.approval_result
                        };
            return query.AsEnumerable();
        }

        public IEnumerable<ResponseGetUnBindDocument> GetDocuments(IEnumerable<int> document_ids)
        {
            var query = from q in _context.siger_project_esop_document
                        join t in _context.siger_project_esop_document_set on q.type_id equals t.id
                        join h in _context.siger_project_esop_document_history on q.id equals h.document_id
                        where document_ids.Contains(q.id) && h.is_valid == 1
                        select new ResponseGetUnBindDocument
                        {
                            document_id = q.id,
                            document_name = q.name,
                            type_name = t.name,
                            version = "V" + h.version
                        };

            return query.AsEnumerable();
        }

        public IEnumerable<ResponseGetDocumentByType> GetDocumentsByType(int typeId, string name, int projectId)
        {
            var query = from q in _context.siger_project_esop_document
                        join t in _context.siger_project_esop_document_set on q.type_id equals t.id
                        join h in _context.siger_project_esop_document_history on q.id equals h.document_id
                        join u in _context.siger_project_user on h.updator_mid equals u.mid
                        where h.is_valid == 1 && q.project_id == projectId && q.approval_status == DocumentApprovalStatus.ApprovalPass
                        select new ResponseGetDocumentByType
                        {
                            id = q.id,
                            file_name = q.name,
                            type_id = t.id,
                            type_name = t.name,
                            version = "V" + h.version,
                            uploader = u.name
                        };

            Expression<Func<ResponseGetDocumentByType, bool>> typeIdExpression = q => true;
            if (typeId != 0)
            {
                typeIdExpression = q => q.type_id == typeId;
            }

            Expression<Func<ResponseGetDocumentByType, bool>> nameExpression = q => true;
            if (!string.IsNullOrWhiteSpace(name))
            {
                nameExpression = q => q.file_name.Contains(name);
            }
            var predicate = typeIdExpression.And(nameExpression);

            return query.Where(predicate).AsNoTracking().ToList();
        }

        public void ClearApprovalRecords(int document_id)
        {
            var his = _context.siger_project_esop_document_approval.Where(q => q.document_id == document_id);
            foreach (var approval in his.ToList())
            {
                approval.status = (int)RowState.Invalid;
                _context.siger_project_esop_document_approval.Update(approval);
            }
        }

        public IEnumerable<ResponseFileInfo> GetFileUrl(int station, string productCode, int projectid)
        {
            var query = from  d in _context.siger_project_esop_document 
                        join pd in _context.siger_project_product on d.product_id equals pd.id
                        join h in _context.siger_project_esop_document_history on d.id equals h.document_id
                        join t in _context.siger_project_esop_document_set on d.type_id equals t.id
                        join m in _context.siger_project_machine on d.machine_id equals m.id
                        join sm in _context.siger_project_machine_attribution on m.id equals sm.machine
          
                        where d.project_id == projectid && sm.station==station && pd.code==productCode && d.status == (int)RowState.Valid && h.is_valid == 1 && m.category == (int)MachineCategory.NC
                        select new ResponseFileInfo
                        {
                            typeid = d.type_id,
                            typename = t.name,
                            filename = d.name,
                            fileurl = h.file_url

                        };
            return query.ToList();

        }

        public List<ResponseFileSet> GetEsopFileSet(int productid, int projectid)
        {
            var query = from d in _context.siger_project_esop_document
                        join pd in _context.siger_project_product on d.product_id equals pd.id
                        join h in _context.siger_project_esop_document_history on d.id equals h.document_id
                        join t in _context.siger_project_esop_document_set on d.type_id equals t.id
                        where d.project_id == projectid  && d.status == (int)RowState.Valid && h.is_valid == 1  
                        && pd.id== productid && d.approval_status== DocumentApprovalStatus.ApprovalPass
                        select new ResponseFileSet
                        {
                            typeid=d.type_id,
                            type = t.name,
                            filename = d.name,
                            fileurl = h.file_url,
                            productName=pd.name,
                            version="V"+h.version

                        };
            return query.ToList();
        }
    }
}
