package cn.iocoder.yudao.module.pms.service.maintenance;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils;
import cn.iocoder.yudao.module.pms.controller.admin.iotmaintenancebom.vo.IotMaintenanceBomPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotmaintenancebom.vo.IotMaintenanceBomSaveReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotmaintenancebom.vo.IotTobeMaintenanceBomRespVO;
import cn.iocoder.yudao.module.pms.controller.admin.maintenance.vo.IotMaintenancePlanPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.maintenance.vo.IotMaintenancePlanSaveReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.maintenance.vo.IotMaintenanceSaveVO;
import cn.iocoder.yudao.module.pms.controller.admin.vo.IotDevicePageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.vo.IotDeviceRespVO;
import cn.iocoder.yudao.module.pms.dal.dataobject.IotDeviceDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotmaintenancebom.IotMaintenanceBomDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.maintenance.IotMaintenancePlanDO;
import cn.iocoder.yudao.module.pms.dal.mysql.IotDeviceMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotmaintenancebom.IotMaintenanceBomMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.maintenance.IotMaintenancePlanMapper;
import cn.iocoder.yudao.module.pms.dal.redis.BizNoRedisDAO;
import cn.iocoder.yudao.module.pms.service.IotDeviceService;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.*;

/**
 * 保养计划 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class IotMaintenancePlanServiceImpl implements IotMaintenancePlanService {

    private static final Logger log = LoggerFactory.getLogger(IotMaintenancePlanServiceImpl.class);
    @Resource
    private IotMaintenancePlanMapper iotMaintenancePlanMapper;
    @Resource
    private IotMaintenanceBomMapper iotMaintenanceBomMapper;
    @Resource
    private BizNoRedisDAO bizNoRedisDAO;
    @Resource
    private DeptService deptService;
    @Resource
    private IotDeviceMapper iotDeviceMapper;
    @Resource
    private IotDeviceService iotDeviceService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createIotMaintenancePlan(IotMaintenanceSaveVO createReqVO) {
        if (ObjectUtil.isEmpty(createReqVO)) {
            throw exception(IOT_MAINTENANCE_PLAN_NOT_EXISTS);
        }
        if (ObjectUtil.isEmpty(createReqVO.getMainPlan())) {
            throw exception(IOT_MAINTENANCE_PLAN_NOT_EXISTS);
        }
        List<IotMaintenanceBomSaveReqVO> deviceBOMs = createReqVO.getMainPlanBom();
        if (ObjectUtil.isEmpty(deviceBOMs)) {
            throw exception(IOT_MAINTENANCE_PLAN_NOT_EXISTS);
        }
        // 校验保养计划明细中的设备只能出现在1个保养计划中
        Set<Long> deviceIds = new HashSet<>();
        // 查验保养计划明细中的设备 只存在于1个保养计划中
        deviceBOMs.forEach(bom -> {
            deviceIds.add(bom.getDeviceId());
        });
        IotMaintenanceBomPageReqVO reqVO = new IotMaintenanceBomPageReqVO();
        reqVO.setDeviceIds(new ArrayList<>(deviceIds));
        List<IotMaintenanceBomDO> boms = iotMaintenanceBomMapper.selectList(reqVO);
        // 需要提示出具体哪些设备已经存在于其它保养计划中
        if (CollUtil.isNotEmpty(boms)) {
            Set<String> deviceCodes = new HashSet<>();
            Set<Long> existDeviceIds = new HashSet<>();
            boms.forEach(bom -> {
                existDeviceIds.add(bom.getDeviceId());
            });
            // 根据设备id查询设备编码
            // 组装bom关联的设备信息
            Map<Long, IotDeviceRespVO> deviceMap = iotDeviceService.getDeviceMap(new ArrayList<>(existDeviceIds));
            if (CollUtil.isNotEmpty(deviceMap)) {
                deviceMap.forEach((k,v) -> {
                    deviceCodes.add(v.getDeviceCode());
                });
            }
            // 拼接设备编码（如果大于3个，显示前3个并加省略号）
            String deviceCodesString = deviceCodes.stream()
                    .limit(3)  // 只取前3个元素
                    .collect(Collectors.joining(","));  // 用逗号连接

            // 如果设备编码超过3个，添加省略号
            if (deviceCodes.size() > 3) {
                deviceCodesString += "...";
            }
            throw exception(IOT_MAINTENANCE_SAME_DEVICE_EXISTS, deviceCodesString);
        }
        // 先保存保养计划主表 再根据主表id更新明细
        IotMaintenancePlanSaveReqVO mainPlanSaveVO = createReqVO.getMainPlan();
        // 自动生成保养计划编号 BYJH202504300001
        // 插入 保养计划
        IotMaintenancePlanDO iotMaintenancePlan = BeanUtils.toBean(mainPlanSaveVO, IotMaintenancePlanDO.class);
        String no = bizNoRedisDAO.generate(BizNoRedisDAO.MAIN_PLAN_NO_PREFIX);
        if (ObjectUtil.isNotEmpty(iotMaintenancePlanMapper.selectByNo(no))) {
            throw exception(IOT_MAINTENANCE_PLAN_NO_EXISTS);
        }
        iotMaintenancePlan.setSerialNumber(no);
        iotMaintenancePlanMapper.insert(iotMaintenancePlan);
        // 插入保养计划明细
        List<IotMaintenanceBomDO> maintenanceBOMs = new ArrayList<>();
        maintenanceBOMs = convertList(deviceBOMs, bom -> BeanUtils.toBean(bom, IotMaintenanceBomDO.class, item -> item
                .setPlanId(iotMaintenancePlan.getId())
                .setDeviceCategoryId(bom.getAssetClass())));
        iotMaintenanceBomMapper.insertBatch(maintenanceBOMs);
        // 返回
        return iotMaintenancePlan.getId();
    }

    @Override
    public void updateIotMaintenancePlan(IotMaintenancePlanSaveReqVO updateReqVO) {
        // 校验存在
        validateIotMaintenancePlanExists(updateReqVO.getId());
        // 更新
        IotMaintenancePlanDO updateObj = BeanUtils.toBean(updateReqVO, IotMaintenancePlanDO.class);
        iotMaintenancePlanMapper.updateById(updateObj);
    }

    @Override
    public void deleteIotMaintenancePlan(Long id) {
        // 校验存在
        validateIotMaintenancePlanExists(id);
        // 删除
        iotMaintenancePlanMapper.deleteById(id);
    }

    private void validateIotMaintenancePlanExists(Long id) {
        if (iotMaintenancePlanMapper.selectById(id) == null) {
            throw exception(IOT_MAINTENANCE_PLAN_NOT_EXISTS);
        }
    }

    @Override
    public IotMaintenancePlanDO getIotMaintenancePlan(Long id) {
        return iotMaintenancePlanMapper.selectById(id);
    }

    @Override
    public PageResult<IotMaintenancePlanDO> getIotMaintenancePlanPage(IotMaintenancePlanPageReqVO pageReqVO) {
        // 查询当前部门及子部门下所有数据
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
        }
        if (StrUtil.isNotBlank(pageReqVO.getName())) {
            pageReqVO.setDeviceName(StrUtil.trim(pageReqVO.getName()));
            pageReqVO.setDeviceCode(StrUtil.trim(pageReqVO.getName()));
        }
        // 设备名称模糊搜索 查询保养计划明细
        IotDevicePageReqVO reqVO = new IotDevicePageReqVO();
        reqVO.setDeviceName(pageReqVO.getDeviceName());
        List<IotDeviceDO> devices = iotDeviceMapper.selectListAlone(reqVO);
        Set<Long> deviceIds = new HashSet<>();
        if (CollUtil.isNotEmpty(devices)) {
            devices.forEach(device -> {
                deviceIds.add(device.getId());
            });
        }
        // 根据设备id查询保养计划明细
        Set<Long> planIds = new HashSet<>();
        if (CollUtil.isNotEmpty(deviceIds)) {
            IotMaintenanceBomPageReqVO planBomReqVO = new IotMaintenanceBomPageReqVO();
            planBomReqVO.setDeviceIds(new ArrayList<>(deviceIds));
            List<IotMaintenanceBomDO> planBoms = iotMaintenanceBomMapper.selectList(planBomReqVO);
            if (CollUtil.isNotEmpty(planBoms)) {
                planBoms.forEach(bom -> {
                    planIds.add(bom.getPlanId());
                });
            }
        }
        if (StrUtil.isNotBlank(pageReqVO.getName()) && CollUtil.isEmpty(planIds)) {
            return PageResult.empty();
        }
        return iotMaintenancePlanMapper.selectPage(pageReqVO, ids, planIds);
    }

    @Override
    public List<IotMaintenancePlanDO> maintenancePlans(IotMaintenancePlanPageReqVO pageReqVO) {
        return iotMaintenancePlanMapper.selectList(pageReqVO);
    }

    @Override
    public List<IotTobeMaintenanceBomRespVO> toBeMaintenanceDeviceBOMs() {
        return iotMaintenancePlanMapper.toBeMaintenanceDeviceBOMs();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long updatePlan(IotMaintenanceSaveVO updateReqVO) {
        if (ObjectUtil.isEmpty(updateReqVO)) {
            throw exception(IOT_MAINTENANCE_PLAN_NOT_EXISTS);
        }
        if (ObjectUtil.isEmpty(updateReqVO.getMainPlan())) {
            throw exception(IOT_MAINTENANCE_PLAN_NOT_EXISTS);
        }
        List<IotMaintenanceBomSaveReqVO> deviceBOMs = updateReqVO.getMainPlanBom();
        if (ObjectUtil.isEmpty(deviceBOMs)) {
            throw exception(IOT_MAINTENANCE_PLAN_NOT_EXISTS);
        }
        // 校验保养计划是否存在
        IotMaintenancePlanDO existPlan = iotMaintenancePlanMapper.selectById(updateReqVO.getMainPlan().getId());
        if (ObjectUtil.isEmpty(existPlan)) {
            throw exception(IOT_MAINTENANCE_PLAN_NOT_EXISTS);
        }
        Set<Long> deviceIds = new HashSet<>();
        // 查验保养计划明细中的设备 只存在于1个保养计划中
        deviceBOMs.forEach(bom -> {
            deviceIds.add(bom.getDeviceId());
        });
        IotMaintenanceBomPageReqVO reqVO = new IotMaintenanceBomPageReqVO();
        reqVO.setNotPlanId(updateReqVO.getMainPlan().getId());
        reqVO.setDeviceIds(new ArrayList<>(deviceIds));
        List<IotMaintenanceBomDO> boms = iotMaintenanceBomMapper.selectList(reqVO);
        if (CollUtil.isNotEmpty(boms)) {
            Set<String> deviceCodes = new HashSet<>();
            Set<Long> existDeviceIds = new HashSet<>();
            boms.forEach(bom -> {
                existDeviceIds.add(bom.getDeviceId());
            });
            // 组装bom关联的设备信息
            Map<Long, IotDeviceRespVO> deviceMap = iotDeviceService.getDeviceMap(new ArrayList<>(existDeviceIds));
            if (CollUtil.isNotEmpty(deviceMap)) {
                deviceMap.forEach((k,v) -> {
                    deviceCodes.add(v.getDeviceCode());
                });
            }
            // 拼接设备编码（如果大于3个，显示前3个并加省略号）
            String deviceCodesString = deviceCodes.stream()
                    .limit(3)  // 只取前3个元素
                    .collect(Collectors.joining(","));  // 用逗号连接
            // 如果设备编码超过3个，添加省略号
            if (deviceCodes.size() > 3) {
                deviceCodesString += "...";
            }
            throw exception(IOT_MAINTENANCE_SAME_DEVICE_EXISTS, deviceCodesString);
        }
        IotMaintenancePlanSaveReqVO mainPlanSaveVO = updateReqVO.getMainPlan();
        IotMaintenancePlanDO iotMaintenancePlan = BeanUtils.toBean(mainPlanSaveVO, IotMaintenancePlanDO.class);
        iotMaintenancePlanMapper.updateById(iotMaintenancePlan);
        // 保养计划明细 先删除再新增
        iotMaintenanceBomMapper.deleteByPlanId(existPlan.getId());
        List<IotMaintenanceBomDO> maintenanceBOMs = new ArrayList<>();
        maintenanceBOMs = convertList(deviceBOMs, bom -> BeanUtils.toBean(bom, IotMaintenanceBomDO.class, item -> item
                .setPlanId(iotMaintenancePlan.getId())
                .setId(null)
                .setDeviceCategoryId(bom.getAssetClass())));
        iotMaintenanceBomMapper.insertBatch(maintenanceBOMs);
        return iotMaintenancePlan.getId();
    }

    @Override
    public void updatePlanStatus(Long id, Integer status) {
        IotMaintenancePlanDO planDO = iotMaintenancePlanMapper.selectById(id).setStatus(status);
        iotMaintenancePlanMapper.updateById(planDO);
    }

    @Override
    public void syncMaintenancePlan(List<Long> deviceIds, Long deptId, List<Long> personIds, Map<Long, Long> oldDeptPair) {
        // 需要过滤掉数据权限
        DataPermissionUtils.executeIgnore(() -> {
            // 查询当前调拨的设备相关的保养计划 保养计划明细
            IotMaintenanceBomPageReqVO reqVO = new IotMaintenanceBomPageReqVO();
            reqVO.setDeviceIds(deviceIds);
            List<IotMaintenanceBomDO> planBoms = iotMaintenanceBomMapper.selectList(reqVO);
            // 以设备为维度组装保养项列表
            List<IotMaintenanceBomDO> relatedDeviceBoms = new ArrayList<>();
            if (CollUtil.isNotEmpty(planBoms)) {
                planBoms.forEach(bom -> {
                    relatedDeviceBoms.add(bom);
                });
            }
            // 查询调拨后的部门是否已经存在保养计划 如果 保养后的部门没有保养计划 则新建保养计划并添加保养项
            // 如果调拨后的部门有多个保养计划 随机取1个保养计划 将保养项 添加进去
            IotMaintenancePlanPageReqVO planReqVO = new IotMaintenancePlanPageReqVO();
            planReqVO.setDeptId(deptId);
            List<IotMaintenancePlanDO> plans = iotMaintenancePlanMapper.selectList(planReqVO);
            // 需要新增的保养项集合
            List<IotMaintenanceBomDO> tobeAddedBoms = new ArrayList<>();
            if (CollUtil.isNotEmpty(plans)) {
                IotMaintenancePlanDO specifiedPlan = plans.get(0);
                // 将集合 relatedDeviceBoms 中的保养项与 新保养计划 建立关联
                if (CollUtil.isNotEmpty(relatedDeviceBoms)) {
                    relatedDeviceBoms.forEach(bom -> {
                        IotMaintenanceBomDO copy = BeanUtils.toBean(bom, IotMaintenanceBomDO.class);
                        copy.setId(null);
                        copy.setPlanId(specifiedPlan.getId());
                        copy.setDeleted(false);
                        tobeAddedBoms.add(copy);
                    });
                }
            } else {
                DeptDO dept = deptService.getDept(deptId);
                String no = bizNoRedisDAO.generate(BizNoRedisDAO.MAIN_PLAN_NO_PREFIX);
                // 调拨后的部门没有保养计划 新增保养计划
                IotMaintenancePlanDO newPlan = new IotMaintenancePlanDO();
                newPlan.setDeptId(deptId);
                newPlan.setSerialNumber(no);
                newPlan.setName(ObjUtil.isNotEmpty(dept) ? dept.getName() : StrUtil.EMPTY + " - " + "保养计划");
                newPlan.setResponsiblePerson(CollUtil.isNotEmpty(personIds) ? String.valueOf(personIds.get(0)) : StrUtil.EMPTY);
                newPlan.setCreator(CollUtil.isNotEmpty(personIds) ? String.valueOf(personIds.get(0)) : StrUtil.EMPTY);
                newPlan.setCreateTime(LocalDateTime.now());
                iotMaintenancePlanMapper.insert(newPlan);
                // 将集合 relatedDeviceBoms 中的保养项与 新保养计划 建立关联
                if (CollUtil.isNotEmpty(relatedDeviceBoms)) {
                    relatedDeviceBoms.forEach(bom -> {
                        IotMaintenanceBomDO copy = BeanUtils.toBean(bom, IotMaintenanceBomDO.class);
                        copy.setId(null);
                        copy.setPlanId(newPlan.getId());
                        copy.setDeleted(false);
                        tobeAddedBoms.add(copy);
                    });
                }
            }
            // 删除设备调拨前保养计划中的保养项 新增调拨后部门保养计划的保养项
            // 需要修改(删除)的保养项集合
            if (CollUtil.isNotEmpty(relatedDeviceBoms)) {
                relatedDeviceBoms.forEach(bom -> {
                    // 执行数据 删除 操作
                    List<Long> deleteIds = relatedDeviceBoms.stream()
                            .map(IotMaintenanceBomDO::getId)
                            .collect(Collectors.toList());
                    iotMaintenanceBomMapper.deleteBatchIds(deleteIds);
                });
            }
            // 执行数据 新增 操作
            if (CollUtil.isNotEmpty(tobeAddedBoms)) {
                iotMaintenanceBomMapper.insertBatch(tobeAddedBoms);
            }
        });

    }

}
