package jnpf.attendance.controller;


import cn.hutool.core.collection.CollUtil;
import io.swagger.v3.oas.annotations.Operation;
import jnpf.attendance.AttendanceDailyRuleApi;
import jnpf.attendance.service.AttendanceDailyRuleService;
import jnpf.attendance.service.AttendanceLeaveRulesService;
import jnpf.base.ActionResult;
import jnpf.entity.attendance.ApplyParam;
import jnpf.enums.attendance.AttendanceTypeEnum;
import jnpf.enums.attendance.v2.ClockOutHandleParam;
import jnpf.exception.HandleException;
import jnpf.model.attendance.dto.LineDrawingSchedulesConfigDto;
import jnpf.model.attendance.dto.SchedulesImportDto;
import jnpf.model.attendance.dto.SchedulesSetDto;
import jnpf.model.attendance.dto.UnifiedSchedulesDto;
import jnpf.model.attendance.dto.UserDayShiftQueryDto;
import jnpf.model.attendance.vo.DayReceivableRevenueVo;
import jnpf.model.attendance.vo.DayShiftRevenueStatVo;
import jnpf.model.attendance.vo.ScheduleRuleDetailVo;
import jnpf.model.attendance.vo.SchedulesV2Vo;
import jnpf.model.attendance.vo.attendance.OvertimeRuleDetailVo;
import jnpf.model.attendance.vo.LineSchedulesVo;
import jnpf.model.attendance.vo.UserDayShiftInfoVo;
import jnpf.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * 排班规则
 *
 * @author ahua
 * @since 2023-11-22
 */
@RestController
@RequestMapping("/arranging/work")
@Slf4j
public class AttendanceDailyRuleController implements AttendanceDailyRuleApi {
    @Resource
    private CustomTenantUtil customTenantUtil;
    @Autowired
    private AttendanceDailyRuleService attendanceDailyRuleService;
    @Autowired
    private AttendanceLeaveRulesService attendanceLeaveRulesService;

    /**
     * 根据指定条件查询某个群体在特定月份的调度情况
     *
     * @param groupId   群体ID，用于标识特定的群体
     * @param realName  真实姓名，用于筛选特定的个人
     * @param month     月份，格式为YYYY-MM，用于指定查询的时间范围
     * @param userIds   用户ID列表，用于限定查询的用户范围
     * @param isSchedules   是否仅查询已调度的记录，true表示仅查询已调度记录，false表示查询所有记录
     * @return 返回根据条件查询到的调度情况结果
     */
    @GetMapping(value = "/schedulesExport")
    public ActionResult<Boolean> schedulesExport(@RequestParam String groupId, @RequestParam(required = false) String workGroupId, @RequestParam(required = false) String realName, @RequestParam String month, @RequestParam(required = false) List<String> userIds, @RequestParam(required = false, defaultValue = "1") Integer isSchedules) {
        attendanceDailyRuleService.schedulesExport(groupId, workGroupId, realName, month, userIds, isSchedules);
        return ActionResult.success();
    }

    /**
     * 划线排班导出
     *
     * @param groupId     考勤组id
     * @param workGroupId 班组ID
     * @param month       月份
     * @param userIdList  用户ID列表
     * @return
     */
    @GetMapping(value = "/lineSchedulesExport")
    public ActionResult<Boolean> lineSchedulesExport(@RequestParam String groupId, @RequestParam(required = false) String workGroupId, @RequestParam String month, @RequestParam(required = false) List<String> userIdList) {
        attendanceDailyRuleService.lineSchedulesExport(groupId, workGroupId, month, userIdList);
        return ActionResult.success();
    }

    /**
     * 排班导入
     *
     * @param schedulesImportDto    参数
     * @return
     */
    @PostMapping(value = "/schedulesImport")
    public ActionResult<List<SchedulesV2Vo>> schedulesImport(@RequestBody SchedulesImportDto schedulesImportDto) throws IOException {
        return ActionResult.success(attendanceDailyRuleService.schedulesImport(schedulesImportDto));
    }

    /**
     * 划线排班导入
     *
     * @param schedulesImportDto    参数
     * @return
     */
    @PostMapping(value = "/lineSchedulesImport")
    public ActionResult lineSchedulesImport(@RequestBody SchedulesImportDto schedulesImportDto) throws IOException {
        attendanceDailyRuleService.lineSchedulesImport(schedulesImportDto);
        return ActionResult.success();
    }

