package com.casic.missiles.service.Impl.meter;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.casic.missiles.constants.MeterDictCode;
import com.casic.missiles.core.application.service.AbstractDictService;
import com.casic.missiles.core.base.service.IBaseExportService;
import com.casic.missiles.core.model.auth.AuthUser;
import com.casic.missiles.core.node.ZTreeNode;
import com.casic.missiles.core.shiro.ShiroKit;
import com.casic.missiles.dto.IdDTO;
import com.casic.missiles.dto.ReturnDTO;
import com.casic.missiles.dto.ReturnUtil;
import com.casic.missiles.dto.meter.MeterStaffImport;
import com.casic.missiles.dto.meter.MeterStaffRequest;
import com.casic.missiles.enums.BusinessExceptionEnum;
import com.casic.missiles.enums.ExportEnum;
import com.casic.missiles.enums.PrefixCodeEnum;
import com.casic.missiles.enums.meter.MeterDictEnum;
import com.casic.missiles.exception.BusinessException;
import com.casic.missiles.mapper.meter.MeterCertificateMapper;
import com.casic.missiles.mapper.meter.MeterStaffMapper;
import com.casic.missiles.mapper.sys.UserInfoMapper;
import com.casic.missiles.model.meter.MeterCertificate;
import com.casic.missiles.model.meter.MeterStaff;
import com.casic.missiles.model.meter.MeterTrainStaff;
import com.casic.missiles.model.system.UserInfo;
import com.casic.missiles.modular.system.dao.DeptMapper;
import com.casic.missiles.modular.system.model.Dept;
import com.casic.missiles.modular.system.model.Dict;
import com.casic.missiles.modular.system.service.IDeptService;
import com.casic.missiles.service.meter.IMeterTrainStaffService;
import com.casic.missiles.service.meter.MeterCertificateService;
import com.casic.missiles.service.meter.MeterStaffService;
import com.casic.missiles.utils.ExportUtils;
import com.casic.missiles.utils.MinioUtil;
import com.casic.missiles.utils.NumberGeneratorUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

/**
 * <p>
 * 计量管理-计量人员-计量人员表 服务实现类
 * </p>
 */
@Service("MeterStaffService")
public class MeterStaffServiceImpl extends ServiceImpl<MeterStaffMapper, MeterStaff> implements MeterStaffService {

    @Resource
    private MeterStaffMapper meterStaffMapper;

    @Resource
    private MeterCertificateService meterCertificateService;

    @Resource
    private MinioUtil minioUtil;

    @Resource
    private MeterCertificateMapper meterCertificateMapper;

    @Resource
    private DeptMapper deptMapper;

    @Resource
    private AbstractDictService dictService;

    @Resource
    private IDeptService deptService;

    @Resource
    private UserInfoMapper userInfoMapper;

    @Resource
    private IBaseExportService iBaseExportService;

    @Resource
    private IMeterTrainStaffService trainStaffService;

    @Override
    public Page<MeterStaff> selectStaffList(Page<MeterStaff> page, MeterStaffRequest meterStaffRequest) {
        Page<MeterStaff> meterStaffPage = meterStaffMapper.selectStaffList(page, meterStaffRequest);
        meterStaffPage.setRecords(supplementList(meterStaffPage.getRecords()));
        return meterStaffPage;
    }

    @Override
    public MeterStaff selectStaffInfo(IdDTO idDto) {
        // 通过id获取对应的人员信息
        MeterStaff meterStaff = meterStaffMapper.selectStaffInfo(String.valueOf(idDto.getId()));
        // 通过人员信息的id获取人员对应的证书列表
        QueryWrapper<MeterCertificate> wrapper = new QueryWrapper<>();
        wrapper.eq("staff_id", idDto.getId());
        List<MeterCertificate> meterCertificates = meterCertificateMapper.selectList(wrapper);
        meterStaff.setCertificateList(meterCertificates);
        return meterStaff;
    }

