package jnpf.workflow.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.bean.ChangeConfig;
import jnpf.attendance.mapper.AttendanceClockInResultMapper;
import jnpf.attendance.service.AttendanceClockInResultService;
import jnpf.attendance.service.AttendanceDailyRuleService;
import jnpf.attendance.service.handle.notice.AttendanceNoticeHandler;
import jnpf.base.service.SuperServiceImpl;
import jnpf.constants.AttendanceConstant;
import jnpf.engine.vo.ApproverByTaskIdAndNodeIdVo;
import jnpf.entity.attendance.AttendanceClockInResult;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.entity.workflow.ApplyAttendanceChange;
import jnpf.enums.attendance.ApprovalSettingTypeEnum;
import jnpf.enums.attendance.AttendanceNoticeEnum;
import jnpf.enums.attendance.ClockInStatusEnum;
import jnpf.exception.QueryException;
import jnpf.model.attendance.vo.attendance.ApproveBaseImVo;
import jnpf.model.attendance.vo.attendance.ApproveImVo;
import jnpf.model.attendance.vo.attendance.AttendanceApproveImVo;
import jnpf.model.workflow.dto.ApplyAttendanceChangeDto;
import jnpf.model.workflow.vo.ApplyAttendanceChangeVo;
import jnpf.permission.UserApi;
import jnpf.permission.model.user.BaseUserInfoVo;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.*;
import jnpf.workflow.mapper.ApplyAttendanceChangeMapper;
import jnpf.workflow.service.ApplyAttendanceChangeService;
import jnpf.workflow.service.FlowTaskService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


/**
 * 出勤变更
 *
 * @author yanwenfu
 * @create 2023-12-11
 */
@Service
public class ApplyAttendanceChangeServiceImpl extends SuperServiceImpl<ApplyAttendanceChangeMapper, ApplyAttendanceChange> implements ApplyAttendanceChangeService {
    @Resource
    private AttendanceClockInResultService attendanceClockInResultService;
    @Resource
    private AttendanceDailyRuleService attendanceDailyRuleService;
    @Resource
    private FlowTaskService flowTaskService;
    @Autowired
    private UserAntifreeze userAntifreeze;
    @Autowired
    private UserApi userApi;
    @Autowired
    private AttendanceNoticeHandler attendanceNoticeHandler;
    @Autowired
    private RedisUtil redisUtil;
    @Resource
    private CustomTenantUtil customTenantUtil;
    @Resource
    private ChangeConfig changeConfig;
    @Resource
    private AttendanceClockInResultMapper attendanceClockInResultMapper;

    @Override
    public ApplyAttendanceChangeVo getApplyAttendanceChange(String id) {

        ApplyAttendanceChange applyAttendanceChange = this.getById(id);
        return JsonUtil.getJsonToBean(applyAttendanceChange, ApplyAttendanceChangeVo.class);
    }

    @Override
    public void save(ApplyAttendanceChange entity, ApplyAttendanceChangeDto applyAttendanceChangeDto) throws Exception {

        int count = attendanceClockInResultMapper.getReplyingCount(applyAttendanceChangeDto.getClockInResultId());
        if (count > 0) {
            throw new QueryException("当前记录正在审批中，请审批结束后再重新执行操作");
        }
        //查询班次信息
        AttendanceClockInResult clockInResult = attendanceClockInResultService.lambdaQuery()
                .eq(AttendanceClockInResult::getId, applyAttendanceChangeDto.getClockInResultId())
                .eq(AttendanceClockInResult::getDeleteMark,0)
                .last("limit 1").one();
        if (null == clockInResult) {
            throw new QueryException("当天班次已变更，请重新发起！");
        }
        // 查询出勤规则
        FtbAttendanceDailyRule dailyRule = attendanceDailyRuleService.getById(clockInResult.getRuleId());
        if (null == dailyRule) {
            throw new QueryException("当天班次已变更，请重新发起！");
        }
        // 判定当前变更是否合法
        if (!applyAttendanceChangeDto.getChangeType().equals(ClockInStatusEnum.ROLLBACK.getValue())) {
            List<ClockInStatusEnum> clockInStatusEnums = changeConfig.getChangeMap().get(clockInResult.getClockInType()).get(ClockInStatusEnum.getClockInStatusEnum(clockInResult.getClockInStatus()));
            if (null == clockInStatusEnums || !clockInStatusEnums.contains(ClockInStatusEnum.getClockInStatusEnum(applyAttendanceChangeDto.getChangeType()))) {
                throw new Exception("无法变更为指定的状态");
            }
        }
        // 查询变更用户信息
        BaseUserInfoVo user = userApi.getUserInfoById(clockInResult.getUserId());
        entity.setChangeUserId(user.getUserId());
        entity.setChangeUserName(user.getUserName());
        entity.setApplyDate(new Date());
        // 变更结果为单个, 变更上班则将下班时间置空, 变更下班置空上班
        if (clockInResult.getClockInType().equals(ConstantUtil.ON_WORK)) {
            entity.setOnWorkTime(dailyRule.getInPoint());
            entity.setOffWorkTime(null);
        } else {
            entity.setOnWorkTime(null);
            entity.setOffWorkTime(dailyRule.getOutPoint());
        }
        entity.setId(applyAttendanceChangeDto.getTaskId());
        save(entity);
        updateClockInResult(entity.getId(), entity.getClockInResultId(), entity.getChangeType());
        //sendToIm(clockInResult.getClockInType(),entity, userProvider.get().getTenantId());
    }

