package jnpf.attendance.controller;

import jnpf.aspect.FtbApiCallLog;
import jnpf.attendance.FtbClockInApi;
import jnpf.attendance.service.AttendanceClockInService;
import jnpf.attendance.service.DailyRuleChangeService;
import jnpf.base.ActionResult;
import jnpf.base.UserInfo;
import jnpf.enums.personnel.FtbPersonnelsCheckStatusCodeEnum;
import jnpf.exception.QueryException;
import jnpf.model.attendance.dto.ClockInDto;
import jnpf.model.attendance.dto.NoApprovalDto;
import jnpf.model.attendance.vo.*;
import jnpf.util.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 打卡控制器
 *
 * @author yanwenfu
 * @create 2023-11-21
 */
@Slf4j
@RestController
@RequestMapping(value = "/attendance/clockIn")
public class AttendanceClockInController implements FtbClockInApi {

    @Resource
    private AttendanceClockInService attendanceClockInService;

    @Resource
    private UserProvider userProvider;

    @Resource
    private CustomTenantUtil customTenantUtil;

    @Resource
    private DailyRuleChangeService dailyRuleChangeService;

    /**
     * 打卡 - 主页
     * @return jnpf.base.ActionResult<java.util.List<jnpf.model.attendance.vo.GroupInfoVo>>
     */
    @GetMapping(value = "/mainInfo")
    public ActionResult<List<GroupInfoVo>> getClockInMainInfo(@RequestParam(required = false) String day) throws Exception {

        try {
            Date date = StringUtils.isEmpty(day) ? new Date() : DateDetail.getStr2Date10(day);
            List<GroupInfoVo> list = attendanceClockInService.getClockInMainInfo(date, userProvider.get(), ConstantUtil.NUM_TRUE);
            return ActionResult.success(list);
        } catch (QueryException e) {
            if (e.getMessage().equals("当前用户暂无考勤组")) {
                return ActionResult.success(e.getMessage());
            } else {
                throw new QueryException(e.getMessage());
            }
        }
    }

    /**
     * 查询考勤组审批列表
     * @param queryDto 查询条件
     * @return jnpf.base.ActionResult<jnpf.model.attendance.vo.GroupApprovalVo>
     */
    @PostMapping(value = "/group-approval/list")
    public ActionResult<List<GroupApprovalVo>> getGroupApprovalList(@RequestBody ApprovalQueryDto queryDto) {

        List<GroupApprovalVo> list = attendanceClockInService.getGroupApprovalList(queryDto);
        return ActionResult.success(list);
    }

    /**
     * 打卡
     * @return java.lang.Object
     */
    @FtbApiCallLog(name = "考勤打卡")
    @PostMapping(value = "/record")
    public Object clockIn(@RequestBody @Valid ClockInDto clockInDto) throws Exception {

        MutablePair<Integer, String> pair = attendanceClockInService.clockIn(clockInDto);
        return ActionResult.success(pair.getLeft());
    }

    /**
     * 更新打卡记录
     * @param clockInId 打卡id
     * @return java.lang.Object
     */
    @PutMapping(value = "/record/{clockInId}")
    public Object updateClockIn(@PathVariable(value = "clockInId") String clockInId, @RequestBody @Valid ClockInDto clockInDto) throws Exception {

        MutablePair<Integer, String> pair = attendanceClockInService.updateClockIn(clockInId, clockInDto);
        return ActionResult.success(pair.getLeft());
    }

    @PostMapping(value = "/testChangeRule")
    public void changeAttendanceRule(@RequestBody List<UserDayVo> userDayList) {

        UserInfo userInfo = userProvider.get();
        attendanceClockInService.changeAttendanceRuleBatch(userDayList, userInfo);
    }

