package jnpf.attendance.service;

import jnpf.base.UserInfo;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceClockInResult;
import jnpf.entity.attendance.FtbAttendanceClockIn;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.exception.HandleException;
import jnpf.exception.QueryException;
import jnpf.model.attendance.dto.ClockInDto;
import jnpf.model.attendance.model.DayClockRange;
import jnpf.model.attendance.vo.*;
import jnpf.model.attendance.vo.attendance.ClockInExportVo;
import jnpf.model.common.DateRangeDto;
import org.apache.commons.lang3.tuple.MutablePair;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * 打卡服务
 *
 * @author yanwenfu
 * @create 2023-11-21
 */
public interface AttendanceClockInService extends SuperService<FtbAttendanceClockIn> {

    /**
     * 打卡 - 主页
     * @param today 日期
     * @param userInfo 用户信息
     * @param isMainInfo 是否打卡主页(1: 是, 0: 否)
     * @return java.util.List<jnpf.model.attendance.vo.GroupInfoVo>
     */
    List<GroupInfoVo> getClockInMainInfo(Date today, UserInfo userInfo, Integer isMainInfo) throws Exception;

    /**
     * 打卡
     *
     * @param clockInDto   打卡信息
     * @return org.apache.commons.lang3.tuple.MutablePair <br> left:打卡结果状态, right:打卡结果id
     */
    MutablePair<Integer, String> clockIn(ClockInDto clockInDto) throws Exception;

    /**
     * 更新打卡记录
     * @param clockInDto 更新内容
     * @param clockInId 打卡记录id
     * @return org.apache.commons.lang3.tuple.MutablePair <br> left:打卡结果状态, right:打卡结果id
     */
    MutablePair<Integer, String> updateClockIn(String clockInId, ClockInDto clockInDto) throws Exception;

    /**
     * 判断本次是否外出打卡
     * @param rule 考勤规则
     * @param clockInType 上/下班打卡
     * @return boolean
     */
    boolean getOutsideCheck(AttendanceRuleVo rule, Integer clockInType);

    /**
     * 变更出勤规则[批量]
     * @param userDayList 用户日期列表
     * @param user 操作人
     */
    void changeAttendanceRuleBatch(List<UserDayVo> userDayList, UserInfo user);

    /**
     * 查询出勤规则
     * @param ruleId 出勤规则id
     * @return jnpf.model.attendance.vo.AttendanceRuleVo
     */
    AttendanceRuleVo getAttendanceRule(String ruleId) throws HandleException;

    /**
     * 查询出勤规则[批量]
     * @param ruleIds 出勤规则ids
     * @return java.util.Map<java.lang.String,jnpf.model.attendance.vo.AttendanceRuleVo>
     */
    Map<String, AttendanceRuleVo> getAttendanceRuleBatch(List<String> ruleIds);

    /**
     * 查询考勤组信息
     * @param today 日期
     * @param groupId 考勤组id
     * @param selfGroupInt 是否自己的考勤组
     * @param userInfo 当前登陆用户
     * @return jnpf.model.attendance.vo.GroupInfoVo
     */
    GroupInfoVo getGroupInfo(Date today, String groupId, int selfGroupInt, UserInfo userInfo) throws QueryException;

    /**
     * 查询考勤组信息
     * @param today 日期
     * @param groupId 考勤组id
     * @param selfGroupInt 是否自己的考勤组
     * @param userInfo 当前登陆用户
     * @param isMainInfo 是否主页进入
     * @return jnpf.model.attendance.vo.GroupInfoVo
     */
    GroupInfoVo getGroupInfo(Date today, String groupId, int selfGroupInt, UserInfo userInfo, Integer isMainInfo) throws QueryException;

    /**
     * 查询考勤组出勤规则
     * @param groupId 考勤组id
     * @param userId 用户id
     * @return jnpf.model.attendance.vo.GroupRuleVo
     */
    GroupRuleVo getGroupRule(String groupId, String userId);

    /**
     * 能否补卡
     * @param day 日期
     * @param clockInResult 出勤结果
     * @param approvalStatus 审批状态
     * @param groupRule 考勤组规则
     * @return org.apache.commons.lang3.tuple.MutablePair<java.util.Date, java.util.Date>
     */
    MutablePair<Date, Date> couldRepairRecord(Date day, AttendanceClockInResult clockInResult, Integer approvalStatus, GroupRuleVo groupRule) throws Exception;

    /**
     * 根据日期查询考勤组信息
     * @param today 日期
     * @param userInfo 当前登陆用户
     * @return jnpf.model.attendance.vo.GroupInfoVo
     */
    GroupInfoVo getGroupInfoByDate(Date today, UserInfo userInfo) throws QueryException;

    /**
     * 外勤打卡
     * @param approvalCode 审批code
     * @param tenantId 租户id
     * @param clockInId 打卡id
     */
    void outsideClockIn(String approvalCode, String tenantId, String clockInId) throws Exception;

    /**
     * 外勤打卡审批(通过/不通过/撤回)
     * @param applyId 审批id
     * @param passed 是否通过(0: 否, 1: 是, 2: 撤回)
     * @param userInfo 当前登录人
     */
    void approvalOutsideClockIn(String applyId, String passed, UserInfo userInfo) throws Exception;

    /**
     * 异常打卡审批(通过/不通过/撤回)
     * @param applyId 审批id
     * @param passed 是否通过(0: 否, 1: 是, 2: 撤回)
     * @param userInfo 当前登录人
     */
    void approvalUnusualPhoneClockIn(String applyId, String passed, UserInfo userInfo) throws Exception;

