package com.ktg.iscs.service.impl;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ktg.common.core.text.Convert;
import com.ktg.common.exception.ServiceException;
import com.ktg.common.utils.DateUtils;
import com.ktg.common.utils.SecurityUtils;
import com.ktg.common.utils.bean.BeanUtils;
import com.ktg.iscs.domain.*;
import com.ktg.iscs.domain.dto.hardwareApi.LoanParamDTO;
import com.ktg.iscs.domain.dto.materials.LoanMaterialDTO;
import com.ktg.iscs.domain.dto.materials.MaterialBindingDTO;
import com.ktg.iscs.domain.dto.materials.MaterialsPageDTO;
import com.ktg.iscs.domain.dto.materialsLoan.AddLoanDTO;
import com.ktg.iscs.domain.dto.materialsLoan.ReturnLoanDTO;
import com.ktg.iscs.domain.vo.hardwareMaterialApi.CheckMaterialsDateVO;
import com.ktg.iscs.domain.vo.materials.ImportMaterialsVO;
import com.ktg.iscs.domain.vo.materials.MaterialsPageVO;
import com.ktg.iscs.domain.vo.materials.PropertyVO;
import com.ktg.iscs.mapper.IsMaterialsMapper;
import com.ktg.iscs.service.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 物资Service业务层处理
 *
 * @author cgj
 * @date 2024-11-08
 */
@Service
public class IsMaterialsServiceImpl extends ServiceImpl<IsMaterialsMapper, IsMaterials> implements IIsMaterialsService {
    @Autowired
    private IsMaterialsMapper isMaterialsMapper;
    @Autowired
    private IIsMaterialsLoanService iIsMaterialsLoanService;
    @Autowired
    private IIsMaterialsTypeService iIsMaterialsTypeService;
    @Autowired
    private IIsMaterialsCabinetService iIsMaterialsCabinetService;
    @Autowired
    private IIsMaterialsPlanCabinetService iIsMaterialsPlanCabinetService;
    @Autowired
    private IIsMaterialsPropertyService iIsMaterialsPropertyService;
    @Autowired
    private IIsMaterialsPropertyValueService iIsMaterialsPropertyValueService;
    @Autowired
    private IIsMaterialsLoanExceptionService isMaterialsLoanExceptionService;

    /**
     * 查询物资
     *
     * @param materialsId 物资主键
     * @return 物资
     */
    @Override
    public IsMaterials selectIsMaterialsByMaterialsId(Long materialsId) {
        IsMaterials materials = isMaterialsMapper.selectIsMaterialsByMaterialsId(materialsId);
        if (materials != null && materials.getMaterialsTypeId() != null) {
            IsMaterialsType materialsType = iIsMaterialsTypeService.getById(materials.getMaterialsTypeId());
            if (materialsType != null) {
                materials.setMaterialsTypeIcon(materialsType.getMaterialsTypeIcon());
                materials.setMaterialsTypePicture(materialsType.getMaterialsTypePicture());
                materials.setPropertyIds(materialsType.getPropertyIds());
            }
        }
        return materials;
    }

    /**
     * 查询物资列表
     *
     * @param isMaterials 物资
     * @return 物资
     */
    @Override
    public List<IsMaterials> selectIsMaterialsList(IsMaterials isMaterials) {
        return isMaterialsMapper.selectIsMaterialsList(isMaterials);
    }

    /**
     * 新增物资
     *
     * @param isMaterials 物资
     * @return 结果
     */
    @Override
    public int insertIsMaterials(IsMaterials isMaterials) {
        // 1.检查物资编码有没有被使用
        List<IsMaterials> list = list(Wrappers.<IsMaterials>lambdaQuery().eq(IsMaterials::getMaterialsCode, isMaterials.getMaterialsCode()));
        Assert.isFalse(!list.isEmpty(), "该物资编码已被使用!");
        // 2.检查rfid重复
        if (StringUtils.isNotBlank(isMaterials.getMaterialsRfid())) {
            List<IsMaterials> rfidList = list(Wrappers.<IsMaterials>lambdaQuery()
                    .eq(IsMaterials::getMaterialsRfid, isMaterials.getMaterialsRfid()));
            Assert.isTrue(rfidList.isEmpty(), "该RFID已被使用!");
        }
        // 3.如果设置了物资柜信息，把loan_state变更
        if (isMaterials.getMaterialsCabinetId() == null || isMaterials.getMaterialsCabinetId() == 0) {
            isMaterials.setLoanState("0");
        }
        isMaterials.setCreateTime(DateUtils.getNowDate());
        return isMaterialsMapper.insertIsMaterials(isMaterials);
    }

