package com.mortals.xhx.module.attendance.web;

import cn.hutool.core.util.ReflectUtil;
import com.alibaba.fastjson.JSONObject;
import com.mortals.framework.annotation.Excel;
import com.mortals.framework.common.Rest;
import com.mortals.framework.exception.AppException;
import com.mortals.framework.model.OrderCol;
import com.mortals.framework.utils.ServletUtils;
import com.mortals.framework.web.BaseCRUDJsonBodyMappingController;
import com.mortals.xhx.base.system.param.service.ParamService;
import com.mortals.xhx.base.system.upload.service.UploadService;
import com.mortals.xhx.common.code.GoWorkResultEnum;
import com.mortals.xhx.common.code.NormalEnum;
import com.mortals.xhx.common.code.OffWorkResultEnum;
import com.mortals.xhx.common.code.YesNoEnum;
import com.mortals.xhx.module.attendance.model.*;
import com.mortals.xhx.module.attendance.model.vo.AttendStatInfo;
import com.mortals.xhx.module.attendance.service.AttendanceClassService;
import com.mortals.xhx.module.attendance.service.AttendanceExportRecordService;
import com.mortals.xhx.module.attendance.service.AttendanceGroupService;
import com.mortals.xhx.module.dept.model.DeptEntity;
import com.mortals.xhx.module.dept.model.DeptQuery;
import com.mortals.xhx.module.dept.service.DeptService;
import com.mortals.xhx.module.perform.model.PerformAttendAppealEntity;
import com.mortals.xhx.module.perform.model.vo.AppealInfo;
import com.mortals.xhx.module.staff.service.StaffService;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.mortals.framework.model.Context;

import com.mortals.xhx.module.attendance.service.AttendanceRecordService;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 考勤打卡记录信息
 *
 * @author zxfei
 * @date 2023-04-07
 */
@RestController
@RequestMapping("attendance/record")
public class AttendanceRecordController extends BaseCRUDJsonBodyMappingController<AttendanceRecordService, AttendanceRecordEntity, Long> {

    @Autowired
    private ParamService paramService;
    @Autowired
    private UploadService uploadService;

    @Autowired
    private AttendanceGroupService attendanceGroupService;

    @Autowired
    private DeptService deptService;

    @Autowired
    private AttendanceClassService attendanceClassService;
    @Autowired
    private StaffService staffService;
    @Autowired
    private AttendanceExportRecordService attendanceExportRecordService;
    @Autowired
    private AttendanceGroupService groupService;
    @Autowired
    private AttendanceClassService classService;

    public AttendanceRecordController() {
        super.setModuleDesc("考勤打卡记录信息");
    }

    @Override
    protected void init(Map<String, Object> model, Context context) {
        this.addDict(model, "deptId", deptService.find(new DeptQuery()).stream().collect(Collectors.toMap(x -> x.getId().toString(), y -> y.getDeptName())));
        this.addDict(model, "groupId", attendanceGroupService.find(new AttendanceGroupQuery()).stream().collect(Collectors.toMap(x -> x.getId().toString(), y -> y.getGroupName())));
        this.addDict(model, "classId", attendanceClassService.find(new AttendanceClassQuery()).stream().collect(Collectors.toMap(x -> x.getId().toString(), y -> y.getClassName())));
        this.addDict(model, "goWorkResult", GoWorkResultEnum.getEnumMap());
        this.addDict(model, "offWorkResult", OffWorkResultEnum.getEnumMap());
        this.addDict(model, "signInResult", NormalEnum.getEnumMap());
        this.addDict(model, "signOutResult", NormalEnum.getEnumMap());
        this.addDict(model, "punchResult", NormalEnum.getEnumMap());
        //设置
        super.init(model, context);
    }

    @Override
    public void doExportBefore(Context context, AttendanceRecordEntity query, List<String> properties) throws AppException {
        if (!ObjectUtils.isEmpty(query.getProperties())) {
          /*  //通过属性转换为注解
            List<Field> tempFields = new ArrayList<>();
            tempFields.addAll(Arrays.asList(ReflectUtil.getFields(AttendanceRecordEntity.class)));
            for (Field field : tempFields) {
                if (field.isAnnotationPresent(Excel.class)) {
                    Excel column = field.getAnnotation(Excel.class);
                    if (column != null && query.getProperties().contains(field.getName())) {
                        properties.add(column.name());
                    }
                }
            }*/

            properties.addAll(query.getProperties());
        }
    }

