using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using GxPress.Common.Tools;
using GxPress.Entity.WorkFlow;
using GxPress.Entity.WorkFlowDto;
using GxPress.Entity.WorkProcessDto;
using GxPress.EnumConst;

namespace GxPress.Service.Implement
{
    public partial class FlowService
    {
        public async Task<List<ProcessNodeDto>> GetNodesAsync(FlowDto flow, List<ProcessNodeDto> nodes)
        {
            var nodeList = new List<ProcessNodeDto>();
            //var nodes = await _processService.GetNodesAsync(flow.ProcessId, 0);
            //var fields = await _processFieldRepository.GetListAsync(flow.ProcessId);
            foreach (var processNodeDto in nodes)
            {
                if (processNodeDto.Type == nameof(ProcessNodeTypeConst.Switch))
                {
                    var theCase = GetCase(processNodeDto.Children, flow);
                    nodeList.AddRange(await GetNodesAsync(flow, theCase.Children));
                }
                else if (processNodeDto.Type == nameof(ProcessNodeTypeConst.Start) ||
                         processNodeDto.Type == nameof(ProcessNodeTypeConst.Approver) ||
                         processNodeDto.Type == nameof(ProcessNodeTypeConst.End))
                {
                    nodeList.Add(processNodeDto);
                }
            }

            return nodeList;
        }

        private ProcessNodeDto GetCase(List<ProcessNodeDto> cases, FlowDto flow)
        {
            cases = cases.OrderBy(x => x.CaseLevel).ToList();
            var rightNode = cases.LastOrDefault();
            foreach (var caseNode in cases)
            {
                var isSuccess = false;
                foreach (var condition in caseNode.Conditions)
                {
                    var field = flow.Fields?.FirstOrDefault(x => x.Id == condition.FieldId);
                    if (field != null)
                    {
                        if (field.Type == nameof(FieldTypeConst.Number) ||
                            field.Type == nameof(FieldTypeConst.Currency))
                        {
                            var value = StringUtils.ToInt(field.Value);
                            if (condition.Operator == nameof(OperatorConst.Equals))
                            {
                                if (value == condition.IntValue)
                                {
                                    isSuccess = true;
                                    break;
                                }
                            }
                            else if (condition.Operator == nameof(OperatorConst.NotEquals))
                            {
                                if (value != condition.IntValue)
                                {
                                    isSuccess = true;
                                    break;
                                }
                            }
                            else if (condition.Operator == nameof(OperatorConst.GreatThan))
                            {
                                if (value > condition.IntValue)
                                {
                                    isSuccess = true;
                                    break;
                                }
                            }
                            else if (condition.Operator == nameof(OperatorConst.LessThan))
                            {
                                if (value < condition.IntValue)
                                {
                                    isSuccess = true;
                                    break;
                                }
                            }
                        }
                        else if (field.Type == nameof(FieldTypeConst.Radio))
                        {
                            var value = field.Value;
                            if (condition.Operator == nameof(OperatorConst.In))
                            {
                                if (condition.StringValues.Contains(value))
                                {
                                    isSuccess = true;
                                    break;
                                }
                            }
                            else if (condition.Operator == nameof(OperatorConst.NotIn))
                            {
                                if (!condition.StringValues.Contains(value))
                                {
                                    isSuccess = true;
                                    break;
                                }
                            }
                        }
                        else if (field.Type == nameof(FieldTypeConst.Text))
                        {
                            var value = field.Value;
                            if (condition.Operator == nameof(OperatorConst.Equals))
                            {
                                if (condition.StringValue == value)
                                {
                                    isSuccess = true;
                                    break;
                                }
                            }
                            else if (condition.Operator == nameof(OperatorConst.NotEquals))
                            {
                                if (condition.StringValue != value)
                                {
                                    isSuccess = true;
                                    break;
                                }
                            }
                        }
                    }
                }

                if (isSuccess)
                {
                    rightNode = caseNode;
                    break;
                }
            }

            return rightNode;
        }

