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

import cn.hutool.core.lang.Assert;
import com.alibaba.excel.util.DateUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.casic.missiles.core.base.service.IBaseExportService;
import com.casic.missiles.core.model.auth.AuthUser;
import com.casic.missiles.core.page.PageFactory;
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.equipment.EquipmentOrSampleDto;
import com.casic.missiles.dto.equipment.FixedAssetRequest;
import com.casic.missiles.dto.equipment.RemindQuantityDTO;
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.enums.workbench.MessageSourceModuleEnum;
import com.casic.missiles.enums.workbench.MessageTypeEnum;
import com.casic.missiles.exception.BusinessException;
import com.casic.missiles.mapper.MeterFixedAssetsMapper;
import com.casic.missiles.mapper.equipment.EquipmentFixedAssetFileMapper;
import com.casic.missiles.mapper.equipment.EquipmentStateChangeLogMapper;
import com.casic.missiles.mapper.equipment.EquipmentUseLogMapper;
import com.casic.missiles.mapper.workbench.WorkbenchRemindMessageMapper;
import com.casic.missiles.model.equipment.*;
import com.casic.missiles.model.page.PageQuery;
import com.casic.missiles.model.workbench.WorkbenchRemindMessage;
import com.casic.missiles.modular.system.model.Dept;
import com.casic.missiles.modular.system.service.IDeptService;
import com.casic.missiles.service.equipment.IEquipmentFixedAssetFileService;
import com.casic.missiles.service.equipment.IEquipmentFixedAssetsService;
import com.casic.missiles.service.system.IMessagePushService;
import com.casic.missiles.utils.DictCodeUtils;
import com.casic.missiles.utils.NumberGeneratorUtil;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 固定资产service
 * </p>
 *
 * @author cuicheng
 * @since 2022-12-07
 */
@Slf4j
@Service
public class EquipmentFixedAssetsServiceImpl extends ServiceImpl<MeterFixedAssetsMapper, EquipmentFixedAssets> implements IEquipmentFixedAssetsService {

    @Autowired(required = false)
    private MeterFixedAssetsMapper meterFixedAssetsMapper;

    @Autowired(required = false)
    private EquipmentFixedAssetFileMapper meterFixedAssetFileMapper;

    @Autowired
    private IEquipmentFixedAssetFileService meterFixedAssetFileService;

    @Resource
    private EquipmentUseLogMapper equipmentUseLogMapper;

    @Resource
    private EquipmentStateChangeLogMapper stateChangeLogMapper;

    @Resource
    private WorkbenchRemindMessageMapper messageMapper;

    @Resource
    private IBaseExportService iBaseExportService;
    @Autowired
    private IDeptService deptService;

    @Autowired
    private IMessagePushService messagePushService;

    /**
     * 分页查询
     *
     * @param page
     * @param request
     * @return
     * @throws Exception
     */
    @Override
    public Page<EquipmentFixedAssets> listPage(Page<EquipmentFixedAssets> page, FixedAssetRequest request) throws Exception {
//        QueryWrapper<MeterFixedAssets> wrapper = getWrapper(request);
        Page<EquipmentFixedAssets> meterFixedAssetsPage = meterFixedAssetsMapper.listPage(page, request);
//        Page<MeterFixedAssets> meterFixedAssetsPage = meterFixedAssetsMapper.selectPage(page, wrapper);
        for (EquipmentFixedAssets meterFixedAssets : meterFixedAssetsPage.getRecords()) {
            // TODO 走guava本地缓存，减少跟redis的IO交互
            DictCodeUtils.convertDictCodeToName(meterFixedAssets);
        }
        return meterFixedAssetsPage;
    }

    /**
     * 固定资产列表
     *
     * @param request
     * @return
     * @throws Exception
     */
    @Override
    public List<EquipmentFixedAssets> list(FixedAssetRequest request) throws Exception {
        PageQuery pageQuery = new PageQuery();
        pageQuery.setPageNo(0);
        pageQuery.setPageSize(10000);
        Page<EquipmentFixedAssets> page = PageFactory.createPage(pageQuery);
        Page<EquipmentFixedAssets> meterFixedAssetsPage = meterFixedAssetsMapper.listPage(page, request);
//        QueryWrapper<MeterFixedAssets> wrapper = getWrapper(request);
//        List<MeterFixedAssets> meterFixedAssetsList = meterFixedAssetsMapper.selectList(wrapper);
        for (EquipmentFixedAssets meterFixedAssets : meterFixedAssetsPage.getRecords()) {
            DictCodeUtils.convertDictCodeToName(meterFixedAssets);
        }
        return meterFixedAssetsPage.getRecords();
    }

