package cn.iocoder.yudao.module.smartfactory.controller.admin.attendance;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.smartfactory.controller.admin.attendance.vo.AttendanceRecordVO;
import cn.iocoder.yudao.module.smartfactory.controller.admin.attendance.vo.StaffAttendanceRecordReqVO;
import cn.iocoder.yudao.module.smartfactory.controller.admin.attendance.vo.StaffAttendanceRecordRespVO;
import cn.iocoder.yudao.module.smartfactory.controller.admin.attendance.vo.StaffAttendanceRecordSaveReqVO;
import cn.iocoder.yudao.module.smartfactory.dal.dataobject.attendance.StaffAttendanceRecordDO;
import cn.iocoder.yudao.module.smartfactory.dal.dataobject.factoryinfo.FactoryInfoDO;
import cn.iocoder.yudao.module.smartfactory.dal.dataobject.staff.StaffDO;
import cn.iocoder.yudao.module.smartfactory.service.attendance.StaffAttendanceRecordService;
import cn.iocoder.yudao.module.smartfactory.service.factoryinfo.FactoryInfoService;
import cn.iocoder.yudao.module.smartfactory.service.staff.StaffService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;

@Tag(name = "管理后台 - 厂区员工考勤记录")
@RestController
@RequestMapping("/smartfactory/staff-attendance-record")
@Validated
public class StaffAttendanceRecordController {

    @Resource
    private StaffAttendanceRecordService staffAttendanceRecordService;

    @Resource
    private StaffService staffService;

    @Resource
    private FactoryInfoService factoryInfoService;

    @PostMapping("/create")
    @Operation(summary = "创建厂区员工考勤记录")
    @PreAuthorize("@ss.hasPermission('smartfactory:staff-attendance-record:create')")
    public CommonResult<Boolean> createStaffAttendanceRecord(@Valid @RequestBody List<StaffAttendanceRecordSaveReqVO> createReqVO) {
        staffAttendanceRecordService.createStaffAttendanceRecord(createReqVO);
        return success(true);
    }