    /**
     * 补卡
     * @param applyId 审批id
     * @param passed 是否通过(0: 否, 1: 是, 2: 撤回)
     * @param tenantId 租户ID
     */
    void repairClockIn(String applyId, String passed, String approveUserId, String tenantId) throws Exception;

    /**
     * 执行缺卡逻辑
     * @param tenantId 租户id
     * @return java.lang.Boolean
     */
    Boolean generateFtbAbsenceRecord(String tenantId);

    /**
     * 生成上班前打卡提醒
     * @param tenantId 租户id
     * @return java.lang.Boolean
     */
    Boolean generateBeforeWorkRemind(String tenantId);

    /**
     * 异步处理缺卡
     * @param tenantId 租户id
     * @param conditionList 需要执行的任务
     * @param now 当前时间
     */
    CompletableFuture<Void> asyncDeal(String tenantId, String hashKey, List<AbsenceClockInVo> conditionList, String now);

    /**
     * 可选择的补卡列表
     * @param userId 用户id
     * @return java.util.List<jnpf.model.attendance.vo.GroupRepairVo>
     */
    List<GroupRepairVo> getRepairList(String userId) throws Exception;

    /**
     * 查询每日出勤及打卡记录
     * @param userId 用户id
     * @param queryDate 查询日期
     * @param currentGroupId 当前考勤组
     * @return java.util.List<jnpf.model.attendance.vo.MiniGroupVo>
     */
    List<MiniGroupVo> getDailyClockInRecord(String userId, String queryDate, String currentGroupId);

    /**
     * 出勤变更
     * @param applyId 申请id
     * @param passed 是否通过(0: 否, 1: 是, 2: 撤回)
     * @param approveUserId 审批人id
     * @param tenantId 租户ID
     */
    void attendanceChange(String applyId, String passed, String approveUserId, String tenantId) throws HandleException;

    /**
     * 出勤变更(不审批)
     * @param clockInResultId 打卡结果id
     * @param changeType 变更类型(1: 变更为旷工, 2: 撤销旷工, 3: 变更为正常, 4: 补卡)
     */
    void attendanceChangeNoApproval(String clockInResultId, Integer changeType) throws HandleException;

    /**
     * 查询每日出勤及打卡记录 - v2
     * @param userId 用户id
     * @param queryDate 查询日期
     * @param currentGroupId 当前考勤组id
     * @param queryOldData 查看原始数据(1: 是, 0: 否)
     * @return jnpf.model.attendance.vo.DailyInfoVo
     */
    DailyInfoVo getDailyClockInRecordV2(String userId, String queryDate, String currentGroupId, Integer queryOldData) throws QueryException;

    /**
     * 获取班次时间
     * @param rule 出勤规则
     * @param workStatus 上/下班
     * @return java.lang.String
     */
    String getShiftTimeStr(FtbAttendanceDailyRule rule, int workStatus);

    /**
     * 生成补卡次数
     * @return java.lang.Boolean
     */
    Boolean generateRepairNum();

    /**
     * 生成用户补卡次数记录
     * @param groupId 考勤组id
     * @param userId 用户id
     * @param generateType 生成类型(1: 新增组成员, 2: 借调到新组)
     * @return java.lang.Boolean
     */
    Boolean generateRepairNumForUser(String groupId, String userId, Integer generateType);

    /**
     * 判断考勤组是否可以补卡
     * @param groupId 考勤组id
     * @return jnpf.model.attendance.vo.RepairRuleVo
     */
    RepairRuleVo getClockInRepairCheck(String groupId);

    /**
     * 生成全面维修编号
     * 本方法旨在生成一个全面的维修编号，该编号用于唯一标识一次维修事件或记录
     * 它可能涉及到复杂的逻辑，如数据库查询、序列生成或其他策略，以确保编号的唯一性和连续性
     *
     * @return Boolean 表示维修编号是否成功生成true表示成功，false表示失败
     */
    Boolean generateRepairNumAll();

    /**
     * 查询每日出勤及打卡记录
     * @param userId 用户id
     * @param clockRecord 查询日期范围
     */
    List<FtbAttendanceClockIn> getDailyClockInRecord(String userId, DayClockRange clockRecord);

    /**
     * 判定连续动作(排班/旷工)
     * @param tenantId 租户id
     * @return java.lang.Boolean
     */
    Boolean continuousCheck(String tenantId);

    /**
     * 获取当前考勤组排班
     * @param today 日期
     * @param userInfo 日期
     */
    List<FtbAttendanceDailyRule> getCurrentDailyRuleListOfWithdraw(Date today, UserInfo userInfo);

    /**
     * 获取当前时间段内考勤组排班
     */
    List<FtbAttendanceDailyRule> getCurrentDailyRuleListOfDay(DateRangeDto dateRangeDto, List<ClockInExportVo> usersByGroupVos);

    /**
     * 生成打卡旷工任务
     * @param flag 是否删除redisKey重新生成(1: 是, 0: 否)
     * @param tenantId 租户id
     * @return java.lang.Boolean
     */
    Boolean generateAbsenceTask(Integer flag, String tenantId);

    /**
     * 查询考勤组审批列表
     * @param queryDto 查询条件
     * @return java.util.List<jnpf.model.attendance.vo.GroupApprovalVo>
     */
    List<GroupApprovalVo> getGroupApprovalList(ApprovalQueryDto queryDto);
}