    /**
     * 修改物资
     *
     * @param isMaterials 物资
     * @return 结果
     */
    @Override
    public int updateIsMaterials(IsMaterials isMaterials) {
        // 1.检查物资编码有没有被使用
        List<IsMaterials> list = list(Wrappers.<IsMaterials>lambdaQuery()
                .eq(IsMaterials::getMaterialsCode, isMaterials.getMaterialsCode()).ne(IsMaterials::getMaterialsId, isMaterials.getMaterialsId()));
        Assert.isFalse(!list.isEmpty(), "该物资编码已被使用!");
        // 2.检查rfid重复
        if (StringUtils.isNotBlank(isMaterials.getMaterialsRfid())) {
            List<IsMaterials> rfidList = list(Wrappers.<IsMaterials>lambdaQuery()
                    .eq(IsMaterials::getMaterialsRfid, isMaterials.getMaterialsRfid())
                    .ne(IsMaterials::getMaterialsId, isMaterials.getMaterialsId()));
            Assert.isTrue(rfidList.isEmpty(), "该RFID已被使用!");
        }
        // 3.如果设置了物资柜信息，把loan_state变更
        if (isMaterials.getMaterialsCabinetId() == null || isMaterials.getMaterialsCabinetId() == 0) {
            isMaterials.setLoanState("0");
        } else {
            isMaterials.setLoanState("1");
        }
        isMaterials.setUpdateTime(DateUtils.getNowDate());
        // 4.设定当前物资所处柜子，如果当前物资没有被使用，只是更改绑定，则同步柜子，否则不变
        return isMaterialsMapper.updateIsMaterials(isMaterials);
    }

    /**
     * 批量删除物资
     *
     * @param materialsIds 需要删除的物资主键
     * @return 结果
     */
    @Override
    public int deleteIsMaterialsByMaterialsIds(String materialsIds) {
        Assert.notBlank(materialsIds, "请选择需要删除的数据!");
        Long[] longIds = Convert.toLongArray(materialsIds);
        return isMaterialsMapper.deleteIsMaterialsByMaterialsIds(longIds);
    }

    /**
     * 删除物资信息
     *
     * @param materialsId 物资主键
     * @return 结果
     */
    @Override
    public int deleteIsMaterialsByMaterialsId(Long materialsId) {
        return isMaterialsMapper.deleteIsMaterialsByMaterialsId(materialsId);
    }

    @Override
    public Page<MaterialsPageVO> getIsMaterialsPage(Page<IsMaterials> page, MaterialsPageDTO dto) throws JsonProcessingException {
        if (StringUtils.isNotBlank(dto.getPropertyId())) {
            dto.setPropertyId('"' + "propertyId" + '"' + ":" + '"' + dto.getPropertyId() + '"');
        }
        if (StringUtils.isNotBlank(dto.getRecordId())) {
            dto.setRecordId('"' + "recordId" + '"' + ":" + '"' + dto.getRecordId() + '"');
        }
        Page<MaterialsPageVO> isMaterialsPage = isMaterialsMapper.getIsMaterialsPage(page, dto);
        // 解析规格属性
        if (!isMaterialsPage.getRecords().isEmpty()) {
            ObjectMapper objectMapper = new ObjectMapper();
            for (MaterialsPageVO record : isMaterialsPage.getRecords()) {
                if (StringUtils.isNotBlank(record.getProperties())) {
                    List<PropertyVO> propertyVOS = objectMapper.readValue(record.getProperties(), new TypeReference<List<PropertyVO>>() {
                    });
                    String propertiesValue = propertyVOS.stream().map(PropertyVO::getValueName).collect(Collectors.joining(","));
                    record.setPropertiesValue(propertiesValue);
                    String propertiesProperty = propertyVOS.stream().map(PropertyVO::getPropertyName).collect(Collectors.joining(","));
                    record.setPropertiesProperty(propertiesProperty);
                }
            }
        }
        return isMaterialsPage;
    }

