package jnpf.attendance.service.handle.notice;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import jnpf.ImRobotApi;
import jnpf.attendance.mapper.AttendanceManagerPermissionMapper;
import jnpf.attendance.service.AttendanceNoticeService;
import jnpf.attendance.service.AttendanceUserService;
import jnpf.attendance.service.AttendanceUserSettingService;
import jnpf.base.ActionResult;
import jnpf.entity.AttendanceGroupUser;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.enums.attendance.UserSettingTypeEnum;
import jnpf.from.*;
import jnpf.model.attendance.dto.NoticeSaveDto;
import jnpf.model.attendance.model.AttendanceNoticeModel;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.NoticeConfirm;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.model.attendance.vo.AttendanceGroupAdminVo;
import jnpf.model.attendance.vo.AttendancePermissionVo;
import jnpf.model.attendance.vo.UserSettingVo;
import jnpf.util.ConstantUtil;
import jnpf.util.RandomUtil;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static jnpf.constants.AttendanceConstant.*;

@Component
@Slf4j
public class AttendanceNoticeHandler {
    @Autowired
    private Map<String, AttendanceNotice> attendanceNoticeList;
    @Autowired
    private AttendanceNoticeService attendanceNoticeService;
    @Autowired
    private ImRobotApi imRobotApi;
    @Autowired
    private AttendanceUserSettingService attendanceUserSettingService;
    @Resource
    private AttendanceManagerPermissionMapper attendanceManagerPermissionMapper;
    @Autowired
    private AttendanceUserService attendanceUserService;

    /**
     * 通知发送
     * @param attendanceNoticeModel 过程数据
     */
    public void send(AttendanceNoticeModel attendanceNoticeModel) {
        if (Objects.isNull(attendanceNoticeModel.getAttendanceNoticeEnum())) {
            log.error("通知类型未填充");
            return;
        }
        AttendanceNotice notice = attendanceNoticeList.get(attendanceNoticeModel.getAttendanceNoticeEnum().getServiceName());
        if (Objects.isNull(notice)) {
            log.error("未获取到该通知[{}]具体service实现", attendanceNoticeModel.getAttendanceNoticeEnum().getDesc());
            return;
        }
        if (!notice.isPass(attendanceNoticeModel)) {
            log.error("未满足通知[{}]条件，过滤", attendanceNoticeModel.getAttendanceNoticeEnum().getDesc());
            return;
        }
        List<T> data = notice.generatingData(attendanceNoticeModel);
        if(CollUtil.isEmpty(data)){
            return;
        }
        List<String> recipientList = notice.getRecipient(attendanceNoticeModel);
        if (CollUtil.isEmpty(recipientList)) {
            log.error("未获取到该通知[{}]接收人", attendanceNoticeModel.getAttendanceNoticeEnum().getDesc());
            return;
        }
        String noticeId = RandomUtil.uuId();
        SystemNoticeStrategy build = notice.setSystemNoticeStrategy(attendanceNoticeModel, noticeId);
        Integer isConfirm = Objects.nonNull(build.getIsConfirm()) && build.getIsConfirm() ? 1 : 0;
        attendanceNoticeService.noticeSave(NoticeSaveDto.builder()
                .dataJson(JSON.toJSONString(data))
                .id(noticeId)
                .title(build.getTitle())
                .isConfirm(isConfirm)
                .type(attendanceNoticeModel.getAttendanceNoticeEnum())
                .userId(UserProvider.getLoginUserId())
                .confirmList(Objects.equals(isConfirm, 0) ? null : JSON.toJSONString(initNoticeConfirm(recipientList)))
                .build());
        sendNotice(attendanceNoticeModel.getTenantId(), notice.getContext(data), build, isConfirm, recipientList, noticeId, attendanceNoticeModel.getModuleId());

    }

