/// <summary>
        /// Get workflow by id for display
        /// </summary>
        /// <param name="workFlowId"></param>
        /// <returns></returns>
        public virtual async Task <ResultModel <WorkFlowGetViewModel> > GetWorkFlowByIdForDisplayAsync(Guid?workFlowId)
        {
            var workFlowRequest = await GetWorkFlowByIdAsync(workFlowId);

            return(!workFlowRequest.IsSuccess ? workFlowRequest.Map <WorkFlowGetViewModel>()
                : new SuccessResultModel <WorkFlowGetViewModel>(WorkFlowMapper.Map(workFlowRequest.Result)));
        }
        /// <summary>
        /// Get workflow states
        /// </summary>
        /// <param name="workFlowId"></param>
        /// <returns></returns>
        public virtual async Task <ResultModel <IEnumerable <StateGetViewModel> > > GetWorkFlowStatesAsync([Required] Guid?workFlowId)
        {
            var workFlowRequest = await GetWorkFlowByIdAsync(workFlowId);

            return(!workFlowRequest.IsSuccess ? workFlowRequest.Map <IEnumerable <StateGetViewModel> >()
                : new SuccessResultModel <IEnumerable <StateGetViewModel> >(WorkFlowMapper.Map(workFlowRequest.Result.States)));
        }
        /// <summary>
        /// Add new state
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public virtual async Task <ResultModel <Guid?> > AddStateToWorkFlowAsync(AddNewStateViewModel model)
        {
            Arg.NotNull(model, nameof(AddNewStateViewModel));
            var response        = new ResultModel <Guid?>();
            var workflowRequest = await GetWorkFlowByIdAsync(model.WorkFlowId);

            if (!workflowRequest.IsSuccess)
            {
                return(workflowRequest.Map <Guid?>());
            }
            var workFlow = workflowRequest.Result;
            var checkDuplicateStateName = workFlow.States.FirstOrDefault(x => x.Name.Equals(model.Name));

            if (checkDuplicateStateName != null)
            {
                response.Errors.Add(new ErrorModel(nameof(WorkFlowErrorCodes.GRWF_0x104), WorkFlowErrorCodes.GRWF_0x104));
                return(response);
            }

            var state = WorkFlowMapper.Map(model);

            if (!workFlow.States.Any())
            {
                state.IsStartState = true;
            }

            await _workFlowContext.States.AddAsync(state);

            var dbRequest = await _workFlowContext.PushAsync();

            return(dbRequest.Map <Guid?>(state.Id));
        }
        /// <summary>
        /// Add new workflow
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public virtual async Task <ResultModel <Guid> > AddNewWorkflowAsync(AddNewWorkflowViewModel model)
        {
            Arg.NotNull(model, nameof(AddNewWorkflowViewModel));
            var workflow = WorkFlowMapper.Map(model);
            await _workFlowContext.WorkFlows.AddAsync(workflow);

            var dbRequest = await _workFlowContext.PushAsync();

            return(dbRequest.Map(workflow.Id));
        }
        /// <summary>
        /// Get state by id
        /// </summary>
        /// <param name="stateId"></param>
        /// <returns></returns>
        public virtual async Task <ResultModel <StateGetViewModel> > GetStateByIdAsync(Guid?stateId)
        {
            if (stateId == null)
            {
                return(new InvalidParametersResultModel <StateGetViewModel>());
            }
            var state = await _workFlowContext.States
                        .Include(x => x.WorkFlow)
                        .FirstOrDefaultAsync(x => x.Id.Equals(stateId));

            if (state == null)
            {
                return(new NotFoundResultModel <StateGetViewModel>());
            }
            return(new SuccessResultModel <StateGetViewModel>(WorkFlowMapper.Map(state)));
        }
        /// <summary>
        /// Get entry history
        /// </summary>
        /// <param name="workflowId"></param>
        /// <param name="entryId"></param>
        /// <returns></returns>
        public virtual async Task <ResultModel <IEnumerable <EntryHistoryViewModel> > > GetEntryHistoryByWorkflowIdAsync(Guid?workflowId, string entryId)
        {
            if (workflowId == null || entryId.IsNullOrEmpty())
            {
                return(new InvalidParametersResultModel <IEnumerable <EntryHistoryViewModel> >());
            }
            var history = await _workFlowContext.EntryStateHistories
                          .AsNoTracking()
                          .Include(x => x.EntryState)
                          .ThenInclude(x => x.Contract)
                          .ThenInclude(x => x.WorkFlow)
                          .Include(x => x.FromState)
                          .Include(x => x.ToState)
                          .Where(x => x.EntryState.Contract.WorkFlowId.Equals(workflowId) &&
                                 x.EntryState.EntryId.Equals(entryId))
                          .ToListAsync();

            return(new SuccessResultModel <IEnumerable <EntryHistoryViewModel> >(WorkFlowMapper.Map(history)));
        }
        /// <summary>
        /// Get next states for entry
        /// </summary>
        /// <param name="entryId"></param>
        /// <param name="workFlowId"></param>
        /// <returns></returns>
        public virtual async Task <ResultModel <IEnumerable <StateGetViewModel> > > GetNextStatesForEntryAsync([Required] string entryId, [Required] Guid?workFlowId)
        {
            var entryStateRequest = await GetEntryStateAsync(entryId, workFlowId);

            if (!entryStateRequest.IsSuccess)
            {
                return(entryStateRequest.Map <IEnumerable <StateGetViewModel> >());
            }
            var entryState        = entryStateRequest.Result;
            var currentState      = entryState.State;
            var nextStatesRequest = await GetNextStatesForAllowedRolesAsync(currentState);

            if (!nextStatesRequest.IsSuccess)
            {
                return(nextStatesRequest.Map <IEnumerable <StateGetViewModel> >());
            }
            var mappedCollection = WorkFlowMapper.Map(nextStatesRequest.Result);

            return(new SuccessResultModel <IEnumerable <StateGetViewModel> >(mappedCollection));
        }
        /// <summary>
        /// Create transition
        /// </summary>
        /// <param name="workFlowId"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task <ResultModel <Guid> > CreateTransitionAsync([Required] Guid?workFlowId, AddTransitionViewModel model)
        {
            Arg.NotNull(model, nameof(AddTransitionViewModel));
            var response        = new ResultModel <Guid>();
            var workflowRequest = await GetWorkFlowByIdAsync(workFlowId);

            if (!workflowRequest.IsSuccess)
            {
                return(workflowRequest.Map <Guid>());
            }
            var workFlow  = workflowRequest.Result;
            var fromState = workFlow.States.FirstOrDefault(x => x.Id.Equals(model.FromStateId));
            var toState   = workFlow.States.FirstOrDefault(x => x.Id.Equals(model.ToStateId));

            if (fromState == null || toState == null)
            {
                response.Errors.Add(new ErrorModel(string.Empty, $"Workflow {workFlow.Name} does not have such states"));
                return(response);
            }

            if (IsDuplicateTransition(workFlow, model.FromStateId, model.ToStateId))
            {
                response.Errors.Add(new ErrorModel(nameof(WorkFlowErrorCodes.GRWF_0x101), WorkFlowErrorCodes.GRWF_0x101));
                return(response);
            }

            if (IsConnectionByItSelf(workFlow, model.FromStateId, model.ToStateId))
            {
                response.Errors.Add(new ErrorModel(nameof(WorkFlowErrorCodes.GRWF_0x100), WorkFlowErrorCodes.GRWF_0x100));
                return(response);
            }

            var transition = WorkFlowMapper.Map(model, workFlowId);

            await _workFlowContext.Transitions.AddAsync(transition);

            var dbRequest = await _workFlowContext.PushAsync();

            return(dbRequest.Map(transition.Id));
        }
        /// <summary>
        /// Get all workflows
        /// </summary>
        /// <returns></returns>
        public virtual async Task <ResultModel <IEnumerable <GetWorkFlowViewModel> > > GetAllWorkFlowsAsync()
        {
            var workFlows = await _workFlowContext.WorkFlows.AsNoTracking().ToListAsync();

            return(new SuccessResultModel <IEnumerable <GetWorkFlowViewModel> >(WorkFlowMapper.Map(workFlows)));
        }