    @PutMapping("/update")
    @Operation(summary = "更新厂区员工考勤记录")
    @PreAuthorize("@ss.hasPermission('smartfactory:staff-attendance-record:update')")
    public CommonResult<Boolean> updateStaffAttendanceRecord(@Valid @RequestBody List<StaffAttendanceRecordSaveReqVO> updateReqVO) {
        staffAttendanceRecordService.updateStaffAttendanceRecord(updateReqVO);
        return success(true);
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除厂区员工考勤记录")
    @Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('smartfactory:staff-attendance-record:delete')")
    public CommonResult<Boolean> deleteStaffAttendanceRecord(@RequestParam("id") Long id) {
        staffAttendanceRecordService.deleteStaffAttendanceRecord(id);
        return success(true);
    }

    @GetMapping("/get")
    @Operation(summary = "获得指定员工考勤记录")
    @Parameter(name = "staffId", description = "员工编号", required = true, example = "1024")
    @Parameter(name = "month", description = "月份", required = true, example = "2025-02")
    @Parameter(name = "type", description = "考勤类型", required = true, example = "1")
    @PreAuthorize("@ss.hasPermission('smartfactory:staff-attendance-record:query')")
    public CommonResult<List<StaffAttendanceRecordRespVO>> getStaffAttendanceRecord(@RequestParam("staffId") Long staffId,
                                                                                    @RequestParam("month") String month,
                                                                                    @RequestParam("type") Integer type) {

        List<StaffAttendanceRecordDO> staffAttendanceRecord = staffAttendanceRecordService.getRecord(staffId, month, type);
        Map<Long, List<StaffAttendanceRecordDO>> recordMap = convertMultiMap(staffAttendanceRecord, StaffAttendanceRecordDO::getFactoryId);

        // 获取厂区信息
        List<FactoryInfoDO> factoryDOS = factoryInfoService.getFactoryList(convertSet(staffAttendanceRecord, StaffAttendanceRecordDO::getFactoryId));
        Map<Long, FactoryInfoDO> factoryMap = convertMap(factoryDOS, FactoryInfoDO::getId);

        // 获取员工信息
        StaffDO staffDO = staffService.getStaff(staffId);

        List<StaffAttendanceRecordRespVO> respVO = staffAttendanceRecord.stream()
                .map(recordDO -> new StaffAttendanceRecordRespVO(
                        recordDO.getStaffId(),
                        recordDO.getFactoryId(),
                        recordDO.getType(),
                        recordDO.getMonth()))
                .distinct()
                .collect(Collectors.toList());
        respVO.forEach(vo -> {
            // 设置员工名称
            vo.setStaffName(staffDO.getNickName());
            // 设置工种
            vo.setWorkTypeId(staffDO.getWorkTypeId());
            // 设置厂区名称
            vo.setFactoryName(factoryMap.get(vo.getFactoryId()) != null ? factoryMap.get(vo.getFactoryId()).getName() : null);
            if (recordMap.containsKey(vo.getFactoryId())) {
                vo.setRecords(BeanUtils.toBean(recordMap.get(vo.getFactoryId()), AttendanceRecordVO.class));
            }
        });

        return success(respVO);
    }

    @GetMapping("/get-type")
    @Operation(summary = "获得厂区考勤类型")
    @Parameter(name = "factoryId", description = "工厂编号", required = true, example = "1024")
    @Parameter(name = "month", description = "考勤月份", required = true, example = "2025-11")
    @PreAuthorize("@ss.hasPermission('smartfactory:staff-attendance-record:query')")
    public CommonResult<Integer> getStaffAttendanceRecord(@RequestParam("factoryId") Long factoryId,
                                                          @RequestParam("month") String month) {
        return success(staffAttendanceRecordService.getType(factoryId, month));
    }

    @GetMapping("/isReview")
    @Operation(summary = "获得厂区员工考勤记录审核状态")
    @Parameter(name = "factoryId", description = "工厂编号", required = true, example = "1024")
    @Parameter(name = "month", description = "考勤月份", required = true, example = "2025-11")
    @PreAuthorize("@ss.hasPermission('smartfactory:staff-attendance-record:query')")
    public CommonResult<Integer> getIsReview(@RequestParam("factoryId") Long factoryId,
                                             @RequestParam("month") String month) {

        // 获取考勤审核状态
        return success(staffAttendanceRecordService.getIsReview(factoryId, month));
    }

    @GetMapping("/list")
    @Operation(summary = "获得厂区员工考勤记录列表")
    @PreAuthorize("@ss.hasPermission('smartfactory:staff-attendance-record:query')")
    public CommonResult<List<StaffAttendanceRecordRespVO>> getStaffAttendanceRecordPage(@Valid StaffAttendanceRecordReqVO reqVO) {
        // 查询所选厂区得考勤记录
        List<StaffAttendanceRecordDO> recordDOS = staffAttendanceRecordService.getStaffAttendanceRecordList(reqVO);
        // 查询该厂区员工在 其他厂区得考勤记录
        List<StaffAttendanceRecordDO> otherRecordDOS = staffAttendanceRecordService.getOtherRecord(reqVO);

        // 获取工厂员工列表
        List<StaffDO> staffDOS = staffService.getListByFactory(reqVO.getFactoryId(), true);
        Map<Long, StaffDO> staffMap = convertMap(staffDOS, StaffDO::getId);

        if (CollUtil.isNotEmpty(recordDOS)) {
            List<StaffAttendanceRecordRespVO> recordRespVO = staffAttendanceRecordService.convertRecord(reqVO, recordDOS, otherRecordDOS);

            // 筛选掉已经存在的员工
            List<Long> staffIds = staffDOS.stream()
                    .map(StaffDO::getId)
                    .filter(id -> !convertList(recordDOS, StaffAttendanceRecordDO::getStaffId).contains(id))
                    .collect(Collectors.toList());

            // 获取其他员工的考勤记录， 打卡状态设置为null
            List<AttendanceRecordVO> otherRecords = recordRespVO.get(0).getRecords().stream()
                    .map(record -> BeanUtils.toBean(record, AttendanceRecordVO.class)
                            .setStatus(null))
                    .collect(Collectors.toList());
            List<StaffAttendanceRecordRespVO> otherRespVO = staffIds.stream()
                    .map(id -> new StaffAttendanceRecordRespVO()
                            .setStaffId(id)
                            .setFactoryId(reqVO.getFactoryId())
                            .setMonth(reqVO.getMonth())
                            .setType(reqVO.getType())
                            .setStaffName(staffMap.get(id).getNickName())
                            .setWorkTypeId(staffMap.get(id).getWorkTypeId())
                            .setRecords(otherRecords))
                    .collect(Collectors.toList());

            recordRespVO.addAll(otherRespVO);
            return success(recordRespVO);
        }else {
            // 判断是否 新增考勤情况
            if (reqVO.getFactoryId() != null && reqVO.getMonth() != null && reqVO.getType() != null) {

                if (reqVO.getStaffId() != null) {
                    // 获取员工信息
                    StaffDO staffDO = staffService.getStaff(reqVO.getStaffId());

                    StaffAttendanceRecordRespVO respVO = new StaffAttendanceRecordRespVO()
                            .setStaffId(reqVO.getStaffId())
                            .setFactoryId(reqVO.getFactoryId())
                            .setMonth(reqVO.getMonth())
                            .setType(reqVO.getType())
                            .setStaffName(staffDO.getNickName())
                            .setWorkTypeId(staffDO.getWorkTypeId());
                    return success(Collections.singletonList(respVO));
                }else {
                    List<StaffAttendanceRecordRespVO> respVO = staffDOS.stream()
                            .map(staffDO -> new StaffAttendanceRecordRespVO()
                                    .setStaffId(staffDO.getId())
                                    .setFactoryId(reqVO.getFactoryId())
                                    .setMonth(reqVO.getMonth())
                                    .setType(reqVO.getType())
                                    .setStaffName(staffDO.getNickName())
                                    .setWorkTypeId(staffDO.getWorkTypeId()))
                            .collect(Collectors.toList());

                    return success(respVO);
                }
            }

            return success(null);
        }
    }

    @GetMapping("/export-excel")
    @Operation(summary = "导出厂区员工考勤记录 Excel")
    @PreAuthorize("@ss.hasPermission('smartfactory:staff-attendance-record:export')")
    @OperateLog(type = EXPORT)
    public void exportStaffAttendanceRecordExcel(@Valid StaffAttendanceRecordReqVO reqVO,
              HttpServletResponse response) throws IOException {

        List<StaffAttendanceRecordDO> recordDOS = staffAttendanceRecordService.getStaffAttendanceRecordList(reqVO);
        // 导出 Excel
        ExcelUtils.write(response, "厂区员工考勤记录.xls", "数据", StaffAttendanceRecordRespVO.class,
                staffAttendanceRecordService.convertRecord(reqVO, recordDOS, null));
    }

    @PutMapping("/review")
    @Operation(summary = "考勤记录审核")
    @Parameter(name = "factoryId", description = "工厂编号", required = true, example = "1024")
    @Parameter(name = "month", description = "考勤月份", required = true, example = "2025-11")
    @PreAuthorize("@ss.hasPermission('smartfactory:staff-attendance-record:review')")
    public CommonResult<Boolean> reviewAttendanceRecord(@RequestParam("factoryId") Long factoryId,
                                                        @RequestParam("month") String month) {

        staffAttendanceRecordService.updateReview(factoryId, month);
        return success(true);
    }
}