    private void sendNotice(String tenantId, String context, SystemNoticeStrategy systemNoticeStrategy, Integer isConfirm, List<String> recipientList, String noticeId,String moduleId) {
        if (CollUtil.isEmpty(recipientList)) {
            log.error("考勤发送系统通知记录id[{}],接收人为空", noticeId);
            return;
        }
        SingleSendRobotNoticeForm form = new SingleSendRobotNoticeForm();
        form.setRobotTypeEnum(ImRobotTypeEnum.FTB_XZS);
        form.setMessageAttributionRobotMpId(MP_ID);
        form.setToUserIds(recipientList);
        form.setTenantId(tenantId);
        SendRobotNoticeDataForm robotNoticeDataForm = new SendRobotNoticeDataForm();
        robotNoticeDataForm.setLogo(ATTENDANCE_APP_LOGO);//固定图片
        robotNoticeDataForm.setAppName(systemNoticeStrategy.getNoticeModuleEnum().getMsg());
        robotNoticeDataForm.setTitle(systemNoticeStrategy.getTitle());
        robotNoticeDataForm.setContent(context);
        robotNoticeDataForm.setContentSummary(systemNoticeStrategy.getTitle());
        LinkedList<JumpUrlListModel> objects = CollUtil.newLinkedList();
        if (Objects.equals(isConfirm, 1)) {
            objects.add(JumpUrlListModel.builder()
                    .displayMethodEnum(JumpUrlListModel.DisplayMethodEnum.FALSE)
                    .reqMethod(JumpUrlListModel.ReqMethodEnum.GET)
                    .type(1)
                    .url(String.format(ATTENDANCE_NOTICE_CONFIRM_LIST_VIEW_URL, noticeId))
                    .buttonName(ATTENDANCE_NOTICE_CONFIRM_LIST_BUTTON_NAME)
                    .mpId(MP_ID)
                    .buttonColor("#1A1A1A")
                    .build());
            objects.add(JumpUrlListModel.builder()
                    .type(2)
                    .isConfirm(1)
                    .confirmButton(ConfirmButton.builder().status(1)
                            .buttName1("确认收到")
                            .color1("#3C6DF8")
                            .url1(String.format(ATTENDANCE_NOTICE_CONFIRM_URL, noticeId))
                            .buttName2("已收到")
                            .color2("#D9D9DB")
                            .url2("")
                            .build())
                    .displayMethodEnum(JumpUrlListModel.DisplayMethodEnum.FALSE)
                    .reqMethod(JumpUrlListModel.ReqMethodEnum.POST)
                    .buttonName(ATTENDANCE_NOTICE_CONFIRM)
                    .url("")
                    .build());

        } else {
            List<JumpUrl> jumpUrls = systemNoticeStrategy.getJumpUrls();
            if (CollUtil.isEmpty(jumpUrls)) {
                log.error("考勤发送系统通知记录id[{}],未设置按钮事件", noticeId);
                return;
            }
            int size = jumpUrls.size();
            jumpUrls.forEach(jumpUrl -> objects.add(JumpUrlListModel.builder()
                    .reqMethod(JumpUrlListModel.ReqMethodEnum.GET)
                    .displayMethodEnum(size > 1 ? JumpUrlListModel.DisplayMethodEnum.FALSE : JumpUrlListModel.DisplayMethodEnum.TRUE)
                    .type(Objects.isNull(jumpUrl.getType()) ? 1 : jumpUrl.getType())
                    .url(jumpUrl.getUrl())
                    .mpId(StringUtil.isNotBlank(jumpUrl.getMpId()) ? jumpUrl.getMpId() : MP_ID)
                    .buttonName(jumpUrl.getUrlName())
                    .buttonColor(jumpUrl.getColor())
                    .nativeUrl(Objects.isNull(jumpUrl.getType()) ? null : NativeUrl.builder()
                            .page(jumpUrl.getPage())
                            .param(jumpUrl.getParam())
                            .build())
                    .build()));
        }
        robotNoticeDataForm.setJumpUrlList(objects);
        form.setRobotNoticeDataForm(robotNoticeDataForm);
//        log.error("打印消息内容form:{}", JSON.toJSONString(form));
        ActionResult actionResult = imRobotApi.sendSingleRobotNotice(form);
    }

    private List<NoticeConfirm> initNoticeConfirm(List<String> recipientList) {
        return recipientList.stream().map(userId -> NoticeConfirm.builder().userId(userId).confirmedTime(new Date()).isConfirmed(0).build()).collect(Collectors.toList());
    }