    /**
     * 晚走晚到
     *
     * @return
     */
    @GetMapping(value = "/clockOutHandle")
    public ActionResult clockOutHandle(@RequestParam String userId, @RequestParam String tenantId, @RequestParam String clockOut, @RequestParam String clockInTime) {
        ClockOutHandleParam param = new ClockOutHandleParam();
        param.setUserId(userId);
        param.setTenantId(tenantId);
        param.setAttendanceType(AttendanceTypeEnum.ORDINARY.getCode());
        param.setStart(DateUtil.stringToDate(clockOut));
        param.setEnd(DateUtil.stringToDate(clockInTime));
        param.setApplyId("");
        param.setRuleId("");
        param.setDay(new Date());
        OvertimeRuleDetailVo overtimeRuleDetailVo = new OvertimeRuleDetailVo();
        overtimeRuleDetailVo.setOvertimeType(1);
        overtimeRuleDetailVo.setMinOvertimeMinute(30);
        overtimeRuleDetailVo.setEnabled(1);
        overtimeRuleDetailVo.setCalcMethod(3);
        overtimeRuleDetailVo.setTimeUnit(1);
        overtimeRuleDetailVo.setCompensateRatio(BigDecimal.ONE);
        overtimeRuleDetailVo.setCompensateType(1);
        param.setRuleDetail(overtimeRuleDetailVo);
        attendanceDailyRuleService.workOvertimeNotApprove(param);
        return ActionResult.success();
    }

    /**
     * 获取排班列表V2版本。
     *
     * @param groupId     考勤组id
     * @param workGroupId     班组ID
     * @param realName    真实姓名（可选）
     * @param month       月份
     * @param userIds     用户ID列表（可选）
     * @param isSchedules 是否排班标识（可选，默认值为1）
     * @return 排班列表V2版本视图对象
     */
    @GetMapping("v2")
    public ActionResult<List<SchedulesV2Vo>> getSchedulesListV2(@RequestParam String groupId, @RequestParam(required = false) String workGroupId, @RequestParam(required = false) String realName, @RequestParam String month, @RequestParam(required = false) List<String> userIds, @RequestParam(required = false, defaultValue = "1") Integer isSchedules) {
        return ActionResult.success(attendanceDailyRuleService.getSchedulesListV2(groupId, workGroupId, realName, month, userIds, isSchedules));
    }

    /**
     * 获取排班列表 V2（按开始日期、结束日期，其它参数与 v2 一致）
     */
    @GetMapping("v2/range")
    public ActionResult<List<SchedulesV2Vo>> getSchedulesListV2ByDateRange(@RequestParam String groupId, @RequestParam(required = false) String workGroupId, @RequestParam(required = false) String realName, @RequestParam String startDate, @RequestParam String endDate, @RequestParam(required = false) List<String> userIds, @RequestParam(required = false, defaultValue = "1") Integer isSchedules) {
        return ActionResult.success(attendanceDailyRuleService.getSchedulesListV2ByDateRange(groupId, workGroupId, realName, startDate, endDate, userIds, isSchedules));
    }

    /**
     * 预排班草稿转排班列表 V2（按员工 + 日期区间）；草稿 Redis 不存在时返回空列表。
     */
    @GetMapping("v2/preSchedule/draft")
    public ActionResult<List<SchedulesV2Vo>> getSchedulesListV2ByPreScheduleDraft(
            @RequestParam String groupId,
            @RequestParam String startDate,
            @RequestParam String endDate,
            @RequestParam String draftId) {
        return ActionResult.success(
                attendanceDailyRuleService.getSchedulesListV2ByPreScheduleDraft(
                        groupId, startDate, endDate, draftId));
    }

    /**
     * 根据ID获取排班规则详情。
     *
     * @param id 排班规则ID
     * @return 排班规则详情视图对象
     * @throws HandleException 处理异常
     */
    @GetMapping("{id}")
    public ActionResult<ScheduleRuleDetailVo> getSchedulesList(@PathVariable String id) throws HandleException {
        return ActionResult.success(attendanceDailyRuleService.getDetail(id));
    }