        /// <summary>
        /// 获取用户ID
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        public async Task<List<int>> GetListUserAsync(ProcessNodeDto node)
        {
            if (node.Type == nameof(ProcessNodeTypeConst.Start) || node.Type == nameof(ProcessNodeTypeConst.End))
            {
                var ccList = await _ruleCarbonCopyRepository.GetListAsync(node.Id);
                var userIdList = new List<int>();
                foreach (var ruleCarbonCopy in ccList)
                {
                    userIdList.AddRange(await GetUserIdListAsync(ruleCarbonCopy));
                }
                return userIdList;
            }
            else if (node.Type == nameof(ProcessNodeTypeConst.Approver))
            {
                var acList = await _ruleApproverCheckRepository.GetListAsync(node.Id);
                var userIdList = new List<int>();
                foreach (var ruleApproverCheck in acList)
                {
                    userIdList.AddRange(await GetUserIdListAsync(ruleApproverCheck));
                }
                return userIdList;
            }
            return new List<int>();
        }
        /// <summary>
        /// 工作流程条件判断
        /// </summary>
        /// <param name="flow"></param>
        /// <returns></returns>
        public async Task NodeExecuteSwitchAsync(FlowDto flow, ProcessNodeDto processNode)
        {
            //查询是否有条件 Switch
            var processNodes = await _processNodeRepository.GetAllAsync(flow.ProcessId);
            //查询Case
            var caseList = processNodes.Where(n => n.ParentId == processNode.Id).ToList();
            var success = false;
            foreach (var caseValue in caseList)
            {
                if (success)
                    break;
                //查询Approver
                var approvers = processNodes.Where(n => n.ParentId == caseValue.Id);
                foreach (var node in approvers)
                {
                    //查询是否有条件
                    if (node.ParentId > 0)
                    {
                        var ruleConditions = await _ruleConditionRepository.GetListAsync(node.ParentId);
                        if (ruleConditions.Count() > 0)
                            success = false;
                        else
                            success = true;
                        foreach (var item in ruleConditions)
                        {
                            //判断是否等于
                            if (item.Operator.Equals("Equals"))
                            {
                                foreach (var field in flow.Fields)
                                {
                                    if (field.Id == item.FieldId)
                                        if (field.Value.Equals(item.IntValue))
                                            success = true;
                                }
                            }
                            if (item.Operator.Equals("In"))
                            {
                                foreach (var field in flow.Fields)
                                {
                                    if (field.Id == item.FieldId)
                                        if (field.Value.Equals(item.StringValue))
                                            success = true;
                                }
                            }
                            if (item.Operator.Equals("NotIn"))
                            {
                                foreach (var field in flow.Fields)
                                {
                                    if (field.Id == item.FieldId)
                                        if (field.Value.Equals(item.StringValue))
                                        {
                                            success = true;
                                            break;
                                        }
                                        else
                                            break;
                                }
                            }
                        }
                    }
                    if (!success)
                        break;
                }
                //
                if (success)
                {
                    approvers = processNodes.Where(n => n.ParentId == caseValue.Id);
                    foreach (var node in approvers)
                    {
                        //获取抄送人
                        var ccList = await _ruleCarbonCopyRepository.GetListAsync(node.Id);
                        var userIdList = new List<int>();
                        foreach (var ruleCarbonCopy in ccList)
                        {
                            userIdList.AddRange(await GetUserIdListAsync(ruleCarbonCopy));
                        }
                        await TaskCarbonCopyAsync(userIdList.Distinct(), flow);
                        var acList = await _ruleApproverCheckRepository.GetListAsync(node.Id);
                        //获取审核人 是否是或签
                        if (node.ApprovalType == "Or")
                        {
                            flow.IsCaseOr = true;
                            flow.ParentId = node.Id;
                        }
                        //审核人
                        acList = await _ruleApproverCheckRepository.GetListAsync(node.Id);
                        userIdList = new List<int>();
                        foreach (var ruleApproverCheck in acList)
                        {
                            userIdList.AddRange(await GetUserIdListAsync(ruleApproverCheck));
                        }
                        await TaskApproverCheckAsync(userIdList.Distinct(), flow);
                    }
                    break;
                }
            }
        }