    /**
     * 外勤打卡
     * @param applyId 审批id
     */
    @GetMapping(value = "/outside")
    public Object outsideClockIn(@RequestParam(value = "taskId") String applyId, @RequestParam(value = "clockInId", required = false) String clockInId) throws Exception {

        UserInfo user = userProvider.get();
        ActionResult<Void> actionResult = new ActionResult<>();
        try {
            attendanceClockInService.outsideClockIn(applyId, user.getUserId(), clockInId);
        } catch (Exception e) {
            actionResult.setCode(FtbPersonnelsCheckStatusCodeEnum.CHECK_REFUSE.getCode());
            actionResult.setMsg(e.getMessage());
            return actionResult;
        }
        actionResult.setCode(FtbPersonnelsCheckStatusCodeEnum.CHECK_PASS.getCode());
        actionResult.setMsg(FtbPersonnelsCheckStatusCodeEnum.CHECK_PASS.getMsg());
        return actionResult;
    }

    /**
     * 外勤打卡审批(通过/不通过/撤回)
     * @param applyId 审批id
     * @param passed - 是否通过(0: 否, 1: 是, 2: 撤回) <br>
     */
    @GetMapping(value = "/outside/approval")
    public Object approvalOutsideClockIn(@RequestParam(value = "taskId") String applyId, @RequestParam(value = "passed") String passed) throws Exception {

        UserInfo userInfo = userProvider.get();
        ActionResult<Void> actionResult = new ActionResult<>();
        try {
            attendanceClockInService.approvalOutsideClockIn(applyId, passed, userInfo);
        } catch (Exception e) {
            actionResult.setCode(FtbPersonnelsCheckStatusCodeEnum.CHECK_REFUSE.getCode());
            actionResult.setMsg(e.getMessage());
            return actionResult;
        }
        actionResult.setCode(FtbPersonnelsCheckStatusCodeEnum.CHECK_PASS.getCode());
        actionResult.setMsg(FtbPersonnelsCheckStatusCodeEnum.CHECK_PASS.getMsg());
        return actionResult;
    }

    /**
     * 异常打卡审批(通过/不通过/撤回)
     * @param applyId 审批id
     * @param passed - 是否通过(0: 否, 1: 是, 2: 撤回) <br>
     */
    @GetMapping(value = "/unusual-phone/approval")
    public Object unusualPhoneClockIn(@RequestParam(value = "taskId") String applyId, @RequestParam(value = "passed") String passed) throws Exception {

        UserInfo userInfo = userProvider.get();
        ActionResult<Void> actionResult = new ActionResult<>();
        try {
            attendanceClockInService.approvalUnusualPhoneClockIn(applyId, passed, userInfo);
        } catch (Exception e) {
            actionResult.setCode(FtbPersonnelsCheckStatusCodeEnum.CHECK_REFUSE.getCode());
            actionResult.setMsg(e.getMessage());
            return actionResult;
        }
        actionResult.setCode(FtbPersonnelsCheckStatusCodeEnum.CHECK_PASS.getCode());
        actionResult.setMsg(FtbPersonnelsCheckStatusCodeEnum.CHECK_PASS.getMsg());
        return actionResult;
    }

    /**
     * 生成用户补卡次数记录
     * @param tenantId 租户id
     * @param groupId 考勤组id
     * @param userId 用id
     * @param type 生成类型(1: 新增组成员, 2: 借调到新组)
     * @return java.lang.Object
     */
    @GetMapping(value = "/generateRepairNum/{tenantId}")
    @NoDataSourceBind
    public Object generateRepairNumForUser(@PathVariable(value = "tenantId") String tenantId, @RequestParam String groupId, @RequestParam String userId, @RequestParam Integer type) {

        customTenantUtil.checkOutTenant(tenantId);
        boolean b = attendanceClockInService.generateRepairNumForUser(groupId, userId, type);
        return ActionResult.success(b);
    }