    private void updateClockInResult(String id, String clockInResultId, Integer changeType) {

        AttendanceClockInResult clockInResult = attendanceClockInResultService.getById(clockInResultId);
        LambdaUpdateWrapper<AttendanceClockInResult> updateWrapper = new LambdaUpdateWrapper<AttendanceClockInResult>()
                .set(AttendanceClockInResult::getApplyType, ConstantUtil.APPLY_CHANGE)
                .set(AttendanceClockInResult::getApplyId, id)
                // .set(AttendanceClockInResult::getAbsenceLeader, userProvider.get().getUserId())
                .eq(AttendanceClockInResult::getDeleteMark, ConstantUtil.NUM_FALSE)
                .eq(AttendanceClockInResult::getId, clockInResult.getId());
        attendanceClockInResultService.update(updateWrapper);
    }

    @Override
    public void submit(String id, ApplyAttendanceChange entity, ApplyAttendanceChangeDto applyAttendanceChangeDto) {
        //查询班次信息
        AttendanceClockInResult clockInResult = attendanceClockInResultService.lambdaQuery()
                .eq(AttendanceClockInResult::getId, applyAttendanceChangeDto.getClockInResultId())
                .eq(AttendanceClockInResult::getDeleteMark,0)
                .last("limit 1").one();
        if (entity.getChangeType().equals(3) || entity.getChangeType().equals(4)) {
            if (clockInResult.getClockInType().equals(ConstantUtil.ON_WORK)) {
                entity.setOffWorkTime(null);
            } else {
                entity.setOnWorkTime(null);
            }
        }
        //表单信息
        if (StringUtil.isEmpty(entity.getId())) {
            entity.setId(id);
            save(entity);
            //sendToIm(clockInResult.getClockInType(), entity, userProvider.get().getTenantId());
        } else {
            entity.setId(id);
            updateById(entity);
        }
        updateClockInResult(entity.getId(), entity.getClockInResultId(), entity.getChangeType());
    }

    private void sendToIm(Integer clockInType, ApplyAttendanceChange entity, String tenantId) {
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.schedule(() -> {
            customTenantUtil.checkOutTenant(tenantId);
            ApproverByTaskIdAndNodeIdVo data = flowTaskService.getApproveInfo(entity.getId(), null, tenantId, null);
            if (null == data) {
                return;
            }
            AttendanceApproveImVo approveIm = JsonUtil.getJsonToBean(data, AttendanceApproveImVo.class);
            approveIm.setId(data.getTaskId());
            List<PartUserInfoVo> userList = userAntifreeze.getAllByIds(List.of(entity.getCreatorUserId()), tenantId);
            PartUserInfoVo userInfo = userList.stream().findFirst().orElse(null);
            // 组装消息
            ApproveImVo approveImVo = new ApproveImVo(tenantId, AttendanceNoticeEnum.APPROVE);
            String content = "%s的【出勤变更】审批";
            String title = String.format(content, null != userInfo ? userInfo.getRealName() : "--");
            ApproveBaseImVo imDetail = new ApproveBaseImVo(title, ApprovalSettingTypeEnum.ACTION_RESULT.getCode(), entity.getChangeUserName(),
                    getRuleTime(clockInType,entity), getResult(entity.getClockInResultId()), getChangeResult(entity.getChangeType()));
            data.getUserOperators().forEach(v -> {
                approveIm.setTaskId(v.getTaskOperatorId());
                approveImVo.setUserIds(List.of(v.getUserId()));
                String encode = FtbUtil.encodeJson(approveIm);
                String url = AttendanceConstant.APPROVE_URL + encode;
                imDetail.setUrl(url);
                approveImVo.setApproveBaseImVo(imDetail);
                attendanceNoticeHandler.send(approveImVo);
                redisUtil.insert(ConstantUtil.APPROVE_NOTICE_CHANGE + approveIm.getId(), JSONUtil.toJsonStr(approveImVo));
            });
        }, 1, TimeUnit.SECONDS);
        scheduler.shutdown();
    }

    private String getChangeResult(Integer changeType) {

        switch (changeType) {
            case 1:
                return "旷工";
            case 2:
                return "撤销旷工";
            case 3:
                return "正常";
            case 4:
                return "补卡";
            default:
                return "--";
        }
    }

    private String getRuleTime(Integer clockInType, ApplyAttendanceChange entity) {
        switch (entity.getChangeType()) {
            case 1:
            case 2:
                return DateDetail.getDate2Str(entity.getOnWorkTime(), DateDetail.DF9) + "-" + DateDetail.getDate2Str(entity.getOffWorkTime(), DateDetail.DF10);
            case 3:
            case 4:
                return clockInType.equals(ConstantUtil.ON_WORK)? DateDetail.getDate2Str(entity.getOnWorkTime(), DateDetail.DF9):DateDetail.getDate2Str(entity.getOffWorkTime(), DateDetail.DF9);
            default:
                return "变更类型不正确";
        }
    }

    private String getResult(String resultId) {

        AttendanceClockInResult clockInResult = attendanceClockInResultService.getById(resultId);
        if (null != clockInResult.getAbsence() && clockInResult.getAbsence().equals(ConstantUtil.NUM_TRUE)) {
            return ClockInStatusEnum.ABSENCE.getDescription();
        } else {
            switch (clockInResult.getClockInStatus()) {
                case -1:
                    return ClockInStatusEnum.NO_CLOCK.getDescription();
                case 1:
                    return ClockInStatusEnum.NORMAL.getDescription();
                case 2:
                    return ClockInStatusEnum.WORK_LATE.getDescription();
                case 3:
                    return ClockInStatusEnum.HOME_EARLY.getDescription();
                default:
                    return "--";
            }
        }
    }
}
