package cn.iocoder.yudao.module.project.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.common.RepairDictConstants;
import cn.iocoder.yudao.common.RepairRoleEnum;
import cn.iocoder.yudao.common.SystemEnum;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.base.service.RepairWorkerService;
import cn.iocoder.yudao.module.conf.entity.BaseType;
import cn.iocoder.yudao.module.conf.entity.BaseWarehouse;
import cn.iocoder.yudao.module.conf.service.BaseTypeService;
import cn.iocoder.yudao.module.conf.service.BaseWarehouseService;
import cn.iocoder.yudao.module.project.entity.RepairWares;
import cn.iocoder.yudao.module.project.mapper.RepairWaresMapper;
import cn.iocoder.yudao.module.project.service.RepairWaresService;
import cn.iocoder.yudao.module.project.vo.*;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
import cn.iocoder.yudao.module.system.api.permission.RoleApi;
import cn.iocoder.yudao.module.system.api.user.dto.UserDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;

/**
 * 配件库 Service 实现类
 *
 * @author pqz
 */
@Service
@Validated
public class RepairWaresServiceImpl extends ServiceImpl<RepairWaresMapper, RepairWares> implements RepairWaresService {

    @Resource
    private RepairWaresMapper waresMapper;

    @Resource
    @Lazy
    private BaseWarehouseService warehouseService;

    @Resource
    @Lazy
    private BaseTypeService typeService;

    @Resource
    @Lazy
    private DictDataApi dictDataApi;

    @Resource
    @Lazy
    private RoleApi roleApi;

    @Resource
    @Lazy
    private RepairWorkerService workerService;

    /**
     * 保存配件库
     *
     * @param saveReqVO RepairWaresSaveReqVO实体
     * @author PQZ
     * @date 9:33 2024/9/18
     **/
    @Override
    public RepairWares saveWares(RepairWaresSaveReqVO saveReqVO) {
        RepairWares repairWares = BeanUtils.toBean(saveReqVO, RepairWares.class);
        saveOrUpdate(repairWares);
        return getById(repairWares.getId());
    }

    /**
     * @param id 配件id
     * @author PQZ
     * @date 9:37 2024/9/18
     **/
    @Override
    public void deleteWares(String id) {
        // 删除
        waresMapper.deleteById(id);
    }

    /**
     * 根据id获取配件信息
     *
     * @param id id
     * @return cn.iocoder.yudao.module.project.vo.RepairWaresRespVO
     * @author PQZ
     * @date 10:52 2024/9/18
     **/
    @Override
    public RepairWaresRespVO getWares(String id) {
        //基本信息
        RepairWares repairWares = getById(id);
        RepairWaresRespVO result = BeanUtils.toBean(repairWares, RepairWaresRespVO.class);
        //关联子公司转换
        if (StringUtils.isNotBlank(result.getCorpId())) {
            result.setCorpIds(Arrays.asList(result.getCorpId().split(",")));
        }
        return result;
    }

    /**
     * 分页获取配件库
     *
     * @param pageReqVO RepairWaresPageReqVO实体
     * @param page      分页信息
     * @return com.baomidou.mybatisplus.core.metadata.IPage<cn.iocoder.yudao.module.project.vo.RepairWaresRespVO>
     * @author PQZ
     * @date 10:53 2024/9/18
     **/
    @Override
    public IPage<RepairWaresRespVO> getWaresPage(RepairWaresPageReqVO pageReqVO, Page<RepairWaresRespVO> page) {
        return waresMapper.queryListPage(pageReqVO, page);
    }

    /**
     * 根据名称获取最新的数据
     *
     * @author 小李
     * @date 18:03 2024/9/25
     **/
    @Override
    public RepairWaresRespVO getWaresByName(String name) {
        return waresMapper.getWaresByName(name);
    }

    /**
     * 查询所有有配件的分配
     *
     * @return java.util.List<java.util.Map < java.lang.String, java.lang.String>>
     * @author vinjor-M
     * @date 10:53 2024/10/22
     **/
    @Override
    public List<Map<String, String>> getAllTypeList() {
        return waresMapper.selectAllType();
    }