    @Transactional
    @Override
    public String updateIsMaterialById(LoanParamDTO loanParamDTO) {
        if (!loanParamDTO.getList().isEmpty()) {
            Long userId = SecurityUtils.getUserId();
            List<String> failRfidList = new ArrayList<>();
            for (LoanMaterialDTO dto : loanParamDTO.getList()) {
                // 1.断言判断
                Assert.isFalse(dto.getMaterialsId() == null && StringUtils.isBlank(dto.getMaterialsRfid()), "请告诉我物资的rfid!");
                Assert.isFalse(StringUtils.isBlank(dto.getLoanState()), "请告诉我是借出还是归还!");

                try {
                    // 1.1 开始查询物资，模拟传的id，物资柜传的rfid
                    if (dto.getMaterialsId() != null) {
                        // 模拟，无需处理
                    } else {
                        IsMaterials materials = getOne(Wrappers.<IsMaterials>lambdaQuery()
                                .eq(IsMaterials::getMaterialsRfid, dto.getMaterialsRfid()));
                        if (materials == null) {
                            // 物资不存在
                            handleOutSystemMaterials(dto.getMaterialsRfid(), dto.getLoanState(), dto.getRestitutionToCabinetCode());
                            Assert.isFalse(true, "通过RFID:" + dto.getMaterialsRfid() + "未查询到物资！");
                            return "true";
                        }
                        dto.setMaterialsId(materials.getMaterialsId());
                    }
                    // 2.物资信息
                    IsMaterials materials = getById(dto.getMaterialsId());
                    Assert.notNull(materials, "该物资不存在！");
                    // 如果物资是借出状态，又来借出就报错
                    // if ("0".equals(materials.getLoanState()) && "0".equals(dto.getLoanState()) && materials.getStatus().equals("0")) {
                    if ("0".equals(materials.getLoanState()) && "0".equals(dto.getLoanState())) {
                        failRfidList.add(dto.getMaterialsRfid() + "物资已经是借出状态，无法再借出！");
                        Assert.isFalse(true, dto.getMaterialsRfid() + "物资已经是借出状态，无法再借出！");
                    }
                    // 如果已经再柜中，又来放入
                    if ("1".equals(materials.getLoanState()) && "1".equals(dto.getLoanState())) {
                        failRfidList.add(dto.getMaterialsRfid() + "物资已经是柜中状态，无法再放入！");
                        Assert.isFalse(true, dto.getMaterialsRfid() + "物资已经是柜中状态，无法再放入！");
                    }
                    // 3.开始更新物资状态
                    update(Wrappers.<IsMaterials>lambdaUpdate()
                            .eq(IsMaterials::getMaterialsId, dto.getMaterialsId())
                            .set(IsMaterials::getLoanState, dto.getLoanState())
                            .set(IsMaterials::getUpdateTime, new Date()));
                    // 4.开始更新借出表信息
                    if ("0".equals(dto.getLoanState())) {
                        // Assert.notNull(dto.getLoanUserId(), "请告诉我借取人员信息!");
                        // 4.1开始新增借出记录表
                        AddLoanDTO addMaterialsLoan = new AddLoanDTO();
                        addMaterialsLoan.setMaterialsId(dto.getMaterialsId());
                        addMaterialsLoan.setMaterialsRfid(materials.getMaterialsRfid());
                        addMaterialsLoan.setLoanUserId(userId);
                        iIsMaterialsLoanService.insertIsMaterialsLoan(addMaterialsLoan);
                    } else if ("1".equals(dto.getLoanState())) {
                        // Assert.notNull(dto.getRestitutionUserId(), "请告诉我归还人员信息!");
                        // 1.2 开始查询物资柜子，模拟传的id，物资柜传的code
                        if (dto.getRestitutionToId() != null) {
                            // 模拟，无需处理
                        } else {
                            IsMaterialsCabinet cabinet = iIsMaterialsCabinetService.getOne(Wrappers.<IsMaterialsCabinet>lambdaQuery()
                                    .eq(IsMaterialsCabinet::getCabinetCode, dto.getRestitutionToCabinetCode()));
                            Assert.isFalse(cabinet == null, "通过物资柜code:" + dto.getRestitutionToCabinetCode() + "未查询到物资柜信息！");
                            dto.setRestitutionToId(cabinet.getCabinetId());
                        }
                        // 4.2开始更新归还记录表
                        ReturnLoanDTO returnLoanDTO = new ReturnLoanDTO();
                        returnLoanDTO.setMaterialsId(dto.getMaterialsId());
                        returnLoanDTO.setRestitutionUserId(userId);
                        returnLoanDTO.setRestitutionToId(dto.getRestitutionToId());
                        iIsMaterialsLoanService.returnIsMaterialsLoan(returnLoanDTO);
                    }
                } catch (Exception e) {
                    log.error("存在异常的存取数据：{}", e);
                    failRfidList.add(dto.getMaterialsRfid());
                }
            }
            // 更新检查记录
            iIsMaterialsPlanCabinetService.autoChangeCheckRecord(loanParamDTO.getList().get(0).getRestitutionToCabinetCode());
            // 5.检查有没有异常的物资，如果有，则返回提示
            if (!failRfidList.isEmpty()) {
                return "以下RFID本次存取失败：" + failRfidList;
            }
        }
        return "true";
    }