    @Override
    public void doExportAfter(Context context, List<AttendanceRecordEntity> list) throws AppException {
        ArrayList<AttendanceRecordEntity> attendanceRecordEntities = new ArrayList<>();

        for (AttendanceRecordEntity recordEntity : list) {
            List<AttendanceRecordDetailEntity> attendanceRecordDetailList = recordEntity.getAttendanceRecordDetailList();
            if (!ObjectUtils.isEmpty(attendanceRecordDetailList)) {
                for (AttendanceRecordDetailEntity detailEntity : attendanceRecordDetailList) {
                    AttendanceRecordEntity attendanceRecord = new AttendanceRecordEntity();
                    attendanceRecord.initAttrValue();
                    BeanUtils.copyProperties(recordEntity, attendanceRecord);
                    attendanceRecord.setAttendanceRecordDetailEntity(detailEntity);
                    attendanceRecordEntities.add(attendanceRecord);
                }
            } else {
                AttendanceRecordEntity attendanceRecord = new AttendanceRecordEntity();
                attendanceRecord.initAttrValue();
                BeanUtils.copyProperties(recordEntity, attendanceRecord);
                attendanceRecordEntities.add(attendanceRecord);
            }
        }

        if (!ObjectUtils.isEmpty(attendanceRecordEntities)) {
            list.clear();
            list.addAll(attendanceRecordEntities);
        }
    }


    @Override
    public void doExportFileAfter(byte[] data, AttendanceRecordEntity query, Context context) throws AppException {
        InputStream inputStream = new ByteArrayInputStream(data);
        MultipartFile file = ServletUtils.getMultipartFile(inputStream, "kaoqin.xlsx");
        String filePath = uploadService.saveFileUpload(file, "file/fileupload", null);
        AttendanceExportRecordEntity attendanceExportRecordEntity = new AttendanceExportRecordEntity();
        attendanceExportRecordEntity.initAttrValue();
        attendanceExportRecordEntity.setFilePath(filePath);
        if (query.getIdList() != null) {
            List<Long> idList = query.getIdList();
            attendanceExportRecordEntity.setRecordIdList(idList.stream().map(i -> i.toString()).collect(Collectors.joining(",")));
        }
        if (query.getAttendanceDateStart() != null) {
            String attendanceDate = query.getAttendanceDateStart() + "~" + query.getAttendanceDateEnd();
            attendanceExportRecordEntity.setAttendanceDate(attendanceDate);
        }
        if (!ObjectUtils.isEmpty(query.getAttendanceGroupId())) {
            AttendanceGroupEntity attendanceGroupEntity = groupService.get(query.getAttendanceGroupId());
            attendanceExportRecordEntity.setGroupName(attendanceGroupEntity == null ? "" : attendanceGroupEntity.getGroupName());
        }

        if (!ObjectUtils.isEmpty(query.getDeptId())) {
            DeptEntity deptEntity = deptService.get(query.getDeptId(), context);
            attendanceExportRecordEntity.setDeptName(deptEntity == null ? "" : deptEntity.getDeptName());
        }

        if (!ObjectUtils.isEmpty(query.getClassId())) {
            AttendanceClassEntity attendanceClassEntity = classService.get(query.getClassId(), context);
            attendanceExportRecordEntity.setClassName(attendanceClassEntity == null ? "" : attendanceClassEntity.getClassName());
        }
        attendanceExportRecordEntity.setCreateUserId(context.getUser().getId());
        attendanceExportRecordEntity.setCreateTime(new Date());
        attendanceExportRecordEntity.setType(2);
        attendanceExportRecordEntity.setExportOrImport(1);
        attendanceExportRecordService.save(attendanceExportRecordEntity);
    }


    @Override
    protected void doListBefore(AttendanceRecordEntity query, Map<String, Object> model, Context context) throws AppException {
        if (query.getClassId() != null) {
            query.setClassId(query.getClassId());
        }
        if (query.getGroupId() != null) {
            query.setAttendanceGroupId(query.getGroupId());
        }

        if (ObjectUtils.isEmpty(query.getOrderColList())) {
            query.setOrderColList(Arrays.asList(new OrderCol("attendanceDate", OrderCol.DESCENDING), new OrderCol("staffName", OrderCol.DESCENDING)));
        } else {
            query.getOrderColList().add(new OrderCol("attendanceDate", OrderCol.DESCENDING));
            // query.getOrderColList().add(new OrderCol("staffName", OrderCol.DESCENDING));
        }

        super.doListBefore(query, model, context);
    }

