package com.yeejoin.equipmanage.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Sequence;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
import com.yeejoin.equipmanage.common.entity.*;
import com.yeejoin.equipmanage.common.entity.vo.WlSpareEquipmentExportVo;
import com.yeejoin.equipmanage.common.enums.BillContentEnum;
import com.yeejoin.equipmanage.common.enums.FileTypeEnum;
import com.yeejoin.equipmanage.common.enums.SingleEnum;
import com.yeejoin.equipmanage.mapper.EquipmentCategoryMapper;
import com.yeejoin.equipmanage.mapper.UnitMapper;
import com.yeejoin.equipmanage.mapper.WarehouseStructureMapper;
import com.yeejoin.equipmanage.mapper.WlSpareEquipmentMapper;
import com.yeejoin.equipmanage.service.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class WlSpareEquipmentServiceImpl extends ServiceImpl<WlSpareEquipmentMapper, WlSpareEquipment>
        implements WlSpareEquipmentService {

    @Autowired
    WlSpareEquipmentMapper wlSpareEquipmentMapper;

    @Autowired
    IEquipmentCategoryService iEquipmentCategoryService;

    @Value("${equipment.type}")
    String equipmentCategoryLeftTypeCode;

    @Autowired
    private Sequence sequence;

    @Autowired
    private IUploadFileService iUploadFileService;

    @Autowired
    private EquipmentServiceImpl equipmentService;

    @Autowired
    private EquipmentCategoryMapper equipmentCategoryMapper;

    @Autowired
    IManufacturerInfoService iManufacturerInfoService;

    @Autowired
    WarehouseStructureMapper warehouseStructureMapper;

    @Autowired
    UnitMapper unitMapper;


    @Override
    public WlSpareEquipment saveOrUpdateSpareEquipment(WlSpareEquipment wlSpareEquipment, ReginParams reginParams) {
        wlSpareEquipment.setBizOrgName(reginParams.getPersonIdentity().getCompanyName());
        wlSpareEquipment.setBizOrgCode(reginParams.getPersonIdentity().getCompanyBizOrgCode());
        if (Objects.nonNull(wlSpareEquipment.getWarehouseStructureId())) {
            WarehouseStructure warehouseStructure = warehouseStructureMapper.selectById(wlSpareEquipment.getWarehouseStructureId());
            wlSpareEquipment.setWarehouseStructureCode(warehouseStructure.getCode());
        }
        if (ObjectUtils.isEmpty(wlSpareEquipment.getId())) {
            wlSpareEquipmentMapper.insert(wlSpareEquipment);
        } else {
            wlSpareEquipmentMapper.updateById(wlSpareEquipment);
            QueryWrapper<UploadFile> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(UploadFile::getObjectType, BillContentEnum.BPBJ.getKey())
                    .eq(UploadFile::getObjectId, wlSpareEquipment.getId());
            iUploadFileService.remove(queryWrapper);
        }
        saveUploadFile(wlSpareEquipment);
        return wlSpareEquipment;
    }

    /**
     * 插入文件信息
     */
    private void saveUploadFile(WlSpareEquipment wlSpareEquipment) {
        List<UploadFile> fileList = new ArrayList<>();
        fileList.addAll(fillFileList(wlSpareEquipment.getImg(), wlSpareEquipment.getId(), FileTypeEnum.image.toString()));
        fileList.addAll(fillFileList(wlSpareEquipment.getVideo(), wlSpareEquipment.getId(), FileTypeEnum.video.toString()));
        fileList.addAll(fillFileList(wlSpareEquipment.getCertification(), wlSpareEquipment.getId(), FileTypeEnum.certificate.toString()));
        fileList.addAll(fillFileList(wlSpareEquipment.getInstruction(), wlSpareEquipment.getId(), FileTypeEnum.instruction.toString()));
        fileList.addAll(fillFileList(wlSpareEquipment.getQuality(), wlSpareEquipment.getId(), FileTypeEnum.quality.toString()));
        fileList.addAll(fillFileList(wlSpareEquipment.getOperation(), wlSpareEquipment.getId(), FileTypeEnum.operation.toString()));
        iUploadFileService.saveBatch(fileList);
    }

    private List<UploadFile> fillFileList(List<UploadFile> list, Long id, String type) {
        if (list == null) {
            return new ArrayList<UploadFile>();
        }
        list.forEach(item -> {
            item.setUrl(item.getUrl());
            item.setId(sequence.nextId());
            item.setFileType(type);
            item.setObjectType(BillContentEnum.BPBJ.getKey());
            item.setObjectId(id);
        });
        return list;
    }

    @Override
    public int deleteByIds(List<Long> ids) {
        LambdaUpdateWrapper<WlSpareEquipment> updateWrapper = new LambdaUpdateWrapper<>();
        // 设置更新条件，例如：根据主键 id 列表进行更新
        updateWrapper.in(WlSpareEquipment::getId, ids);
        // 设置更新内容，例如：将字段 field1 的值更新为 newValue
        updateWrapper.set(WlSpareEquipment::getIsDelete, true);
        return wlSpareEquipmentMapper.update(null, updateWrapper);
    }

    @Override
    public WlSpareEquipment getById(Long id) {
        WlSpareEquipment wlSpareEquipment = wlSpareEquipmentMapper.selectById(id);
        wlSpareEquipment.setImg(getEquipFileList(id, FileTypeEnum.image.toString()));
        wlSpareEquipment.setVideo(getEquipFileList(id, FileTypeEnum.video.toString()));
        wlSpareEquipment.setCertification(getEquipFileList(id, FileTypeEnum.certificate.toString()));
        wlSpareEquipment.setInstruction(getEquipFileList(id, FileTypeEnum.instruction.toString()));
        wlSpareEquipment.setQuality(getEquipFileList(id, FileTypeEnum.quality.toString()));
        wlSpareEquipment.setOperation(getEquipFileList(id, FileTypeEnum.operation.toString()));
        return wlSpareEquipment;
    }

    private List<UploadFile> getEquipFileList(Long id, String type) {
        List<UploadFile> list = iUploadFileService.list(new QueryWrapper<UploadFile>().eq("object_id", id)
                .eq("object_type", BillContentEnum.BPBJ.getKey()).eq("file_type", type));
        list.forEach(item -> {
            item.setUrl(item.getUrl());
        });
        return list;
    }

    @Override
    public Page<WlSpareEquipment> listByPage(WlSpareEquipment dto, Page page, int hierarchy, String codeHead) {
        Page<WlSpareEquipment> wlSpareEquipmentPage = wlSpareEquipmentMapper.listByPage(page, dto, hierarchy, codeHead);
        List<WlSpareEquipment> records = wlSpareEquipmentPage.getRecords();
        for (WlSpareEquipment record : records) {
            record.setImg(getEquipFileList(record.getId(), FileTypeEnum.image.toString()));
        }
        wlSpareEquipmentPage.setRecords(records);
        return wlSpareEquipmentPage;
    }

    @Override
    public void saveImportBatch(List<WlSpareEquipmentExportVo> list, ReginParams reginParams) {
        List<String> equipModelCodeList = new ArrayList<>();
        List<String> warehouseStructureList = new ArrayList<>();
        List<String> unitList = new ArrayList<>();
        list.stream().forEach(item -> {
            if (StrUtil.isEmpty(item.getEquipModelCode())) {
                throw new BadRequest("装备编码（从装备定义中获取）项不能为空");
            }
            equipModelCodeList.add(item.getEquipModelCode());
            warehouseStructureList.add(item.getWarehouseStructure());
            unitList.add(item.getUnit());
        });

        // 装备定义数据
        LambdaQueryWrapper<Equipment> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(Equipment::getCode, equipModelCodeList);
        List<Equipment> equipmentList = equipmentService.list(wrapper);

        // 装备定义
        Map<String, Equipment> equipmentMap = new HashMap<>();
        // 装备分类IDs
        List<Long> equipCategoryIds = new ArrayList<>();
        equipmentList.stream().forEach(item -> {
            equipmentMap.put(item.getCode(), item);
            equipCategoryIds.add(item.getCategoryId());
        });
        // 装备分类数据
        LambdaQueryWrapper<EquipmentCategory> categoryWrapper = new LambdaQueryWrapper<>();
        categoryWrapper.in(EquipmentCategory::getId, equipCategoryIds);
        Map<Long, EquipmentCategory> categoryMap = equipmentCategoryMapper.selectList(categoryWrapper).stream().collect(Collectors.toMap(EquipmentCategory::getId, t -> t));

        // 生产厂家数据
        List<ManufacturerInfo> manufacturerInfos = iManufacturerInfoService.list();
        Map<String, ManufacturerInfo> manufacturerMap = manufacturerInfos.stream().collect(Collectors.toMap(ManufacturerInfo::getName, t -> t));

        // 存放位置
        LambdaQueryWrapper<WarehouseStructure> warehouseLambda = new LambdaQueryWrapper<>();
        warehouseLambda.in(WarehouseStructure::getCode, warehouseStructureList);
        Map<String, WarehouseStructure> structureMap = warehouseStructureMapper.selectList(warehouseLambda).stream().collect(Collectors.toMap(WarehouseStructure::getCode, t -> t));

        // 单位
        LambdaQueryWrapper<Unit> unitLambda = new LambdaQueryWrapper<>();
        unitLambda.in(Unit::getName, unitList);
        unitLambda.groupBy(Unit::getName);
        Map<String, Long> unitMap = unitMapper.selectList(unitLambda).stream().collect(Collectors.toMap(Unit::getName, Unit::getId));

        List<WlSpareEquipment> saveList = new ArrayList<>();
        list.forEach(item -> {
            Equipment equipment = equipmentMap.get(item.getEquipModelCode());
            EquipmentCategory equipmentCategory = categoryMap.get(equipment.getCategoryId());
            ManufacturerInfo manufacturerInfo = manufacturerMap.get(item.getManufacturer());
            WarehouseStructure warehouseStructure = structureMap.get(item.getWarehouseStructure());
            Long unitId = unitMap.get(item.getUnit());

            WlSpareEquipment wlSpareEquipment = new WlSpareEquipment();
            BeanUtils.copyProperties(item, wlSpareEquipment);
            if (ObjectUtils.isNotEmpty(equipment)) {
                wlSpareEquipment.setEquipModelId(equipment.getId());
                wlSpareEquipment.setEquipModelName(equipment.getName());
            }
            if (ObjectUtils.isNotEmpty(equipmentCategory)) {
                wlSpareEquipment.setEquipCategoryId(equipmentCategory.getId());
                wlSpareEquipment.setEquipCategoryCode(equipmentCategory.getCode());
                wlSpareEquipment.setEquipCategoryName(equipmentCategory.getName());
            }
            if (ObjectUtils.isNotEmpty(manufacturerInfo)) {
                wlSpareEquipment.setManufacturerId(manufacturerInfo.getId());
            }
            if (ObjectUtils.isNotEmpty(warehouseStructure)) {
                wlSpareEquipment.setWarehouseStructureId(warehouseStructure.getId());
                wlSpareEquipment.setWarehouseStructure(warehouseStructure.getName());
                wlSpareEquipment.setWarehouseStructureCode(warehouseStructure.getCode());
            }
            wlSpareEquipment.setBizOrgName(reginParams.getPersonIdentity().getCompanyName());
            wlSpareEquipment.setBizOrgCode(reginParams.getPersonIdentity().getCompanyBizOrgCode());
            wlSpareEquipment.setSingle(SingleEnum.DXGL.getName().equals(item.getSingle()) ? SingleEnum.DXGL.getKey() : SingleEnum.PLGL.getKey());
            wlSpareEquipment.setUnitId(unitId);
            saveList.add(wlSpareEquipment);
        });
        this.saveBatch(saveList);
    }

    @Override
    public void subtractNum(Long id, Float num) {
        synchronized (id.toString()) {
            WlSpareEquipment wlSpareEquipment = this.getById(id);
            if (num > wlSpareEquipment.getStockNum()) {
                throw new BadRequest("使用数量大于备品备件库存数量");
            }
            wlSpareEquipment.setStockNum(wlSpareEquipment.getStockNum() - num);
            this.updateById(wlSpareEquipment);
        }
    }

    @Override
    public List<EquipmentCategory> getEquipmentTypeAndCount(String bizOrgCode) {
        return refreshEquipmentTypeAndCount(bizOrgCode);
    }


    public List<EquipmentCategory> refreshEquipmentTypeAndCount(String bizOrgCode) {
        List<EquipmentCategory> responseList = this.typeList();
        if (responseList == null || responseList.size() < 1) {
            return null;
        }
        List<EquipmentCategory> equipmentTypeList = responseList.stream()
                .filter(i -> !i.getCode().startsWith("2") && "2".equals(i.getIndustryCode()))
                .filter(m -> !m.getCode().startsWith("9306") && "2".equals(m.getIndustryCode()))
                .collect(Collectors.toList());
        List<EquipmentCategory> list = typeListTree(equipmentTypeList, bizOrgCode);
        return list;
    }

    public List<EquipmentCategory> typeList() {
        return iEquipmentCategoryService.getEquipmentCategoryList(Integer.valueOf(equipmentCategoryLeftTypeCode));
    }

    public List<EquipmentCategory> typeListTree(List<EquipmentCategory> equipmentCategorys, String bizOrgCode) {
        LambdaQueryWrapper<WlSpareEquipment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WlSpareEquipment::getIsDelete, 0);
        queryWrapper.gt(WlSpareEquipment::getStockNum, 0);
        queryWrapper.likeRight(WlSpareEquipment::getBizOrgCode, bizOrgCode);
        List<WlSpareEquipment> wlSpareEquipments = wlSpareEquipmentMapper.selectList(queryWrapper);
        Map<Long, Integer> resultMap = wlSpareEquipments.stream()
                .collect(Collectors.groupingBy(WlSpareEquipment::getEquipCategoryId, Collectors.summingInt(e -> 1)));
        List<EquipmentCategory> list = new ArrayList<>();
        Map<String, List<EquipmentCategory>> tmpMap = new HashMap<String, List<EquipmentCategory>>();
        equipmentCategorys.forEach(action -> {
            action.setCount(Double.parseDouble(resultMap.getOrDefault(action.getId(), 0) + ""));
            if (action.getParentId() == null) {
                list.add(action);
            } else {
                if (tmpMap.get(action.getParentId().toString()) == null) {
                    ArrayList<EquipmentCategory> tmplist = new ArrayList<EquipmentCategory>();
                    tmplist.add(action);
                    tmpMap.put(action.getParentId().toString(), tmplist);
                } else {
                    if (!tmpMap.get(action.getParentId().toString()).contains(action)) {
                        tmpMap.get(action.getParentId().toString()).add(action);
                    }
                }
            }
        });
        getChildren(list, tmpMap);

        list.forEach(this::accumulateCount);
        List<EquipmentCategory> collect = list.stream().filter(t -> t.getCount() > 0).collect(Collectors.toList());
        return collect;
    }

    public int accumulateCount(EquipmentCategory node) {
        int totalCount = (int) Math.round(node.getCount());
        for (EquipmentCategory child : node.getChildren()) {
            totalCount += accumulateCount(child);
        }
        node.setCount((double) totalCount);
        return totalCount;
    }

    private void getChildren(List<EquipmentCategory> list, Map<String, List<EquipmentCategory>> tmpMap) {
        for (EquipmentCategory equipmentCategory : list) {
            if (tmpMap.get(equipmentCategory.getId().toString()) != null
                    && tmpMap.get(equipmentCategory.getId().toString()).size() > 0) {
                List<EquipmentCategory> equipcliss = tmpMap.get(equipmentCategory.getId().toString());
                equipmentCategory.setHasLowerClassification(true);
                equipmentCategory.setChildren(equipcliss);
                getChildren(equipcliss, tmpMap);
            }
        }
    }

    @Override
    public List<Map<String, Object>> countSpareEquip(String bizOrgCode) {
        return wlSpareEquipmentMapper.countSpareEquip(bizOrgCode);
    }

    @Override
    public List<WlSpareEquipment> exportList(WlSpareEquipment dto, int hierarchy, String codeHead) {
        return wlSpareEquipmentMapper.exportList(dto, hierarchy, codeHead);
    }
}