        public async Task NodeExecuteAsync(FlowDto flow, ProcessNodeDto node)
        {
            //_ruleCarbonCopyRepository = ruleCarbonCopyRepository;
            //_ruleApproverCheckRepository = ruleApproverCheckRepository;
            //_ruleConditionRepository = ruleConditionRepository;

            if (node.Type == nameof(ProcessNodeTypeConst.Start) || node.Type == nameof(ProcessNodeTypeConst.End))
            {
                var ccList = await _ruleCarbonCopyRepository.GetListAsync(node.Id);
                var userIdList = new List<int>();
                foreach (var ruleCarbonCopy in ccList)
                {
                    userIdList.AddRange(await GetUserIdListAsync(ruleCarbonCopy));
                }
                await TaskCarbonCopyAsync(userIdList.Distinct(), flow);
            }
            else if (node.Type == nameof(ProcessNodeTypeConst.Approver))
            {
                var acList = await _ruleApproverCheckRepository.GetListAsync(node.Id);
                //获取审核人 是否是或签
                if (node.ApprovalType == "Or")
                {
                    flow.IsCaseOr = true;
                    flow.ParentId = node.Id;
                }
                else
                {
                    flow.IsCaseOr = false;
                    flow.ParentId = 0;
                }
                var userIdList = new List<int>();
                foreach (var ruleApproverCheck in acList)
                {
                    userIdList.AddRange(await GetUserIdListAsync(ruleApproverCheck));
                }
                await TaskApproverCheckAsync(userIdList.Distinct(), flow);
            }


        }

        private async Task TaskCarbonCopyAsync(IEnumerable<int> userIdList, FlowDto flow)
        {
            foreach (var userId in userIdList)
            {
                var todo = new FlowTodo
                {
                    ProcessId = flow.ProcessId,
                    FlowId = flow.Id,
                    UserId = userId,
                    Type = nameof(TodoTypeConst.CarbonCopy),
                    IsDone = false,
                    IsOperate = false,
                };

                await _flowTodoRepository.InsertAsync(todo);
            }
        }

        private async Task TaskApproverCheckAsync(IEnumerable<int> userIdList, FlowDto flow)
        {
            foreach (var userId in userIdList)
            {
                var todo = new FlowTodo
                {
                    ProcessId = flow.ProcessId,
                    FlowId = flow.Id,
                    UserId = userId,
                    Type = nameof(TodoTypeConst.ApproverCheck),
                    IsDone = false,
                    IsOperate = false,
                    IsCaseOr = flow.IsCaseOr,
                    ParentId = flow.ParentId
                };
                await _flowTodoRepository.InsertAsync(todo);
            }
        }

        private async Task<List<int>> GetUserIdListAsync(List<ApproverCheck> approverChecks)
        {
            var allUserIdList = new List<int>();
            foreach (var multipleUser in approverChecks)
            {
                var userIdList = await GetUserIdListAsync(multipleUser);
                foreach (var userId in userIdList)
                {
                    if (!allUserIdList.Contains(userId))
                    {
                        allUserIdList.Add(userId);
                    }
                }
            }
            return allUserIdList;
        }

        private async Task<List<int>> GetUserIdListAsync(IMultipleUser multipleUser)
        {
            if (multipleUser != null)
            {
                if (multipleUser.UserId > 0)
                {
                    return new List<int> { multipleUser.UserId };
                }

                if (multipleUser.RoleId > 0)
                {
                    return (await _userRepository.GetUserIdListByRoleIdAsync(multipleUser.RoleId)).ToList();
                }

                if (multipleUser.DepartmentId > 0)
                {
                    return (await _userRepository.GetUserIdListByDepartmentIdAsync(multipleUser.DepartmentId)).ToList();
                }
            }
            return new List<int>();
        }
    }
}