    @Override
    protected int doListAfter(AttendanceRecordEntity query, Map<String, Object> model, Context context) throws AppException {

        List<AttendanceRecordEntity> list = (List<AttendanceRecordEntity>) model.get(KEY_RESULT_DATA);
        List<AttendanceRecordDetailEntity> collect = list.parallelStream()
                .flatMap(item -> item.getAttendanceRecordDetailList().stream())
                .distinct()
                .sorted(Comparator.comparingInt(AttendanceRecordDetailEntity::getOrderNum))
                .collect(Collectors.toList());
        List<AttDsyncColumn> dsyncColumns = new ArrayList<>();
        collect.forEach(item -> {
            AttDsyncColumn attDsyncColumn = new AttDsyncColumn();
            attDsyncColumn.setName(String.format("上班%s打卡时间", item.getOrderNum()));
            attDsyncColumn.setProperty("goWorkDate");
            attDsyncColumn.setOrderNum(item.getOrderNum());
            dsyncColumns.add(attDsyncColumn);

            attDsyncColumn = new AttDsyncColumn();
            attDsyncColumn.setName(String.format("上班%s打卡结果", item.getOrderNum()));
            attDsyncColumn.setProperty("goWorkResult");
            attDsyncColumn.setOrderNum(item.getOrderNum());
            dsyncColumns.add(attDsyncColumn);

            attDsyncColumn = new AttDsyncColumn();
            attDsyncColumn.setName(String.format("下班%s打卡时间", item.getOrderNum()));
            attDsyncColumn.setProperty("offWorkDate");
            attDsyncColumn.setOrderNum(item.getOrderNum());
            dsyncColumns.add(attDsyncColumn);

            attDsyncColumn = new AttDsyncColumn();
            attDsyncColumn.setName(String.format("下班%s打卡结果", item.getOrderNum()));
            attDsyncColumn.setProperty("offWorkResult");
            attDsyncColumn.setOrderNum(item.getOrderNum());
            dsyncColumns.add(attDsyncColumn);
        });
        Set<Integer> dsyncSet = dsyncColumns.stream().map(i -> i.getOrderNum()).collect(Collectors.toSet());
        //填充空的detail 对象
        Iterator<AttendanceRecordEntity> iterator = list.iterator();
        while (iterator.hasNext()) {
            AttendanceRecordEntity recordEntity = iterator.next();

            Set<Integer> existSet = recordEntity.getAttendanceRecordDetailList().stream().map(i -> i.getOrderNum()).collect(Collectors.toSet());
            //判断详细列表中是否存在顺序 没有自动填充空对象数据
            List<AttendanceRecordDetailEntity> addDetailList = dsyncSet.stream().map(i -> {
                if (!existSet.contains(i)) {
                    AttendanceRecordDetailEntity recordDetailEntity = new AttendanceRecordDetailEntity();
                    recordDetailEntity.initAttrValue();
                    recordDetailEntity.setOrderNum(i);
                    return recordDetailEntity;
                }
                return null;
            }).filter(f -> f != null).collect(Collectors.toList());

            if (ObjectUtils.isEmpty(addDetailList)) {
                recordEntity.getAttendanceRecordDetailList().addAll(addDetailList);
                List<AttendanceRecordDetailEntity> orderList = recordEntity.getAttendanceRecordDetailList().stream().sorted(Comparator.comparingInt(AttendanceRecordDetailEntity::getOrderNum))
                        .collect(Collectors.toList());
                recordEntity.setAttendanceRecordDetailList(orderList);
            }
        }
        model.put("dyncColumns", dsyncColumns);
       /* //出勤情况
        //总人数
        Integer total = (Integer)model.get("total");
        //未出勤
        Integer noAtt = 0;
        //迟到
        Integer beLate = 0;
        //早退
        Integer leaveEarly = 0;
        //缺卡
        Integer lackOfCards = 0;
        for (AttendanceRecordEntity attendanceRecordEntity : list) {
            boolean a = true;
            for (AttendanceRecordDetailEntity item : attendanceRecordEntity.getAttendanceRecordDetailList()) {
                if (item.getGoWorkResult()==3){
                    lackOfCards=lackOfCards+1;
                }
                if (item.getGoWorkResult()==4){
                    beLate = beLate+1;
                }
                if (item.getOffWorkResult()==3){
                    lackOfCards=lackOfCards+1;
                }
                if (item.getOffWorkResult()==5){
                    leaveEarly = leaveEarly +1;
                }
                if (item.getGoWorkResult()!=3 || item.getOffWorkResult()!=3){
                    a  = false;
                }
            }
            if (a){
                noAtt = noAtt+1;
            }
        }

        String attPercentage = "";
        if (total!=0){
            float l = ((total - noAtt) / total)*100;
            attPercentage =l+"%";
        }else {
            attPercentage = "0";
        }
        AttendanceStatus attendanceStatus = new AttendanceStatus();
        attendanceStatus.setNeedAttNum(total);
        attendanceStatus.setAttPercentage(attPercentage);
        attendanceStatus.setNoAtt(noAtt);
        attendanceStatus.setBeLate(beLate);
        attendanceStatus.setLeaveEarly(leaveEarly);
        attendanceStatus.setLackOfCards(lackOfCards);
        model.put("attendanceStatus",attendanceStatus);*/

        return super.doListAfter(query, model, context);
    }


    /**
     * 每日统计
     */
    @PostMapping(value = "stat")
    public String statByDay() {
        JSONObject jsonObject = new JSONObject();
        String busiDesc = this.getModuleDesc() + "统计";
        try {
            Rest<AttendStatInfo> rest = this.service.statByDay(getContext());
            if (rest.getCode() == YesNoEnum.NO.getValue()) {
                throw new AppException("统计异常！");
            } else {
                jsonObject.put(KEY_RESULT_DATA, rest.getData());
            }
            recordSysLog(request, busiDesc + " 【成功】");
            jsonObject.put(KEY_RESULT_CODE, VALUE_RESULT_SUCCESS);
        } catch (Exception e) {
            log.error("申诉审核", e);
            jsonObject.put(KEY_RESULT_CODE, VALUE_RESULT_FAILURE);
            jsonObject.put(KEY_RESULT_MSG, super.convertException(e));
        }
        return jsonObject.toJSONString();
    }

}