    /**
     * 扫描是否有未执行的班次变更任务
     * @return java.lang.Object
     */
    @GetMapping(value = "/daily-rule-change/execute")
    public Boolean dailyRuleChangeExecute() {

        return dailyRuleChangeService.dailyRuleChangeExecute();
    }

    /**
     * 补卡
     * @param applyId 审批id
     * @param passed 是否通过(0: 否, 1: 是, 2: 撤回)
     */
    @GetMapping(value = "/repair")
    public ActionResult<Void> repairClockIn(@RequestParam(value = "taskId") String applyId, @RequestParam(value = "passed") String passed) {

        log.error("补卡入参 -> applyId: {}, passed: {}", applyId, passed);
        UserInfo userInfo = userProvider.get();
        String approveUserId = userInfo.getUserId();
        ActionResult<Void> actionResult = new ActionResult<>();
        try {
            attendanceClockInService.repairClockIn(applyId, passed, approveUserId, userInfo.getTenantId());
        } catch (Exception e) {
            actionResult.setCode(FtbPersonnelsCheckStatusCodeEnum.CHECK_REFUSE.getCode());
            actionResult.setMsg(e.getMessage());
            return actionResult;
        }
        actionResult.setCode(FtbPersonnelsCheckStatusCodeEnum.CHECK_PASS.getCode());
        actionResult.setMsg(FtbPersonnelsCheckStatusCodeEnum.CHECK_PASS.getMsg());
        return actionResult;
    }

    /**
     * 出勤变更
     * @param tenantId 租户id
     * @param applyId 申请id
     * @param passed 是否通过(0: 否, 1: 是, 2: 撤回)
     */
    @GetMapping(value = "/change")
    @NoDataSourceBind
    public void attendanceChange(@RequestParam(value = "tenantId") String tenantId, @RequestParam(value = "applyId") String applyId,
                                 @RequestParam(value = "passed") String passed, @RequestParam(value = "approveUserId") String approveUserId) throws Exception {

        log.error("出勤变更 -> tenantId: {}, applyId: {}, passed: {}", tenantId, applyId, passed);
        customTenantUtil.checkOutTenant(tenantId, approveUserId);
        attendanceClockInService.attendanceChange(applyId, passed, approveUserId,tenantId);
    }

    /**
     * 出勤变更(不审批)
     * @param noApprovalDto 出勤变更无需审批dto
     * @return java.lang.Object
     */
    @PutMapping(value = "/change/noApproval")
    public Object attendanceChangeNoApproval(@RequestBody @Valid NoApprovalDto noApprovalDto) throws Exception {

        attendanceClockInService.attendanceChangeNoApproval(noApprovalDto.getClockInResultId(), noApprovalDto.getChangeType());
        return ActionResult.success();
    }

    /**
     * 可选择的补卡列表
     * @param userId 用户id
     * @return jnpf.base.ActionResult<java.util.List<jnpf.model.attendance.vo.AbnormalClockInVo>>
     */
    @GetMapping(value = "/repair/list/{userId}")
    public ActionResult<List<GroupRepairVo>> getRepairList(@PathVariable(value = "userId") String userId) throws Exception {

        List<GroupRepairVo> list = attendanceClockInService.getRepairList(userId);
        return ActionResult.success(list);
    }

    /**
     * 执行打卡旷工逻辑
     * @return java.lang.Boolean
     */
    @Override
    @PostMapping(value = "/absenceRecord")
    public Boolean generateFtbAbsenceRecord(@RequestParam(value = "tenantId") String tenantId) {
        return attendanceClockInService.generateFtbAbsenceRecord(tenantId);
    }

    /**
     * 生成打卡旷工任务
     * @return java.lang.Boolean
     */
    @Override
    @PostMapping(value = "/absenceTask")
    public Boolean generateAbsenceTask(@RequestParam(value = "tenantId") String tenantId) {
        return attendanceClockInService.generateAbsenceTask(ConstantUtil.NUM_TRUE, tenantId);
    }