    /**
     * 设置排班。
     *
     * @param schedulesSets 排班设置列表
     * @return 处理结果字符串
     * @throws HandleException 处理异常
     */
    @PostMapping
    public ActionResult<String> setSchedules(@RequestBody List<SchedulesSetDto> schedulesSets) throws HandleException {
        return ActionResult.success(attendanceDailyRuleService.setSchedules(schedulesSets));
    }

    /**
     * 自己排班调整排班
     *
     * @param shiftId 班次id
     * @return
     */
    @GetMapping("/selfSchedules")
    public ActionResult<String> setSchedulesForSelfSchedules(@RequestParam("shiftId") String shiftId) throws HandleException {
        return ActionResult.success(attendanceDailyRuleService.setSchedulesForSelfSchedules(shiftId));
    }

    /**
     * 定时执行初始化下个月固定排班。
     */
    @PostMapping("initFixedScheduleRule")
    public ActionResult initFixedScheduleRule(@RequestParam("tenantId") String tenantId) {
        attendanceDailyRuleService.initFixedScheduleRule(tenantId);
        return ActionResult.success();
    }

    /**
     * 处理日常规则申请。
     *
     * @param applyParam 申请参数类
     * @return 处理结果字符串
     * @throws HandleException 处理异常
     */
    @PostMapping("applyDailyRuleHandle")
    public ActionResult applyDailyRuleHandle(@RequestBody ApplyParam applyParam) throws HandleException {
        return ActionResult.success(attendanceDailyRuleService.applyDailyRuleHandle(applyParam));
    }

    /**
     * 处理借调申请日规则。
     *
     * @param userId        借调用户ID
     * @param fromGroupId   原考勤组ID
     * @param toGroupId     借调考勤组ID
     * @param start         开始时间
     * @param end           结束时间
     * @param departureTime 离岗时间
     * @param backTime      回岗时间
     * @return 处理结果视图对象
     * @throws HandleException 处理异常
     */
    @PostMapping("secondmentDailyRuleHandle")
    public ActionResult secondmentDailyRuleHandle(@RequestParam String userId, @RequestParam String fromGroupId, @RequestParam String toGroupId, @RequestParam String start, @RequestParam String end, @RequestParam String departureTime, @RequestParam String backTime) throws HandleException {
        return ActionResult.success(attendanceDailyRuleService.secondmentDailyRuleHandle(CollUtil.newArrayList(userId), fromGroupId, toGroupId, DateDetail.getStr2DateTime(start), DateDetail.getStr2DateTime(end), DateDetail.getStr2DateTime(departureTime), DateDetail.getStr2DateTime(backTime), "yawentest2"));
    }

    /**
     * 自动授予假期余额。
     *
     * @param tenantId 租户ID
     * @return 处理结果视图对象
     */
    @PostMapping("autoGrantBalance")
    public ActionResult autoGrantBalance(@RequestParam("tenantId") String tenantId) {
        // 2.0 节日不发劵了
//        attendanceFestivalSettingService.autoGrantBalance();
        //  需要修改
//        attendanceHolidaySettingService.autoGrantBalance(tenantId);
        attendanceLeaveRulesService.autoGrantBalance(tenantId);

        return ActionResult.success();
    }

    /**
     * 用户是否排班
     *
     * @param tenantId 租户ID
     * @param userId   用户ID
     * @return
     */
    @Override
    @NoDataSourceBind
    @GetMapping("userIsScheduling")
    public ActionResult<Boolean> userIsScheduling(@RequestParam("tenantId") String tenantId, @RequestParam("userId") String userId) {
        customTenantUtil.checkOutTenant(tenantId);
        return ActionResult.success(attendanceDailyRuleService.userIsScheduling(userId));
    }

    /**
     * 用户是否排班
     *
     * @return
     */
    @PostMapping("userIsSchedulingOrdinary")
    @Override
    public ActionResult<List<String>> userIsSchedulingOrdinary(@RequestBody List<String> organizeIds) {
        return ActionResult.success(attendanceDailyRuleService.userIsSchedulingOrdinary(organizeIds));
    }

