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

import cn.axzo.msg.center.dal.mapper.TodoMapper;
import cn.axzo.msg.center.domain.dto.PendingCalendarCodeDTO;
import cn.axzo.msg.center.domain.entity.PendingRecordAdapter;
import cn.axzo.msg.center.domain.entity.Todo;
import cn.axzo.msg.center.inside.notices.config.PendingCalendarCodeConfig;
import cn.axzo.msg.center.message.domain.param.MessageGroupNodeStatisticParam;
import cn.axzo.msg.center.message.service.group.GroupTemplateService;
import cn.axzo.msg.center.message.service.group.GroupTemplates;
import cn.axzo.msg.center.service.dto.PersonDTO;
import cn.axzo.msg.center.service.enums.PendingMessageStateEnum;
import cn.axzo.msg.center.service.enums.TodoType;
import cn.axzo.msg.center.service.pending.request.PendingMessageFixedTemplatePageRequest;
import cn.axzo.msg.center.service.pending.request.PendingMessagePageRequest;
import cn.axzo.msg.center.service.pending.request.PendingMessageStatisticForWorkerRequest;
import cn.axzo.msg.center.service.pending.response.AnalysisPage;
import cn.axzo.msg.center.service.pending.response.PendingMessageResponse;
import cn.axzo.msg.center.service.pending.response.PendingMessageStatisticResponseV2;
import cn.axzo.msg.center.service.pending.response.PendingMessageStatisticResponseV2.GroupStat;
import cn.axzo.msg.center.service.pending.response.PendingMessageStatisticResponseV2.Stat;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.function.Function;

import static cn.axzo.msg.center.inside.notices.utils.Queries.collect;
import static java.util.stream.Collectors.toList;

/**
 * 工人定制内容唉
 *
 * @author yanglin
 */
@Component
@RequiredArgsConstructor
public class TodoWorkerQueryService {

    private final PendingCalendarCodeConfig calendarCodeConfig;
    private final TodoMapper todoMapper;
    private final TodoRespBuilder todoRespBuilder;
    private final TodoRangeQueryService todoRangeQueryService;
    private final GroupTemplateService groupTemplateService;

    /**
     * 小小聚合一把
     */
    public PendingMessageStatisticResponseV2 countStatGroupedForWorker(
            PendingMessageStatisticForWorkerRequest request) {
        MessageGroupNodeStatisticParam statRequest = new MessageGroupNodeStatisticParam();
        PersonDTO executor = new PersonDTO();
        executor.setId(request.getPersonId());
        statRequest.setOperator(executor);
        statRequest.setOuId(request.getOuId());
        statRequest.setGroupNodeCodes(request.getGroupNodeCodes());
        statRequest.setTerminalType(request.getAppTerminalType());
        PendingMessageStatisticResponseV2 statResp = todoRangeQueryService.countStatGrouped(statRequest);
        List<String> groupNodeCodes = statResp.getGroupStats().stream()
                .filter(i -> i.getStat() != null)
                .filter(i -> i.getStat().getPendingCount() == 1)
                .map(GroupStat::getGroupCode)
                .distinct()
                .collect(toList());
        if (CollectionUtils.isEmpty(groupNodeCodes))
            return statResp;
        PendingMessagePageRequest pageRequest = new PendingMessagePageRequest();
        pageRequest.setGroupNodeCodes(groupNodeCodes);
        pageRequest.setTodoType(TodoType.EXECUTABLE);
        pageRequest.setPersonId(request.getPersonId());
        pageRequest.setAppTerminalType(request.getAppTerminalType());
        pageRequest.setTerminalType(request.getTerminalType());
        pageRequest.setOuId(request.getOuId());
        pageRequest.setMsgState(PendingMessageStateEnum.HAS_BEEN_SENT);
        // 只查询只有一条待处理的分类, 所以数据量不会太大, 因为分类不可能无限大
        pageRequest.setPageSize(Long.MAX_VALUE);
        AnalysisPage<PendingMessageResponse> pageResp = todoRangeQueryService.pageQuery(pageRequest);
        List<PendingMessageResponse> pendingList = pageResp.getList() == null
                ? Collections.emptyList()
                : pageResp.getList();
        if (CollectionUtils.isEmpty(pendingList))
            return statResp;
        GroupTemplates groupTemplates = groupTemplateService.collectTemplates(groupNodeCodes);
        Function<String, PendingMessageResponse> findPendingFun = groupNodeCode -> {
            for (PendingMessageResponse pending : pendingList) {
                if (groupTemplates.groupContainsTemplate(groupNodeCode, pending.getTemplateCode()))
                    return pending;
            }
            return null;
        };
        for (GroupStat groupStat : statResp.getGroupStats()) {
            Stat stat = groupStat.getStat();
            if (stat == null)
                continue;
            if (stat.getPendingCount() != 1)
                continue;
            PendingMessageResponse pending = findPendingFun.apply(groupStat.getGroupCode());
            groupStat.setWorkerSingleTodo(pending);
        }
        return statResp;
    }

    // !! calendar

    public List<PendingMessageResponse> getWorkerCalendar(PendingMessageFixedTemplatePageRequest request) {
        LocalDate selectedTime = request.getSelectDate()
                .toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
        LocalDate currentTime = LocalDate.now();
        // 当前时间之后
        if (selectedTime.isAfter(currentTime))
            return Collections.emptyList();
        // 是否是当天? very tricky?
        boolean isToday = !selectedTime.isBefore(currentTime);
        PendingCalendarCodeDTO calendarCodes = new PendingCalendarCodeDTO(
                calendarCodeConfig.getConstructionCodes(), calendarCodeConfig.getClockInCodes(),
                calendarCodeConfig.getPunchInCodes(), calendarCodeConfig.getCalendarAllCodes());
        List<Todo> todos = todoMapper.queryWorkerCalendar(
                calendarCodes, request.getWorkspaceId(),
                request.getSelectDate(), request.getPersonId(), isToday);
        int order = 0;
        HashMap<Long, Integer> todoId2Order = new HashMap<>();
        for (Todo todo : todos)
            todoId2Order.put(todo.getId(), ++order);
        // JSON的TypeHandle没有生效, 重新查询一次
        if (CollectionUtils.isNotEmpty(todos)) {
            todos = todoMapper.selectBatchIds(collect(todos, Todo::getId));
            // 拷贝一份, 恢复排序
            todos = new ArrayList<>(todos);
            todos.sort((t1, t2) -> {
                Integer o1 = todoId2Order.getOrDefault(t1.getId(), 0);
                Integer o2 = todoId2Order.getOrDefault(t2.getId(), 0);
                return o1.compareTo(o2);
            });
        }
        List<PendingRecordAdapter> adapters = todoRespBuilder.buildTodoAdapters(todos);
        return todoRespBuilder.convertAdapter2MessageResponse(adapters, request.getTerminalType());
    }

}