    private void handleOutSystemMaterials(String materialsRfid, String loanState, String restitutionToCabinetCode) {
        if (loanState.equals("1")) {
            IsMaterialsCabinet cabinetByCode = iIsMaterialsCabinetService.getCabinetByCode(restitutionToCabinetCode);
            // 开始存入异常存放-系统外物资
            IsMaterialsLoanException loanException = new IsMaterialsLoanException();
            loanException.setMaterialsId(null);
            loanException.setMaterialsRfid(materialsRfid);
            loanException.setMaterialsLoanId(null);
            loanException.setLoanFromId(null);
            loanException.setRestitutionUserId(SecurityUtils.getUserId());
            loanException.setRestitutionToId(cabinetByCode != null ? cabinetByCode.getCabinetId() : null);
            loanException.setOccurTime(new Date());
            loanException.setExceptionType("0");
            isMaterialsLoanExceptionService.save(loanException);
        }
        if (loanState.equals("0")) {
            isMaterialsLoanExceptionService.update(Wrappers.<IsMaterialsLoanException>lambdaUpdate()
                    .eq(IsMaterialsLoanException::getMaterialsRfid, materialsRfid)
                    .set(IsMaterialsLoanException::getHandleTime, new Date())
                    .set(IsMaterialsLoanException::getStatus, "1"));
        }
    }