    /**
     * 添加固定资产
     *
     * @param meterFixedAssets
     * @return
     */
    @Override
    @Transactional
    public ReturnDTO addFixedAsset(EquipmentFixedAssets meterFixedAssets) {
        if (meterFixedAssets.getCreateUser() == null) {
            AuthUser authUser = ShiroKit.getUser();
            if (authUser != null) {
                meterFixedAssets.setCreateUser(authUser.getId());
            }
        }
        //需要根据出厂编号判重
        validManufacturingNo(meterFixedAssets);
        //生成资产编号
        Long maxNo = meterFixedAssetsMapper.selectMaxNo();
        String asset_no = NumberGeneratorUtil.getContactNo(PrefixCodeEnum.FIXED_ASSETS_PREFIX, maxNo);
        meterFixedAssets.setAssetNo(asset_no);
        meterFixedAssets.setEquipmentNo(asset_no);
        meterFixedAssetsMapper.insert(meterFixedAssets);
        // 插入文件列表
        batchSaveFile(meterFixedAssets);
        // 新增状态变更记录表
        EquipmentStateChangeLog stateChangeLog = new EquipmentStateChangeLog(null, meterFixedAssets.getId(), meterFixedAssets.getManagerState(), DateUtils.format(new Date()), null, meterFixedAssets.getCreateUser());
        if (stateChangeLogMapper.insert(stateChangeLog) <= 0) {
            throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
        }
        return ReturnUtil.success(meterFixedAssets.getId());
    }

    /**
     * 批量添加固定资产
     *
     * @return
     */
    @Override
    @Transactional
    public ReturnDTO addFixedAssetList(List<EquipmentFixedAssets> meterFixedAssetsList) throws Exception {
        //用于存储验证后的错误信息
        Long maxNo = meterFixedAssetsMapper.selectMaxNo();
        for (EquipmentFixedAssets item : meterFixedAssetsList) {
            Set<ConstraintViolation<EquipmentFixedAssets>> validate = Validation.buildDefaultValidatorFactory().getValidator().validate(item);
            if (!CollectionUtils.isEmpty(validate)) {
                return ReturnUtil.failed(validate.iterator().next().getMessage());
            }
            DictCodeUtils.validDictCode(item);
            //需要根据出厂编号判重
            validManufacturingNo(item);
            //生成资产编号
            String asset_no = NumberGeneratorUtil.getContactNo(PrefixCodeEnum.FIXED_ASSETS_PREFIX, maxNo);
            item.setAssetNo(asset_no);
            item.setEquipmentNo(asset_no);
            maxNo++;
        }
        super.saveBatch(meterFixedAssetsList);
        return ReturnUtil.success();
    }

    private void validManufacturingNo(EquipmentFixedAssets item) {
        if (StringUtils.isNotEmpty(item.getManufacturingNo())) {
            QueryWrapper<EquipmentFixedAssets> wrapper = new QueryWrapper<>();
            wrapper.eq("manufacturing_no", item.getManufacturingNo());
            wrapper.eq("is_del", 0);
            EquipmentFixedAssets result = meterFixedAssetsMapper.selectOne(wrapper);
            if (result != null) {
                log.error("出厂编号:{},重复", result.getManufacturingNo());
                throw new BusinessException(BusinessExceptionEnum.DUPLICATE_MANUFACTURE_NUMBER);
            }
        }
    }


    /**
     * 更新固定资产
     *
     * @param meterFixedAssets
     * @return
     */
    @Transactional
    @Override
    public ReturnDTO updateFixedAsset(EquipmentFixedAssets meterFixedAssets) {
        int updateFlag = meterFixedAssetsMapper.updateById(meterFixedAssets);
        batchSaveFile(meterFixedAssets);
        if (updateFlag > 0) {
            return ReturnUtil.success();
        }
        return ReturnUtil.failed("更新失败");
    }