    @Override
    public ReturnDTO deleteStaff(IdDTO idDto) {
        if (meterStaffMapper.deleteById(idDto.getId()) > 0) {
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    public Page<UserInfo> getUserList(String name, String deptId, Page<UserInfo> page) {
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.like(StringUtils.isNotBlank(name), "name", name);
        wrapper.eq(StringUtils.isNotBlank(deptId), "dept_id", deptId);
        Page<UserInfo> userInfoPage = userInfoMapper.selectPage(page, wrapper);
        userInfoPage.getRecords().forEach(user -> {
            Dept dept = deptMapper.selectById(user.getDeptId());
            user.setDeptName(dept == null ? "" : dept.getFullName());
        });
        return userInfoPage;
    }

    @Override
    @Transactional
    public ReturnDTO addStaffInfo(MeterStaff meterStaff) {
        QueryWrapper<MeterStaff> staffWrapper = new QueryWrapper<>();
        staffWrapper.eq("account", meterStaff.getAccount());
        Long count = meterStaffMapper.selectCount(staffWrapper);
        if (count != 0) {
            return ReturnUtil.failed("该用户已是计量人员");
        }
        long maxNo = meterStaffMapper.getMaxNo();
        meterStaff.setIsDel(0);
        String staffNo = NumberGeneratorUtil.getContactNo(PrefixCodeEnum.STAFF_PREFIX, maxNo);
        meterStaff.setStaffNo(staffNo);
        if (meterStaffMapper.insert(meterStaff) > 0) {
            Long id = meterStaff.getId();
            meterStaff.getCertificateList().forEach(bean -> {
                bean.setStaffId(String.valueOf(id));
            });
            meterCertificateService.saveBatch(meterStaff.getCertificateList());
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    public void exportStaffList(MeterStaffRequest meterStaffRequest, HttpServletResponse response) {
        try {
            List<MeterStaff> meterStaffList;
            if (!CollectionUtils.isEmpty(meterStaffRequest.getIds())) {
                MeterStaffRequest request = new MeterStaffRequest();
                request.setIds(meterStaffRequest.getIds());
                meterStaffList = supplementList(meterStaffMapper.selectStaffList(request));
            } else {
                meterStaffList = supplementList(meterStaffMapper.selectStaffList(meterStaffRequest));
            }
            meterStaffList.forEach(bean -> {
                bean.setSex(bean.getSex().equals("2") ? "女" : "男");
                bean.setTechnologyExam(bean.getTechnologyExam().equals("0") ? "已考核" : "未考核");
            });
            iBaseExportService.exportExcel(response, MeterStaff.class, meterStaffList, ExportEnum.METER_STAFF.getSheetName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    @Transactional
    public ReturnDTO updateStaffInfo(MeterStaff meterStaff) {
        int updateFlag = meterStaffMapper.updateById(meterStaff);
        if (updateFlag > 0) {
            QueryWrapper<MeterCertificate> wrapper = new QueryWrapper<>();
            wrapper.eq("staff_id", meterStaff.getId());
            meterStaff.getCertificateList().forEach(bean -> {
                bean.setStaffId(String.valueOf(meterStaff.getId()));
            });
            if (meterCertificateService.remove(wrapper) && meterCertificateService.saveBatch(meterStaff.getCertificateList())) {
                return ReturnUtil.success();
            }
            throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    public ReturnDTO dataCheck(List<MeterStaffImport> list) {
        AtomicBoolean checkResult = new AtomicBoolean(true);
        // 获取字典值
        List<Dict> educationDict = dictService.findInDictByCode(MeterDictEnum.EDUCATION);
        List<Dict> technologyJobDict = dictService.findInDictByCode(MeterDictEnum.TECHNOLOGY_JOB);
        List<Dict> administrationJobDict = dictService.findInDictByCode(MeterDictEnum.ADMINISTRATION_JOB);
        List<ZTreeNode> deptList = deptService.tree();
        Map<String, List<Dict>> educationDictMap = educationDict.stream().collect(Collectors.groupingBy(Dict::getName));
        Map<String, List<Dict>> technologyJobDictMap = technologyJobDict.stream().collect(Collectors.groupingBy(Dict::getName));
        Map<String, List<Dict>> administrationJobDictMap = administrationJobDict.stream().collect(Collectors.groupingBy(Dict::getName));
        Map<String, List<ZTreeNode>> deptMap = deptList.stream().collect(Collectors.groupingBy(ZTreeNode::getName));
        list.forEach(bean -> {
            StringBuilder result = new StringBuilder();
            // 校验导入数据中的字典值是否存在
            if (null == educationDictMap.get(bean.getEducation())) {
                result.append(BusinessExceptionEnum.EDUCATION_NOT_EXISTENCE.getMessage());
                checkResult.set(false);
            }
            if (null == technologyJobDictMap.get(bean.getTechnologyJob())) {
                result.append(BusinessExceptionEnum.TECHNOLOGY_JOB_NOT_EXISTENCE.getMessage());
                checkResult.set(false);
            }
            if (null == administrationJobDictMap.get(bean.getAdministrationJob())) {
                result.append(BusinessExceptionEnum.ADMINISTRATION_JOB_NOT_EXISTENCE.getMessage());
                checkResult.set(false);
            }
            if (null == deptMap.get(bean.getDeptId())) {
                result.append(BusinessExceptionEnum.DEPT_NOT_EXISTENCE.getMessage());
                checkResult.set(false);
            }
            // 校验导入数据中的性别等信息是否正确
            if (!(bean.getSex().equals("男") || bean.getSex().equals("女"))) {
                result.append(BusinessExceptionEnum.SEX_NOT_CORRECT.getMessage());
                checkResult.set(false);
            }
            if (!(bean.getMainExaminer().equals("是") || bean.getMainExaminer().equals("否"))) {
                result.append(BusinessExceptionEnum.MAIN_EXAMINER_NOT_CORRECT.getMessage());
                checkResult.set(false);
            }
            if (!(bean.getSpecialOperator().equals("是") || bean.getSpecialOperator().equals("否"))) {
                result.append(BusinessExceptionEnum.SPECIAL_OPERATOR_NOT_CORRECT.getMessage());
                checkResult.set(false);
            }
            if (!(bean.getTechnologyExam().equals("是") || bean.getTechnologyExam().equals("否"))) {
                result.append(BusinessExceptionEnum.TECHNOLOGY_EXAM_NOT_CORRECT.getMessage());
                checkResult.set(false);
            }
            // 校验导入数据中的日期格式是否规范
            if (isDateFormat(bean.getValidDate())) {
                result.append(BusinessExceptionEnum.VALID_DATE_NOT_CORRECT.getMessage());
                checkResult.set(false);
            }
            if (isDateFormat(bean.getWorkDate())) {
                result.append(BusinessExceptionEnum.WORK_DATE_NOT_CORRECT.getMessage());
                checkResult.set(false);
            }
            if (isDateFormat(bean.getBirthday())) {
                result.append(BusinessExceptionEnum.BIRTHDAY_NOT_CORRECT.getMessage());
                checkResult.set(false);
            }
            if (isDateFormat(bean.getCertificateDate())) {
                result.append(BusinessExceptionEnum.CERTIFICATE_DATE_NOT_CORRECT.getMessage());
                checkResult.set(false);
            }
            bean.setResult(result.toString());
        });
        if (checkResult.get()) {
            // 校验通过
            AtomicLong maxNo = new AtomicLong(meterStaffMapper.getMaxNo());
            list.forEach(bean -> {
                // 生成编号
                String staffNo = NumberGeneratorUtil.getContactNo(PrefixCodeEnum.STAFF_PREFIX, maxNo.get());
                maxNo.set(Long.parseLong(staffNo.substring(4)));
                bean.setStaffNo(staffNo);
                // 获取id
                Long id = IdWorker.getId();
                bean.setId(id);
                Long certificateId = IdWorker.getId();
                bean.setCertificateId(certificateId);
                // 将数据的字典值替换
                bean.setEducation(educationDictMap.get(bean.getEducation()).get(0).getCode());
                bean.setTechnologyJob(technologyJobDictMap.get(bean.getTechnologyJob()).get(0).getCode());
                bean.setAdministrationJob(administrationJobDictMap.get(bean.getAdministrationJob()).get(0).getCode());
                bean.setDeptId(deptMap.get(bean.getDeptId()).get(0).getId());
                bean.setSex(bean.getSex().equals("男") ? "1" : "2");
                bean.setMainExaminer(bean.getMainExaminer().equals("是") ? "0" : "1");
                bean.setSpecialOperator(bean.getSpecialOperator().equals("是") ? "0" : "1");
                bean.setTechnologyExam(bean.getTechnologyExam().equals("是") ? "0" : "1");
            });
            // 批量新增数据
            meterStaffMapper.addStaffList(list);
            meterCertificateMapper.addCertificateList(list);
            return ReturnUtil.success();
        } else {
            // 校验不通过
            // 将处理后的数据导出成文件
            MultipartFile[] file = ExportUtils.exportMultipartFile(list, "checkResult", MeterStaffImport.class);
            // 将文件存储到minio中返回文件id,供前台下载
            List<String> upload = minioUtil.upload(file);
            return ReturnUtil.failed(upload.get(0));
        }

    }


    public static boolean isDateFormat(String date) {
        if (StringUtils.isBlank(date)) {
            return false;
        }
        try {
            DateUtil.parseDate(date);
            return false;
        } catch (Exception e) {
            return true;
        }
    }


    private List<MeterStaff> supplementList(List<MeterStaff> meterStaffList) {
        meterStaffList.forEach(bean -> {
            bean.setEducation(dictService.getDictNameByCode(MeterDictEnum.EDUCATION, bean.getEducation()));
            bean.setTechnologyJob(dictService.getDictNameByCode(MeterDictEnum.TECHNOLOGY_JOB, bean.getTechnologyJob()));
            bean.setAdministrationJob(dictService.getDictNameByCode(MeterDictEnum.ADMINISTRATION_JOB, bean.getAdministrationJob()));
            bean.setMajor(dictService.getDictNameByCode(MeterDictCode.MEASURE_MAJOR, bean.getMajor()));
            bean.setDeptName(deptMapper.selectById(bean.getDeptId()).getFullName());
        });
        return meterStaffList;
    }

    @Override
    public List<MeterStaff> selectStaffListByDept(MeterStaffRequest meterStaffRequest) {
        return supplementList(meterStaffMapper.selectStaffList(meterStaffRequest));
    }

    @Override
    public Page<MeterTrainStaff> staffCultivateLog(Page<MeterTrainStaff> page, IdDTO idDto) {
        return meterStaffMapper.staffCultivateLog(page, idDto.getId());
    }

    @Override
    @Transactional
    public ReturnDTO updateStaffCultivateLog(List<MeterTrainStaff> list) {
        QueryWrapper<MeterTrainStaff> wrapper = new QueryWrapper<>();
        wrapper.eq("staff_id", list.get(0).getStaffId());
        if (trainStaffService.remove(wrapper) && trainStaffService.saveBatch(list)) {
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    public ReturnDTO<Map<String, Integer>> isMeterStaff() {
        AuthUser authUser = ShiroKit.getUser();
        MeterStaff meterStaff = getMeterStaffInfo(authUser);
        HashMap<String, Integer> map = new HashMap<>();
        if (Objects.isNull(meterStaff)) {
            map.put("isMeterStaff", 0);
        }else {
            map.put("isMeterStaff", 1);
        }
        return ReturnUtil.success(map);
    }

    private MeterStaff getMeterStaffInfo(AuthUser user) {
        String account = user.getAccount();
        QueryWrapper<MeterStaff> wrapper = new QueryWrapper<>();
        wrapper.eq("account", account);
        return meterStaffMapper.selectOne(wrapper);
    }

}