    /**
     * 通过id查询集合
     *
     * @param idList waresId集合
     * @return java.util.List<cn.iocoder.yudao.module.project.entity.RepairWares>
     * @author PQZ
     * @date 14:56 2024/10/24
     **/
    @Override
    public List<RepairWares> listByIds(List<String> idList) {
        return baseMapper.selectBatchIds(idList);
    }

    /**
     * 导入配件数据
     *
     * @author 小李
     * @date 16:20 2024/11/29
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ImportExcelRespVO importData(List<RepairWaresExcelVO> list, Boolean updateSupport) {
        // 参数校验
        if (CollUtil.isEmpty(list)) {
            throw exception0(500, "导入配件数据不能为空！");
        }

        // 取所有的仓库变成map，key是名称，value是id
        List<BaseWarehouse> warehouses = warehouseService.list();
        Map<String, String> warehousesMap = warehouses.stream().collect(Collectors.toMap(BaseWarehouse::getName, BaseWarehouse::getId));

        // 取所有的配件类型变成map，key是名称，value是id
        List<BaseType> types = typeService.list(new LambdaQueryWrapper<BaseType>().eq(BaseType::getType, "02"));
        Map<String, String> typesMap = types.stream().collect(Collectors.toMap(BaseType::getName, BaseType::getId));

        // 遍历，逐个创建 or 更新
        ImportExcelRespVO result = ImportExcelRespVO.builder().createNames(new ArrayList<>())
                .updateNames(new ArrayList<>()).failureNames(new LinkedHashMap<>()).build();
        list.forEach(item -> {
            // 验证是否存在，用selectList防止本来就有多个导致的报错
            List<RepairWares> repairWares = baseMapper.selectList(new LambdaQueryWrapper<RepairWares>().eq(RepairWares::getName, item.getName()));
            if (CollUtil.isEmpty(repairWares)) {
                RepairWares wares = BeanUtils.toBean(item, RepairWares.class);
                if (ObjectUtil.isNotEmpty(item.getType()) && ObjectUtil.isNotEmpty(typesMap.get(item.getType()))) {
                    wares.setType(typesMap.get(item.getType()));
                }
                if (ObjectUtil.isNotEmpty(item.getWarehouse()) && ObjectUtil.isNotEmpty(warehousesMap.get(item.getWarehouse()))) {
                    wares.setWarehouse(warehousesMap.get(item.getWarehouse()));
                }
                wares.setStatus("01");
                baseMapper.insert(wares);
                result.getCreateNames().add(item.getName());
                return;
            }
            // 存在看是否可以修改
            if (!updateSupport) {
                result.getFailureNames().put(item.getName(), "不允许修改！");
                return;
            }
            // 可以修改，看是否有多个相同名称的配件
            if (repairWares.size() > 1) {
                result.getFailureNames().put(item.getName(), "存在多个相同名称的配件！");
                return;
            }
            // 更新
            RepairWares wares = repairWares.get(0);
            RepairWares updateWares = BeanUtils.toBean(item, RepairWares.class);
            updateWares.setId(wares.getId());
            if (ObjectUtil.isNotEmpty(item.getType()) && ObjectUtil.isNotEmpty(typesMap.get(item.getType()))) {
                updateWares.setType(typesMap.get(item.getType()));
            }
            if (ObjectUtil.isNotEmpty(item.getWarehouse()) && ObjectUtil.isNotEmpty(warehousesMap.get(item.getWarehouse()))) {
                updateWares.setWarehouse(warehousesMap.get(item.getWarehouse()));
            }
            updateWares.setStatus(wares.getStatus());
            baseMapper.updateById(updateWares);
            result.getUpdateNames().add(item.getName());
        });
        return result;
    }

    /**
     * 配件入库超多少天（可以自己设置）没用的话需要做一个临期提醒
     *
     * @author 小李
     * @date 14:42 2024/11/30
     **/
    @Override
    public void timeOver() {
        // 取仓管、维修管理员
        List<UserDTO> warehouse = roleApi.selectUserListByRoleCode(TenantContextHolder.getRequiredTenantId(), RepairRoleEnum.WAREHOUSE.getCode());
        List<UserDTO> admin = roleApi.selectUserListByRoleCode(TenantContextHolder.getRequiredTenantId(), RepairRoleEnum.ADMIN.getCode());
        // 取配置
        List<DictDataRespDTO> dataList = dictDataApi.getDictDataList(RepairDictConstants.REPAIR_WARES_NOTICE);

        // 取出第一个
        if (CollUtil.isEmpty(dataList)) {
           noticeByFlag(true, admin, warehouse);
           return;
        }
        DictDataRespDTO dictDataRespDTO = dataList.get(0);
        String day = dictDataRespDTO.getValue();
        // 转时间，如果updateTime小于这个时间，那就是需要提醒的
        LocalDateTime dateAgo = LocalDateTime.now().minusDays(Integer.parseInt(day));

        List<RepairWares> repairWares = baseMapper.selectList(new LambdaQueryWrapper<RepairWares>().le(RepairWares::getUpdateTime, dateAgo));
        if (CollUtil.isNotEmpty(repairWares)) {
            List<String> names = repairWares.stream().map(RepairWares::getName).collect(Collectors.toList());
            String result = String.join(",", names);
            String message = "以下配件未使用天数超过设定的未使用天数提醒,请及时处理相关事项！" + result;
            warehouse.forEach(item -> workerService.sentMessage(SystemEnum.REPAIR.getCode(),item.getId(), message));
            admin.forEach(item -> workerService.sentMessage(SystemEnum.REPAIR.getCode(),item.getId(), message));
        }
    }