    /**
     * 生成打卡提醒记录
     * @return java.lang.Boolean
     */
    @Override
    @PostMapping(value = "/remindRecord")
    public Boolean generateBeforeWorkRemind(@RequestParam(value = "tenantId") String tenantId) {
        return attendanceClockInService.generateBeforeWorkRemind(tenantId);
    }

    /**
     * 生成补卡次数
     * @param tenantId 租户id
     * @return java.lang.Boolean
     */
    @Override
    @PostMapping(value = "/repairNum")
    public Boolean generateRepairNum(@RequestParam(value = "tenantId") String tenantId) {
        return attendanceClockInService.generateRepairNum();
    }

    /**
     * 判定连续动作(排班/旷工)
     * @param tenantId 租户id
     * @return java.lang.Boolean
     */
    @Override
    @PostMapping(value = "/continuousCheck")
    public Boolean continuousCheck(@RequestParam(value = "tenantId") String tenantId) {
        return attendanceClockInService.continuousCheck(tenantId);
    }

    /**
     * 临时调用
     * @return java.lang.Boolean
     */
    @NoDataSourceBind
    @PostMapping(value = "/repairNum/all")
    public Boolean generateRepairNumAll(@RequestParam String tenantId) {
        customTenantUtil.checkOutTenant(tenantId);
        return attendanceClockInService.generateRepairNumAll();
    }

    /**
     * 临时调用
     */
    @PostMapping(value = "/test/{tenantId}")
    public void test(@PathVariable(value = "tenantId") String tenantId) {

        attendanceClockInService.generateFtbAbsenceRecord(tenantId);
    }

    /**
     * 查询每日出勤及打卡记录
     * @param userId 用户id
     * @param queryDate 查询日期
     * @param currentGroupId 当前考勤组
     * @return jnpf.base.ActionResult<java.util.List<jnpf.model.attendance.vo.MiniGroupVo>>
     */
    @GetMapping(value = "/dailyClockInRecord")
    public ActionResult<List<MiniGroupVo>> getDailyClockInRecord(@RequestParam(value = "userId") String userId,
                                                                                                    @RequestParam(value = "queryDate") String queryDate,
                                                                                                    @RequestParam(value = "currentGroupId") String currentGroupId) {

        List<MiniGroupVo> list = attendanceClockInService.getDailyClockInRecord(userId, queryDate, currentGroupId);
        return ActionResult.success(list);
    }

    /**
     * 查询每日出勤及打卡记录 - v2
     * @param userId 用户id
     * @param queryDate 查询日期
     * @param currentGroupId 当前考勤组
     * @return jnpf.base.ActionResult<jnpf.model.attendance.vo.DailyInfoVo>
     */
    @GetMapping(value = "/dailyClockInRecord/v2")
    public ActionResult<DailyInfoVo> getDailyClockInRecordV2(@RequestParam(value = "userId") String userId,
                                                             @RequestParam(value = "queryDate") String queryDate,
                                                             @RequestParam(value = "currentGroupId") String currentGroupId,
                                                             @RequestParam(value = "queryOldData", required = false) Integer queryOldData) throws QueryException {

        queryOldData = null == queryOldData ? 0 : queryOldData;
        DailyInfoVo dailyInfoVo = attendanceClockInService.getDailyClockInRecordV2(userId, queryDate, currentGroupId, queryOldData);
        return ActionResult.success(dailyInfoVo);
    }

    /**
     * 查询考勤组补卡规则
     * @param groupId 考勤组id
     * @return jnpf.base.ActionResult<java.lang.Boolean>
     */
    @GetMapping(value = "/clockInRepair/rule/{groupId}")
    public ActionResult<RepairRuleVo> getClockInRepairRule(@PathVariable(value = "groupId") String groupId) {

        RepairRuleVo rule = attendanceClockInService.getClockInRepairCheck(groupId);
        return ActionResult.success(rule);
    }
}
