package cn.axzo.msg.center.message.service.todo;

import cn.axzo.basics.common.BeanMapper;
import cn.axzo.msg.center.common.enums.TableIsDeleteEnum;
import cn.axzo.msg.center.common.utils.BizAssertions;
import cn.axzo.msg.center.dal.TodoBusinessDao;
import cn.axzo.msg.center.dal.TodoDao;
import cn.axzo.msg.center.domain.entity.PendingRecordAdapter;
import cn.axzo.msg.center.domain.entity.Todo;
import cn.axzo.msg.center.domain.entity.TodoBusiness;
import cn.axzo.msg.center.inside.notices.config.PendingMessageBizConfig;
import cn.axzo.msg.center.service.enums.TerminalTypeEnum;
import cn.axzo.msg.center.service.enums.TodoQueryType;
import cn.axzo.msg.center.service.enums.TodoType;
import cn.axzo.msg.center.service.pending.request.PendingMessageByBizCodeRequest;
import cn.axzo.msg.center.service.pending.request.PendingMessageQueryRequest;
import cn.axzo.msg.center.service.pending.response.PendingMessageResponse;
import cn.axzo.msg.center.service.pending.response.PendingMessageSimpleDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;

/**
 * @author yanglin
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class TodoSimpleQueryService {

    private final TodoBusinessDao todoBusinessDao;
    private final TodoDao todoDao;
    private final TodoRespBuilder todoRespBuilder;
    private final PendingMessageBizConfig cfg;

    public PendingMessageResponse query(PendingMessageQueryRequest req) {
        // 虽然通过code可以查询到唯一的记录, 把一些事情交给数据库去库, 成本不高
        Todo todo = todoDao.lambdaQuery()
                .eq(Todo::getIdentityCode, req.getMsgIdentityCode())
                .eq(req.getMsgState() != null, Todo::getState, req.getMsgState())
                .eq(req.getWorkspaceId() != null, Todo::getOrgId, req.getWorkspaceId())
                .last("LIMIT 1")
                .one();
        if (todo == null)
            return null;
        // 虽然通过business id可以查询到唯一的记录, 把一些事情交给数据库去库, 成本不高
        TodoBusiness business = todoBusinessDao.lambdaQuery()
                .eq(TodoBusiness::getId, todo.getTodoBusinessId())
                .eq(req.getBizFinalState() != null, TodoBusiness::getBizFinalState, req.getBizFinalState())
                .like(StringUtils.isNotBlank(req.getTitle()), TodoBusiness::getTitle, req.getTitle())
                .last("LIMIT 1")
                .one();
        return todoRespBuilder
                .convertTodoToMessage(business, todo)
                .toResponse(req.getTerminalType());
    }

    public PendingMessageResponse getDetail(
            String identityCode, TerminalTypeEnum terminalType, TodoQueryType queryType) {
        Todo todo = todoDao.findTodoByCode(identityCode).orElse(null);
        if (todo == null)
            return null;
        if (queryType == TodoQueryType.SEND_BY_ME) {
            TodoBusiness business = todoBusinessDao.getById(todo.getTodoBusinessId());
            PendingRecordAdapter adapter = todoRespBuilder.buildBusinessAdapter(business);
            return todoRespBuilder.convertAdapter2MessageResponse(adapter, terminalType);
        }
        return todoRespBuilder
                .convertTodoToMessage(todo)
                .toResponse(terminalType);
    }

    public PendingMessageResponse getLatestTodoByBiz(
            String templateCode, String bizCode, String subBizCode, TodoType todoType) {
        Todo todo = todoDao
                .getLatestByBiz(templateCode, bizCode, subBizCode, todoType)
                .orElse(null);
        if (todo == null)
            return null;
        return todoRespBuilder
                .convertTodoToMessage(todo)
                .toResponse(null);
    }

    public List<PendingMessageSimpleDTO> getLatestTodosByBiz(PendingMessageByBizCodeRequest param) {
        List<String> bizCodes = param.determineBizCodes();
        if (CollectionUtils.isEmpty(bizCodes))
            return Collections.emptyList();
        BizAssertions.assertTrue(bizCodes.size() <= cfg.getGetLatestByBizCodeMaxSize(),
                String.format("bizCode的数量不能超过 %d", cfg.getGetLatestByBizCodeMaxSize()));
        List<Todo> todos = todoDao.lambdaQuery()
                .in(Todo::getBizCode, bizCodes)
                .eq(Todo::getIsDelete, TableIsDeleteEnum.NORMAL.value)
                .list();
        Map<String, List<Todo>> bizCode2Todos = todos.stream()
                .collect(groupingBy(Todo::getBizCode));
        List<Todo> latestTodos = new ArrayList<>();
        for (List<Todo> todosPerBizCode : bizCode2Todos.values()) {
            List<Todo> filteredTodos = new ArrayList<>(todosPerBizCode.size());
            // 存在操作人
            if (param.getOperatorPersonId() != null)
                filteredTodos = todosPerBizCode.stream()
                        .filter(e -> e.getExecutorPersonId().equals(param.getOperatorPersonId()))
                        .collect(toList());
            else if (null != param.getOperatorIdentityId())
                filteredTodos = todosPerBizCode.stream()
                        .filter(e -> e.getExecutorId().equals(param.getOperatorIdentityId()))
                        .collect(toList());
            // 流程最终的记录
            List<Todo> finalTodos = CollectionUtils.isEmpty(filteredTodos) ? todosPerBizCode : filteredTodos;
            // 获取最新的待办
            finalTodos.stream()
                    .max(comparing(Todo::getId))
                    .ifPresent(latestTodos::add);
        }
        List<PendingRecordAdapter> adapters = todoRespBuilder.buildTodoAdapters(latestTodos);
        return adapters.stream()
                .map(MigrateUtils::convertAdapterToPending)
                .map(p -> BeanMapper.copyBean(p, PendingMessageSimpleDTO.class))
                .collect(toList());
    }

}