    @Transactional
    @Override
    public String importMaterials(List<ImportMaterialsVO> itemList, boolean updateSupport, String operName) throws JsonProcessingException {
        Assert.notNull(itemList, "导入物资数据不能为空！");
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        for (ImportMaterialsVO materials : itemList) {
            // 0.检测第一行示例数据有没有被删除
            if ("测试白大褂(测试示例行可删除)".equals(materials.getMaterialsTypeName()) || "测试实验室(测试示例行可删除)".equals(materials.getSupplier())) {
                continue;
            }
            // 1.定义一个boolean，记录当前这条数据有没有问题
            boolean result = true;
            // 1.1定义一个物资类型id
            Long materialsTypeId = null;

            // 2.-----------------检查物资名称不能为空-------------------------------
            if (StringUtils.isBlank(materials.getMaterialsName())) {
                result = false;
                failureMsg.append("<br/>" + failureNum + "、物资名称 :" + materials.getMaterialsName() + " 不能为空");
            }
            // 3.-----------------检查物资类型不能为空-------------------------------
            if (StringUtils.isNotBlank(materials.getMaterialsTypeName())) {
                // 3.1检查物资类型是否在我们的系统中
                List<IsMaterialsType> materialsTypelist = iIsMaterialsTypeService.list(Wrappers.<IsMaterialsType>lambdaQuery()
                        .eq(IsMaterialsType::getMaterialsTypeName, materials.getMaterialsTypeName()));
                if (materialsTypelist.isEmpty()) {
                    result = false;
                    failureMsg.append("<br/>" + failureNum + "、物资分类 :" + materials.getMaterialsTypeName() + " 系统中无该物资类型");
                } else {
                    materialsTypeId = materialsTypelist.get(0).getMaterialsTypeId();
                }
            } else {
                result = false;
                failureMsg.append("<br/>" + failureNum + "、物资分类 :" + materials.getMaterialsName() + " 的物资分类不能为空");
            }
            // 4.---------------------检查rfid是否填写------------------------------
            if (StringUtils.isNotBlank(materials.getMaterialsRfid())) {
                // 4.1检查rfid是否被使用
                List<IsMaterials> materialslist = list(Wrappers.<IsMaterials>lambdaQuery()
                        .eq(IsMaterials::getMaterialsRfid, materials.getMaterialsRfid()));
                if (!materialslist.isEmpty()) {
                    result = false;
                    failureMsg.append("<br/>" + failureNum + "、物资RFID :" + materials.getMaterialsRfid() + " 已被使用");
                }
            } else {
                result = false;
                failureMsg.append("<br/>" + failureNum + "、物资RFID :" + materials.getMaterialsName() + " 的RFID不能为空");
            }
            // 5.---------------------检查物资柜信息------------------------------
            if (StringUtils.isNotBlank(materials.getCabinetName())) {
                List<IsMaterialsCabinet> cabinets = iIsMaterialsCabinetService.list(Wrappers.<IsMaterialsCabinet>lambdaQuery()
                        .eq(IsMaterialsCabinet::getCabinetName, materials.getCabinetName()));
                if (!cabinets.isEmpty()) {
                    materials.setMaterialsCabinetId(cabinets.get(0).getCabinetId());
                }
            }
            // 6.---------------------检查物资规格------------------------------
            if (StringUtils.isNotBlank(materials.getValueName())) {
                List<IsMaterialsPropertyValue> propertyValueList = iIsMaterialsPropertyValueService.list(Wrappers.<IsMaterialsPropertyValue>lambdaQuery()
                        .eq(IsMaterialsPropertyValue::getValueName, materials.getValueName()));
                if (!propertyValueList.isEmpty()) {
                    IsMaterialsProperty property = iIsMaterialsPropertyService.getById(propertyValueList.get(0).getPropertyId());
                    PropertyVO propertyVO = new PropertyVO();
                    propertyVO.setPropertyId(String.valueOf(property.getPropertyId()));
                    propertyVO.setPropertyName(property.getPropertyName());
                    propertyVO.setRecordId(String.valueOf(propertyValueList.get(0).getRecordId()));
                    propertyVO.setValueName(propertyValueList.get(0).getValueName());
                    // 使用 ObjectMapper 将对象转换为 JSON 字符串
                    ObjectMapper objectMapper = new ObjectMapper();
                    String jsonString = objectMapper.writeValueAsString(propertyVO);
                    materials.setProperties("[" + jsonString + "]");
                }
            }

            // 开始做最后的插入操作
            if (result) {
                successNum++;
                IsMaterials bean = BeanUtils.toBean(materials, IsMaterials.class);
                bean.setMaterialsTypeId(materialsTypeId);
                insertIsMaterials(bean);
            } else {
                failureNum++;
            }

        }
        // 总结
        if (failureNum > 0) {
            failureMsg.insert(0, "导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
        } else {
            if (successNum > 0) {
                successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条");
            } else {
                successMsg.insert(0, "导入失败！");
            }
        }
        return successMsg.toString();
    }

    @Override
    public Boolean updateMaterialsBinding(MaterialBindingDTO dto) {
        // 1.断言开道，bug闪开
        Assert.notNull(dto.getMaterialsCabinetId(), "物资柜信息不可为空!");
        Assert.isFalse(dto.getMaterialsIds().isEmpty(), "请选择物资!");
        // 2.开始更新啊
        return update(Wrappers.<IsMaterials>lambdaUpdate()
                .in(IsMaterials::getMaterialsId, dto.getMaterialsIds())
                .set(IsMaterials::getMaterialsCabinetId, dto.getMaterialsCabinetId()));
    }

    @Override
    public List<MaterialsPageVO> getExMaterials(MaterialsPageDTO dto) {
        // 查询异常未处理的归还物资
        List<IsMaterialsLoanException> exMaterials = isMaterialsLoanExceptionService.list(Wrappers.<IsMaterialsLoanException>lambdaQuery()
                .eq(IsMaterialsLoanException::getStatus, "0")
                .eq(dto.getMaterialsCabinetId() != null, IsMaterialsLoanException::getRestitutionToId, dto.getMaterialsCabinetId()));
        // 吧当前柜子的异常数据返回给前端
        List<MaterialsPageVO> materialsPageVOS = new ArrayList<>();
        if (!exMaterials.isEmpty()) {
            List<Long> materialsIds = exMaterials.stream().map(IsMaterialsLoanException::getMaterialsId).collect(Collectors.toList());
            materialsPageVOS = isMaterialsMapper.getExMaterials(materialsIds);
        }
        return materialsPageVOS;
    }

    @Override
    public List<CheckMaterialsDateVO> getCheckMaterialsByCabinetId(Long cabinetId) {
        return isMaterialsMapper.getCheckMaterialsByCabinetId(cabinetId);
    }

    @Override
    public List<IsMaterials> getMaterialListByRfid(List<String> rfidList) {
        return isMaterialsMapper.getMaterialListByRfid(rfidList);
    }

}