    public List<String> getRecipientForSelfAndChild(String groupId, Boolean isAdmin) {
        List<String> selfAndChildrenGroupIds = CollUtil.newArrayList(groupId);
        if (isAdmin) {
            List<AttendanceGroupAdminVo> attendanceGroupAdminVos = attendanceManagerPermissionMapper.queryGroupUsers(selfAndChildrenGroupIds);
            List<String> adminUserIds = attendanceGroupAdminVos.stream().map(AttendanceGroupAdminVo::getUserId).collect(Collectors.toList());
            if (CollUtil.isEmpty(adminUserIds)) {
                return Collections.emptyList();
            }
            return getUserIdsForFilterStatus(adminUserIds, UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE, UserSettingEnum.ATTENDANCE_SETTING_ATTENDANCE_GROUP_RULE_CHANGE_REMINDER);
        }
        Date date = new Date();
        List<AttendanceGroupUser> attendanceGroupUsers = attendanceUserService.queryByUsersAndGroupFilterSecondment(date, date, null, selfAndChildrenGroupIds);
        List<String> userIds = attendanceGroupUsers.stream().map(AttendanceGroupUser::getUserId).collect(Collectors.toList());
        if (CollUtil.isEmpty(userIds)) {
            return Collections.emptyList();
        }
        List<String> userIdsForFilterStatus = getUserIdsForFilterStatus(userIds, UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE, UserSettingEnum.ATTENDANCE_SETTING_ATTENDANCE_GROUP_RULE_CHANGE_REMINDER);
        return userIdsForFilterStatus;
    }

    /**
     * 根据配置多个code来过滤出开关都开启的用户集合
     *
     * @param userIds
     * @param settingCodes
     * @return
     */
    public List<String> getUserIdsForFilterStatus(List<String> userIds, UserSettingEnum... settingCodes) {
        // 判断前置 开启考勤消息提醒 开启极速打卡成功提醒
        List<String> userSettingList = new ArrayList<>();
        Arrays.stream(settingCodes).forEach(v -> userSettingList.add(v.getCode()));
        if (CollUtil.isEmpty(userIds)) {
            return Collections.emptyList();
        }
        List<UserSettingVo> settingList = attendanceUserSettingService.getSettingList(userIds, UserSettingTypeEnum.USER.getCode(), userSettingList);
        Map<String, List<UserSettingVo>> collect = settingList.stream().collect(Collectors.groupingBy(UserSettingVo::getAssociationId));
        userSettingList.clear();
        collect.forEach((userId, settings) -> {
            if (settings.stream().allMatch(setting -> Objects.equals(setting.getStatus(), 1))) {
                userSettingList.add(userId);
            }
        });
        return userSettingList;
    }

    public boolean checkBeforeCondition(String userId, UserSettingEnum... settingCodes) {

        // 判断前置 开启考勤消息提醒 开启极速打卡成功提醒
        List<String> userSettingList = new ArrayList<>();
        Arrays.stream(settingCodes).forEach(v -> userSettingList.add(v.getCode()));
        if (StringUtil.isEmpty(userId)) {
            return false;
        }
        List<UserSettingVo> settingList = attendanceUserSettingService.getSettingList(List.of(userId), UserSettingTypeEnum.USER.getCode(), userSettingList);
        if (null == settingList || settingList.isEmpty()) {
            return false;
        }
        Map<String, UserSettingVo> map = settingList.stream().collect(Collectors.toMap(UserSettingVo::getCode, Function.identity()));
        boolean result = true;
        for (String code : userSettingList) {
            result = checkRule(code, map);
            if (!result) {
                break;
            }
        }
        return result;
    }

    private boolean checkRule(String code, Map<String, UserSettingVo> map) {
        switch (code) {
            case UserSettingEnum.MESSAGE_RECEIVE:
            case UserSettingEnum.SPEED_CHECK_SUCCESS_REMINDER:
            case UserSettingEnum.MISSING_CHECKIN_REMINDER:
            case UserSettingEnum.MISSING_END_WORK_REMINDER:
            case UserSettingEnum.CLASS_ABSENCE_REMINDER:
            case UserSettingEnum.DAILY_REPORT:
            case UserSettingEnum.PERSONAL_MONTHLY_REPORT:
            case UserSettingEnum.ATTENDANCE_GROUP_LOCK_UNLOCK_NOTICE:
            case UserSettingEnum.CLASS_CHANGE_REMINDER:
            case UserSettingEnum.PRE_WORK_REMINDER:
            case UserSettingEnum.END_WORK_REMINDER:
            case UserSettingEnum.ATTENDANCE_RESULT_CHANGE_REMINDER:
                UserSettingVo absenceSetting = map.get(code);
                if (null == absenceSetting) {
                    return false;
                } else {
                    return absenceSetting.getStatus().equals(ConstantUtil.NUM_TRUE);
                }
            default:
                return true;
        }
    }
}