    /**
     * 获取资产详情
     *
     * @param id
     * @return
     */
    public EquipmentFixedAssets getById(Long id) throws Exception {
        PageQuery pageQuery = new PageQuery();
        pageQuery.setPageNo(0);
        pageQuery.setPageSize(1);
        Page<EquipmentFixedAssets> page = PageFactory.createPage(pageQuery);
        FixedAssetRequest request = new FixedAssetRequest();
        request.setId(id);
        Page<EquipmentFixedAssets> meterFixedAssetsPage = meterFixedAssetsMapper.listPage(page, request);
        EquipmentFixedAssets meterFixedAssets = null;
        if (!CollectionUtils.isEmpty(meterFixedAssetsPage.getRecords())) {
            meterFixedAssets = meterFixedAssetsPage.getRecords().get(0);
            DictCodeUtils.convertDictCodeToName(meterFixedAssets);
            QueryWrapper<EquipmentFixedAssetFile> wrapper = new QueryWrapper<>();
            wrapper.eq("asset_id", id);
            meterFixedAssets.setFileList(meterFixedAssetFileMapper.selectList(wrapper));
        }
//        MeterFixedAssets meterFixedAssets = super.getById(id);
        return meterFixedAssets;
    }


    /**
     * 删除资产
     *
     * @param id
     * @return
     */
    @Override
    public ReturnDTO deleteByFixedAssetId(Long id) {
        int deleteFlag = meterFixedAssetsMapper.deleteById(id);
        if (deleteFlag > 0) {
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    public ReturnDTO removeStandardSupportEquipment(Long id) {
        return removeTypeSign(id, "is_standard_support_equipment");
    }

    @Override
    public ReturnDTO removeCalibrationTestEquipment(Long id) {
        return removeTypeSign(id, "is_calibration_test_equipment");
    }

    @Override
    public ReturnDTO removeMeasureAccount(Long id) {
        return removeTypeSign(id, "is_measure_account");
    }

    /**
     * 删除类型标记（更新字段）
     *
     * @param id       固定资产id
     * @param signName 字段名
     * @return 更新结果
     */
    @NotNull
    private ReturnDTO removeTypeSign(Long id, String signName) {
        UpdateWrapper<EquipmentFixedAssets> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", id).set(signName, 0);
        if (meterFixedAssetsMapper.update(null, updateWrapper) > 0) {
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    /**
     * @param meterFixedAssets
     */
    public void batchSaveFile(EquipmentFixedAssets meterFixedAssets) {
        if (!CollectionUtils.isEmpty(meterFixedAssets.getFileList())) {
            // 删除老的文件，更新新的文件
            QueryWrapper<EquipmentFixedAssetFile> wrapper = new QueryWrapper<>();
            wrapper.eq("asset_id", meterFixedAssets.getId());
            meterFixedAssetFileMapper.delete(wrapper);
            meterFixedAssets.getFileList().stream().forEach(item -> {
                item.setAssetId(meterFixedAssets.getId());
                item.setId(null);
            });
            meterFixedAssetFileService.saveBatch(meterFixedAssets.getFileList());
        }
    }


    /**
     * 查询equipment_fixed_asserts表资产类型为1的测量设备
     *
     * @return
     */
    @Override
    public ReturnDTO querySelectList() {
        QueryWrapper<EquipmentFixedAssets> wrapper = new QueryWrapper<>();
        wrapper.eq("asset_type", MeterDictEnum.ASSET_TYPE_1);
        wrapper.eq("is_del", MeterDictEnum.DELETE_FALSE);
        return ReturnUtil.success(this.baseMapper.selectList(wrapper));
    }


    @Override
    public ReturnDTO queryListByDept(Long id) throws Exception {
        QueryWrapper<EquipmentFixedAssets> wrapper = new QueryWrapper<>();
        wrapper.eq("asset_type", MeterDictEnum.ASSET_TYPE_1);
        wrapper.eq("use_dept", id);
        List<EquipmentFixedAssets> equipmentFixedAssets = this.baseMapper.selectList(wrapper);
        for (EquipmentFixedAssets meterFixedAssets : equipmentFixedAssets) {
            DictCodeUtils.convertDictCodeToName(meterFixedAssets);
        }
        return ReturnUtil.success(equipmentFixedAssets);
    }


    /**
     * 根据ids查设备
     *
     * @param ids
     * @return
     */
    @Override
    public List<EquipmentFixedAssets> list(List<Long> ids) {
        QueryWrapper<EquipmentFixedAssets> wrapper = new QueryWrapper<>();
        wrapper.in("id", ids);
        wrapper.eq("is_del", MeterDictEnum.DELETE_FALSE);
        List<EquipmentFixedAssets> equipmentFixedAssetsList = this.baseMapper.selectList(wrapper);
        List<Dept> deptList = deptService.list();
        Map<Long, String> meterOrganizeMap = deptList.stream()
                .collect(Collectors.toMap(Dept::getId, Dept::getSimpleName));
        for (EquipmentFixedAssets equipmentFixedAssets : equipmentFixedAssetsList) {
            if (Objects.nonNull(equipmentFixedAssets.getUseDept())) {
                equipmentFixedAssets.setUseDeptName(meterOrganizeMap.get(Long.valueOf(equipmentFixedAssets.getUseDept())));
            }
//            if(Objects.nonNull(equipmentFixedAssets.getMesureDept())){
//                equipmentFixedAssets.setMesureDeptName(meterOrganizeMap.get(Long.valueOf(equipmentFixedAssets.getMesureDept())));
//            }
        }
        return equipmentFixedAssetsList;
    }

    @Override
    public ReturnDTO queryUseLogList(Long id) throws Exception {
        List<EquipmentUseLog> logList = equipmentUseLogMapper.queryUseLogList(id);
        for (EquipmentUseLog equipmentUseLog : logList) {
            DictCodeUtils.convertDictCodeToName(equipmentUseLog);
            if (!StringUtils.isNotEmpty(equipmentUseLog.getEndDate())) {
                equipmentUseLog.setEndDate("至今");
            }
        }
        return ReturnUtil.success(logList);
    }

    @Override
    public ReturnDTO queryStateChangeLogList(Long id) throws Exception {
        List<EquipmentStateChangeLog> logList = stateChangeLogMapper.queryStateChangeLogList(id);
        for (EquipmentStateChangeLog stateChangeLog : logList) {
            DictCodeUtils.convertDictCodeToName(stateChangeLog);
            if (!StringUtils.isNotEmpty(stateChangeLog.getEndDate())) {
                stateChangeLog.setEndDate("至今");
            }
        }
        return ReturnUtil.success(logList);
    }

    @Override
    public Page<EquipmentOrSampleDto> queryEquipment(Page<EquipmentOrSampleDto> page, EquipmentOrSampleDto request) throws Exception {
        Page<EquipmentOrSampleDto> resultPage = meterFixedAssetsMapper.queryEquipment(page, request);
        for (EquipmentOrSampleDto dto : resultPage.getRecords()) {
            DictCodeUtils.convertDictCodeToName(dto);
        }
        return resultPage;
    }

    @Override
    public Page<EquipmentFixedAssets> remindListPage(Page<EquipmentFixedAssets> page, FixedAssetRequest request) throws Exception {
        Page<EquipmentFixedAssets> meterFixedAssetsPage = meterFixedAssetsMapper.remindListPage(page, request);
        for (EquipmentFixedAssets meterFixedAssets : meterFixedAssetsPage.getRecords()) {
            DictCodeUtils.convertDictCodeToName(meterFixedAssets);
        }
        return meterFixedAssetsPage;
    }

    @Override
    public RemindQuantityDTO remindQuantity() {
        Integer remindQuantity = meterFixedAssetsMapper.selectRemindQuantity();
        RemindQuantityDTO result = new RemindQuantityDTO();
        result.setRemindQuantity(remindQuantity);
        return result;
    }

    @Override
    public void exportList(FixedAssetRequest request, HttpServletResponse response) throws Exception {
        List<EquipmentRemindExport> resultList;
        if (!CollectionUtils.isEmpty(request.getIds())) {
            FixedAssetRequest fixedAssetRequest = new FixedAssetRequest();
            fixedAssetRequest.setIds(request.getIds());
            resultList = meterFixedAssetsMapper.remindList(fixedAssetRequest);
        } else {
            resultList = meterFixedAssetsMapper.remindList(request);
        }
        for (EquipmentRemindExport item : resultList) {
            DictCodeUtils.convertDictCodeToName(item);
        }
        iBaseExportService.exportExcel(response, EquipmentRemindExport.class, resultList, ExportEnum.EQUIPMENT_REMIND.getSheetName());
    }

    @Override
    public ReturnDTO remindWorker(IdDTO idDTO) {
        AuthUser user = ShiroKit.getUser();
        Assert.isFalse(Objects.isNull(user), () -> {
            throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_ACQUIRE_FAILED);
        });
        EquipmentFixedAssets fixedAssets = meterFixedAssetsMapper.selectById(idDTO.getId());
        if (fixedAssets != null && ObjectUtils.isNotEmpty(fixedAssets.getUsePerson())) {
            WorkbenchRemindMessage remindMessage = new WorkbenchRemindMessage(fixedAssets.getUsePerson(), fixedAssets.getUseDept(), idDTO.getId(), fixedAssets.getAssetNo(),
                    MessageTypeEnum.MEASURING_EQUIPMENT.getCode(), MessageSourceModuleEnum.EQUIPMENT.getCode(), MessageTypeEnum.MEASURING_EQUIPMENT.getValue(),
                    MessageTypeEnum.MEASURING_EQUIPMENT.getValue(), fixedAssets.getEquipmentName(), 0, user.getId(), user.getName());
            if (messageMapper.insert(remindMessage) > 0) {
                Boolean sendFlag = messagePushService.pushToUser(remindMessage);
                return ReturnUtil.success();
            }
        } else {
            throw new BusinessException(BusinessExceptionEnum.DEVICE_USER_OR_EMPTY);
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    /**
     * 转换字典code
     *
     * @param request
     * @return
     */
    private QueryWrapper<EquipmentFixedAssets> getWrapper(FixedAssetRequest request) {
        QueryWrapper<EquipmentFixedAssets> wrapper = new QueryWrapper<>();
        wrapper.like(StringUtils.isNotBlank(request.getAssetNo()), "asset_no", request.getAssetNo());
        wrapper.eq(request.getAssetType() != null, "asset_type", request.getAssetType());
        wrapper.like(StringUtils.isNotBlank(request.getEquipmentName()), "equipment_name", request.getEquipmentName());
        wrapper.like(StringUtils.isNotBlank(request.getEquipmentNo()), "equipment_no", request.getEquipmentNo());
        wrapper.eq(request.getMesureType() != null, "mesure_type", request.getMesureType());
        wrapper.eq(request.getManagerState() != null, "manager_state", request.getManagerState());
        wrapper.eq(request.getUseDept() != null, "use_dept", request.getUseDept());
        wrapper.eq(StringUtils.isNotEmpty(request.getAbc()), "ABC", request.getAbc());
        wrapper.like(StringUtils.isNotEmpty(request.getModelNo()), "model_no", request.getModelNo());
        wrapper.eq(StringUtils.isNotEmpty(request.getEquipmentSpecifications()), "equipment_specifications", request.getEquipmentSpecifications());
        wrapper.eq(request.getEquipmentCategory() != null, "equipment_category", request.getEquipmentCategory());
        wrapper.apply(StringUtils.isNotBlank(request.getValidDateStart()),
                "{0} = DATE_FORMAT(valid_date,'%Y-%m-%d %H:%i:%s')", request.getValidDateStart());
        wrapper.apply(StringUtils.isNotBlank(request.getValidDateEnd()),
                "{0} = DATE_FORMAT(valid_date,'%Y-%m-%d %H:%i:%s')", request.getValidDateEnd());
        wrapper.eq(StringUtils.isNotEmpty(request.getManufacturingNo()), "manufacturing_no", request.getModelNo());
        wrapper.eq("is_del", 0);
        wrapper.orderByDesc("create_time");
        wrapper.eq(request.getIsMeasureAccount() != null, "is_measure_account", request.getIsMeasureAccount());
        wrapper.eq(request.getIsStandardSupportEquipment() != null, "is_standard_support_equipment", request.getIsStandardSupportEquipment());
        wrapper.eq(request.getIsCalibrationTestEquipment() != null, "is_calibration_test_equipment", request.getIsCalibrationTestEquipment());
        wrapper.eq(request.getIsFixedAssets() != null, "is_fixed_assets", request.getIsFixedAssets());
        return wrapper;
    }
}