    /**
     *
     * @param userId
     * @param start
     * @param end
     * @return
     */
    @GetMapping("hasRuleByUserIdAndTime")
    @Override
    public ActionResult<Boolean> hasRuleByUserIdAndTime(@RequestParam String userId, @RequestParam Date start, @RequestParam Date end) {
        return ActionResult.success(attendanceDailyRuleService.hasRuleByUserIdAndTime(userId, start, end));
    }
    /**
     * 设置划线排班
     *
     * @param configDto 划线排班配置DTO
     * @return 处理结果
     * @throws HandleException 处理异常
     */
    @PostMapping("lineDrawingSchedules")
    public ActionResult<String> setLineDrawingSchedules(@RequestBody LineDrawingSchedulesConfigDto configDto) throws HandleException {
        return ActionResult.success(attendanceDailyRuleService.setLineDrawingSchedules(configDto));
    }

    /**
     * 统一排班接口（支持固定排班和划线排班）
     *
     * @param dto 统一排班DTO
     * @return 处理结果
     * @throws HandleException 处理异常
     */
    @PostMapping("unifiedSchedules")
    public ActionResult<String> setUnifiedSchedules(@RequestBody UnifiedSchedulesDto dto) throws HandleException {
        return ActionResult.success(attendanceDailyRuleService.setUnifiedSchedules(dto));
    }

    /**
     * 指定用户日期是否存在划线排班
     *
     * @param configDto 划线排班配置DTO
     * @return 处理结果
     */
    @PostMapping("queryLineSchedulingExist")
    public ActionResult<Boolean> queryLineSchedulingExist(@RequestBody LineDrawingSchedulesConfigDto configDto) {
        return ActionResult.success(attendanceDailyRuleService.queryLineSchedulingExist(configDto));
    }

    /**
     * 获取划线排班列表
     *
     * @param groupId         考勤组id
     * @param workGroupId     班组ID
     * @param dayList         日期列表
     * @param finalUserIdList 用户ID列表
     * @return 划线排班列表
     */
    @GetMapping("getLineSchedulesList")
    public ActionResult<List<LineSchedulesVo>> getLineSchedulesList(@RequestParam String groupId, @RequestParam(required = false) String workGroupId, @RequestParam(required = false) String dayList, @RequestParam(required = false) List<String> finalUserIdList) {
        return ActionResult.success(attendanceDailyRuleService.getLineSchedulesList(groupId, workGroupId, Arrays.asList(StringUtil.split(dayList, ",")), finalUserIdList));
    }

    /**
     * 查询指定用户指定日期的班次信息，包含有效请假及普班
     *
     * @param queryDto 查询参数（用户ID、查询日期）
     * @return 用户指定日期的班次信息
     */
    /**
     * 按自然日查询考勤组所属门店营业额预估
     *
     * @param groupId   考勤组ID
     * @param startTime 开始日期（含），yyyy-MM-dd
     * @param endTime   结束日期（含），yyyy-MM-dd
     */
    @Operation(summary = "按自然日查询考勤组营业额预估")
    @GetMapping("/group-receivable-revenue-by-day")
    public ActionResult<List<DayReceivableRevenueVo>> listReceivableRevenueByDay(
            @RequestParam String groupId,
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date startTime,
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date endTime) {
        return ActionResult.success(attendanceDailyRuleService.listReceivableRevenueByDay(groupId, startTime, endTime));
    }

    @Operation(summary = "查询指定用户指定日期的班次信息")
    @PostMapping("/user-day-shift-info")
    public ActionResult<UserDayShiftInfoVo> getUserDayShiftInfo(@Valid @RequestBody UserDayShiftQueryDto queryDto) {
        try {
            log.info("查询用户指定日期班次信息，userId=>{}, queryDate=>{}", 
                    queryDto.getUserId(), DateUtil.dateToString(queryDto.getQueryDate(), "yyyy-MM-dd"));
            long st = System.currentTimeMillis();
            
            UserDayShiftInfoVo result = attendanceDailyRuleService.getUserDayShiftInfo(
                    queryDto.getUserId(), 
                    queryDto.getQueryDate());
            
            long ent = System.currentTimeMillis();
            log.info("查询用户指定日期班次信息完成，耗时=>{} 毫秒", ent - st);
            return ActionResult.success(result);
        } catch (Exception e) {
            log.error("查询用户指定日期班次信息异常", e);
            return ActionResult.fail("查询失败：" + e.getMessage());
        }
    }
}