    /**
     * 配件库存低于几个（可以自己设置）需要做库存预警
     *
     * @author 小李
     * @date 15:54 2024/11/30
     **/
    @Override
    public void stockBelow(){
        // 取仓管、维修管理员
        List<UserDTO> warehouse = roleApi.selectUserListByRoleCode(TenantContextHolder.getRequiredTenantId(), RepairRoleEnum.WAREHOUSE.getCode());
        List<UserDTO> admin = roleApi.selectUserListByRoleCode(TenantContextHolder.getRequiredTenantId(), RepairRoleEnum.ADMIN.getCode());
        // 取配置
        List<DictDataRespDTO> dataList = dictDataApi.getDictDataList(RepairDictConstants.REPAIR_WARES_NOTICE);

        // 取出第二个
        if (CollUtil.isEmpty(dataList)) {
            noticeByFlag(false, admin, warehouse);
            return;
        }
        DictDataRespDTO dictDataRespDTO = dataList.get(1);
        String count = dictDataRespDTO.getValue();
        List<RepairWares> repairWares = baseMapper.selectList(new LambdaQueryWrapper<RepairWares>().le(RepairWares::getStock, count));

        if (CollUtil.isNotEmpty(repairWares)) {
            List<String> names = repairWares.stream().map(RepairWares::getName).collect(Collectors.toList());
            String result = String.join(",", names);
            String message = "以下配件库存低于设定的库存不足提醒，请及时处理相关事项！\n" + result;
            warehouse.forEach(item -> workerService.sentMessage(SystemEnum.REPAIR.getCode(),item.getId(), message));
            admin.forEach(item -> workerService.sentMessage(SystemEnum.REPAIR.getCode(),item.getId(), message));
        }
    }

    /**
     * 上面两个方法公共的通知方法
     *
     * @author 小李
     * @date 15:57 2024/11/30
     * @param flag 什么通知
     * @param admin 维修管理员们
     * @param warehouse 仓库管理员们
    **/
    private void noticeByFlag(Boolean flag, List<UserDTO> admin, List<UserDTO> warehouse){
        String message = flag ? "检查配件入库是否超时出现故障，请联系开发人员解决" : "检查配件库存是否充足出现故障，请联系开发人员解决";
        // 如果为空就通知相关人员出现了问题
        if (CollUtil.isNotEmpty(warehouse)) {
            warehouse.forEach(item -> workerService.sentMessage(SystemEnum.REPAIR.getCode(),item.getId(), message));
        }
        if (CollUtil.isNotEmpty(admin)) {
            admin.forEach(item -> workerService.sentMessage(SystemEnum.REPAIR.getCode(),item.getId(), message));
        }
    }
}