using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using GxPress.Entity.WorkFlow;
using GxPress.EnumConst;
using GxPress.Request.App.Flow;
using GxPress.Result.App.Flow;

namespace GxPress.Service.Implement
{
    public partial class FlowService
    {
        public async Task<ListResult> ListAllAsync(int page, int perPage, int processId, string state, string startDate, string endDate)
        {
            var flowList = await _flowRepository.GetListAllAsync(page, perPage, processId, state, startDate, endDate);
            var items = await GetFlowListResultListAsync(flowList);

            return new ListResult
            {
                Count = await _flowRepository.GetCountAsync(processId, state, startDate, endDate),
                Items = items
            };
        }

        public async Task<ListResult> ListMyCheckingAsync(int userId, FlowListRequest request, string source = "")
        {
            var todoIdFlowIdList = await _flowTodoRepository.GetTodoIdFlowIdListAsync(userId, nameof(TodoTypeConst.ApproverCheck), false, request);
            var items = new List<FlowListResult>();
            foreach (var todoIdFlowId in todoIdFlowIdList)
            {
                var flow = await _flowRepository.GetAsync(todoIdFlowId.FlowId);
                if (flow != null)
                {
                    items.Add(await GetFlowListResultAsync(flow, todoIdFlowId.TodoId, source));
                }
            }
            //var flowList = await _flowRepository.GetListByIdListAsync(flowIdList, request.Page, request.PerPage);
            //var items = await GetFlowListResultListAsync(flowList);

            return new ListResult
            {
                Count = await _flowTodoRepository.GetCountAsync(userId, nameof(TodoTypeConst.ApproverCheck), false,
                    request),
                Items = items
            };
        }

        public async Task<ListResult> ListMyCheckedAsync(int userId, FlowListRequest request, string source = "")
        {
            var todoIdFlowIdList = await _flowTodoRepository.GetTodoIdFlowIdListAsync(userId, nameof(TodoTypeConst.ApproverCheck), true, request);
            var items = new List<FlowListResult>();
            foreach (var todoIdFlowId in todoIdFlowIdList)
            {
                var flow = await _flowRepository.GetAsync(todoIdFlowId.FlowId);
                if (flow != null)
                {
                    items.Add(await GetFlowListResultAsync(flow, todoIdFlowId.TodoId, source));
                }
            }

            return new ListResult
            {
                Count = await _flowTodoRepository.GetCountAsync(userId, nameof(TodoTypeConst.ApproverCheck), true, request),
                Items = items
            };
        }

        public async Task<ListResult> ListSubmittedCheckingAsync(int userId, FlowListRequest request, string source = "")
        {
            var flowList = await _flowRepository.GetListByUserIdAsync(userId, true, request);
            var items = await GetFlowListResultListAsync(flowList, source);

            return new ListResult
            {
                Count = await _flowRepository.GetCountByUserIdAsync(userId, true, request),
                //Count = items.Count(),
                Items = items
            };
        }

        public async Task<ListResult> ListSubmittedCheckedAsync(int userId, FlowListRequest request)
        {
            var flowList = await _flowRepository.GetListByUserIdAsync(userId, false, request);
            var items = await GetFlowListResultListAsync(flowList);

            return new ListResult
            {
                Count = await _flowRepository.GetCountByUserIdAsync(userId, false, request),
                Items = items
            };
        }

        public async Task<ListResult> ListCcUnreadAsync(int userId, FlowListRequest request)
        {
            var todoIdFlowIdList = await _flowTodoRepository.GetTodoIdFlowIdListAsync(userId, nameof(TodoTypeConst.CarbonCopy), request,false);
            var items = new List<FlowListResult>();
            foreach (var todoIdFlowId in todoIdFlowIdList)
            {
                var flow = await _flowRepository.GetAsync(todoIdFlowId.FlowId);
                if (flow != null)
                {
                    items.Add(await GetFlowListResultAsync(flow, todoIdFlowId.TodoId));
                }
            }

            return new ListResult
            {
                Count = await _flowTodoRepository.GetReadCountAsync(userId, nameof(TodoTypeConst.CarbonCopy), request,false),
                Items = items
            };
        }

        public async Task<ListResult> ListCcAllAsync(int userId, FlowListRequest request, string source = "")
        {
            var todoIdFlowIdList = await _flowTodoRepository.GetTodoIdFlowIdListAsync(userId, nameof(TodoTypeConst.CarbonCopy), request,true);
            var items = new List<FlowListResult>();
            foreach (var todoIdFlowId in todoIdFlowIdList)
            {
                var flow = await _flowRepository.GetAsync(todoIdFlowId.FlowId);
                if (flow != null)
                {
                    items.Add(await GetFlowListResultAsync(flow, todoIdFlowId.TodoId, source));
                }
            }

            return new ListResult
            {
                Count = await _flowTodoRepository.GetReadCountAsync(userId, nameof(TodoTypeConst.CarbonCopy), request,true),
                Items = items
            };
        }

        private async Task<IEnumerable<FlowListResult>> GetFlowListResultListAsync(IEnumerable<Entity.WorkFlow.Flow> flowList, string source = "")
        {
            var resultList = flowList.Select(async x =>
            {
                var user = await _userRepository.GetAsync(x.UserId);
                var result = new FlowListResult
                {
                    Id = x.Id,
                    ProcessId = x.ProcessId,
                    UserId = x.UserId,
                    State = x.State,
                    ProcessNodeId = x.ProcessNodeId,
                    CreatedDate = x.CreatedDate,
                    Guid = x.Guid
                };
                var (title, summaries) = await GetFlowTitleAndSummaryAsync(user, x.ProcessId, x.Id);
                result.Title = title;
                result.AvatarUrl = _userRepository.GetAvatarUrl(user);
                result.Summaries = summaries;
                if (source == nameof(FlowListTypeConst.SubmittedChecking))
                    result.IsRead = true;
                else
                    result.IsRead = x.IsRead;
                return result;
            });

            return await Task.WhenAll(resultList);
        }

        private async Task<FlowListResult> GetFlowListResultAsync(Entity.WorkFlow.Flow flow, int todoId, string source = "")
        {
            var user = await _userRepository.GetAsync(flow.UserId);
            //获取todo
            var tode = await _flowTodoRepository.GetAsync(todoId);
            var result = new FlowListResult
            {
                Id = flow.Id,
                TodoId = todoId,
                ProcessId = flow.ProcessId,
                UserId = flow.UserId,
                State = flow.State,
                ProcessNodeId = flow.ProcessNodeId,
                CreatedDate = flow.CreatedDate,
                Guid = flow.Guid
            };
            // if (tode != null)
            // {
            //     if (tode.IsDone && tode.IsChecked)
            //         result.State = FlowState.Checked;
            //     else if (tode.IsDone && !tode.IsChecked)
            //         result.State = FlowState.Denied;
            //     else
            //         result.State = FlowState.Checking;
            // }
            var (title, summaries) = await GetFlowTitleAndSummaryAsync(user, flow.ProcessId, flow.Id);
            result.Title = title;
            result.AvatarUrl = _userRepository.GetAvatarUrl(user);
            result.Summaries = summaries;
            if (source == nameof(FlowListTypeConst.MyChecking) || source == nameof(FlowListTypeConst.MyChecked))
                result.IsRead = tode.IsDone;
            else if (source == nameof(FlowListTypeConst.CcAll) || source == nameof(FlowListTypeConst.SubmittedChecking))
                result.IsRead = true;
            else
                result.IsRead = tode.IsRead;
            return result;
        }
    }
}