package com.zehong.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.zehong.common.constant.RoboticArmConstans;
import com.zehong.common.core.domain.AjaxResult;
import com.zehong.common.utils.DateUtils;
import com.zehong.common.utils.StringUtils;
import com.zehong.common.utils.http.HttpUtils;
import com.zehong.system.domain.*;
import com.zehong.system.mapper.PalletDeviceBindingMapper;
import com.zehong.system.mapper.ProductStandardInspectionMapper;
import com.zehong.system.mapper.TTrayInfoMapper;
import com.zehong.system.service.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 托盘绑定的设备列Service业务层处理
 *
 * @author zehong
 * @date 2025-06-29
 */
@Service
public class PalletDeviceBindingServiceImpl implements IPalletDeviceBindingService
{
    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(PalletDeviceBindingServiceImpl.class);
    @Resource
    private IUploadMesResultHistoryService uploadMesResultHistoryService;
    @Resource
    private PalletDeviceBindingMapper palletDeviceBindingMapper;
    @Resource
    private IPalletDeviceUploadHistoryService palletDeviceUploadHistoryService;

    @Resource
    private IPalletDeviceUploadFailureService iPalletDeviceUploadFailureService;

    @Resource
    private ISysConfigService sysConfigService;
    @Resource
    private TTrayInfoMapper tTrayInfoMapper;

    @Resource
    private ProductStandardInspectionMapper productStandardInspectionMapper;

    /**
     * 查询托盘绑定的设备列
     *
     * @param palletDeviceBindingId 托盘绑定的设备列ID
     * @return 托盘绑定的设备列
     */
    @Override
    public PalletDeviceBinding selectPalletDeviceBindingById(Long palletDeviceBindingId)
    {
        return palletDeviceBindingMapper.selectPalletDeviceBindingById(palletDeviceBindingId);
    }

    /**
     * 查询托盘绑定的设备列列表
     *
     * @param palletDeviceBinding 托盘绑定的设备列
     * @return 托盘绑定的设备列
     */
    @Override
    public List<PalletDeviceBinding> selectPalletDeviceBindingList(PalletDeviceBinding palletDeviceBinding)
    {
        return palletDeviceBindingMapper.selectPalletDeviceBindingList(palletDeviceBinding);
    }

    /**
     * 获取所有未解除绑定的托盘绑定的设备列
     *
     * @param trayId 托盘ID
     * @return 列表
     */
    @Override
    public List<PalletDeviceBinding> getAllExcludeUnbindingTimeByTrayId(Long trayId) {

        return palletDeviceBindingMapper.getAllExcludeUnbindingTimeByTrayId(trayId);
    }

    /**
     * 根据托盘码查询托盘绑定的设备列
     *
     * @param trayCode 托盘码
     * @return 列表
     */
    @Override
    public List<PalletDeviceBinding> listByTrayCode(String trayCode) {
        return palletDeviceBindingMapper.listByTrayCode(trayCode);
    }

    @Override
    public void batchUpdateAdAndStatus(List<PalletDeviceBinding> palletDeviceBindingList) {
        palletDeviceBindingMapper.batchUpdateAdAndStatus(palletDeviceBindingList);
    }

    /**
     * 新增托盘绑定的设备列
     *
     * @param palletDeviceBinding 托盘绑定的设备列
     * @return 结果
     */
    @Override
    public int insertPalletDeviceBinding(PalletDeviceBinding palletDeviceBinding)
    {
        palletDeviceBinding.setCreateTime(DateUtils.getNowDate());
        return palletDeviceBindingMapper.insertPalletDeviceBinding(palletDeviceBinding);
    }

    /**
     * 重置所有托盘绑定的设备列
     *
     * @param trayId 托盘ID
     * @return 结果
     */
    @Override
    public AjaxResult resetAll(Long trayId) {

        int i = palletDeviceBindingMapper.countErrorByTrayId(trayId);
        if (i > 0) {
            return AjaxResult.error("有错误设备未解除绑定，不允许重置");
        }

        palletDeviceBindingMapper.resetAll(trayId);

        tTrayInfoMapper.initStatusByTrayId(trayId);

        return AjaxResult.success();
    }

    /**
     * 批量添加托盘绑定的设备列
     *
     * @param palletDeviceBindingList 托盘绑定的设备列
     * @return 结果
     */
    @Override
    public List<PalletDeviceBinding> batchInsertPalletDeviceBinding(List<PalletDeviceBinding> palletDeviceBindingList) {

        check(palletDeviceBindingList);

        // 获取所有不为空的 deviceCode
        List<String> validDeviceCodes = palletDeviceBindingList.stream()
                .filter(item -> StringUtils.isNotBlank(item.getMotherboardCode()))
                .map(PalletDeviceBinding::getMotherboardCode)
                .collect(Collectors.toList());

        int i1 = palletDeviceBindingMapper.checkRepeat(validDeviceCodes);
        if(i1 > 0) {
            throw new RuntimeException("有重复绑定设备码");
        }

        palletDeviceBindingList.forEach(palletDeviceBinding -> {
            palletDeviceBinding.setUpdateTime(DateUtils.getNowDate());
            palletDeviceBinding.setCreateTime(DateUtils.getNowDate());
            palletDeviceBinding.setBindingTime(DateUtils.getNowDate());
            // 默认状态为未解除绑定
            palletDeviceBinding.setCalibrationUnbindStatus("0");
        });

        TTrayInfo tTrayInfo  = new TTrayInfo();
        tTrayInfo.setfTrayId(palletDeviceBindingList.get(0).getTrayId());
        tTrayInfo.setfStatus("4");
        tTrayInfoMapper.updateStatusByTrayId(tTrayInfo);
        int i = palletDeviceBindingMapper.batchInsertPalletDeviceBinding(palletDeviceBindingList);
        if(i <= 0) {
            throw new RuntimeException("添加失败");
        }
        return palletDeviceBindingList;
    }

    @Override
    public int batchUpdateDeviceCode(List<PalletDeviceBinding> palletDeviceBindingList) {
        check(palletDeviceBindingList);
        palletDeviceBindingList.forEach(palletDeviceBinding -> {
            palletDeviceBinding.setDeviceStatus("1");
            palletDeviceBinding.setUpdateTime(DateUtils.getNowDate());
        });

        tTrayInfoMapper.updateToBoundWhenStateIsIdle(palletDeviceBindingList.get(0).getTrayId());

        return palletDeviceBindingMapper.batchUpdateDeviceCode(palletDeviceBindingList);
    }


    private void check(List<PalletDeviceBinding> palletDeviceBindingList) {

        if(palletDeviceBindingList == null || palletDeviceBindingList.size() ==0) {
            throw new RuntimeException("数据不能为空");
        }

        boolean b = palletDeviceBindingList.stream().allMatch(item->StringUtils.isBlank(item.getMotherboardCode()));
        if(b) {
            throw new RuntimeException("不能所有设备号都为空！！！");
        }
    }

    @Override
    public int batchUpdateDeviceCodeAndUnbindingTime(List<PalletDeviceBinding> palletDeviceBindingList) {
        palletDeviceBindingList.forEach(palletDeviceBinding -> {
            palletDeviceBinding.setDeviceStatus("1");
            palletDeviceBinding.setUpdateTime(DateUtils.getNowDate());
        });

        tTrayInfoMapper.updateToBoundWhenStateIsIdle(palletDeviceBindingList.get(0).getTrayId());

        return palletDeviceBindingMapper.batchUpdateDeviceCodeAndUnbindingTime(palletDeviceBindingList);
    }

    /**
     * 修改托盘绑定的设备列
     *
     * @param palletDeviceBinding 托盘绑定的设备列
     * @return 结果
     */
    @Override
    public int updatePalletDeviceBinding(PalletDeviceBinding palletDeviceBinding)
    {
        return palletDeviceBindingMapper.updatePalletDeviceBinding(palletDeviceBinding);
    }

    /**
     * 批量删除托盘绑定的设备列
     *
     * @param palletDeviceBindingIds 需要删除的托盘绑定的设备列ID
     * @return 结果
     */
    @Override
    public int deletePalletDeviceBindingByIds(Long[] palletDeviceBindingIds)
    {
        return palletDeviceBindingMapper.deletePalletDeviceBindingByIds(palletDeviceBindingIds);
    }

    /**
     * 删除托盘绑定的设备列信息
     *
     * @param palletDeviceBindingId 托盘绑定的设备列ID
     * @return 结果
     */
    @Override
    public int deletePalletDeviceBindingById(Long palletDeviceBindingId)
    {
        return palletDeviceBindingMapper.deletePalletDeviceBindingById(palletDeviceBindingId);
    }

    /**
     * 批量解绑所有设备
     *
     * @param trayId 托盘ID
     * @return 删除结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized AjaxResult unbindAllDevice(Long trayId) {

        if(trayId == null) {
            return AjaxResult.error("参数错误");
        }
        // 所有设备都是正常的一键解绑
        initMesDataAndUpload(trayId);

        // 解绑设备
        palletDeviceBindingMapper.unbindAllDevice(trayId);

        // 初始托盘状态
        tTrayInfoMapper.initStatusByTrayId(trayId);

        return AjaxResult.success();
    }

    /**
     * 解绑设备
     *
     * @param palletDeviceBinding 托盘绑定的设备列ID
     * @return 删除结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized AjaxResult unbindDevice(PalletDeviceBinding palletDeviceBinding) {

        if(palletDeviceBinding.getPalletDeviceBindingId() == null || StringUtils.isBlank(palletDeviceBinding.getMotherboardCode())) {
            return AjaxResult.error("参数错误");
        }
        PalletDeviceBinding palletDeviceBindingDb = palletDeviceBindingMapper.selectPalletDeviceBindingById(palletDeviceBinding.getPalletDeviceBindingId());
        if(palletDeviceBindingDb == null) {
            return AjaxResult.error("数据不存在");
        }

        if(!palletDeviceBindingDb.getMotherboardCode().equals(palletDeviceBinding.getMotherboardCode())) {
            return AjaxResult.error("设备码错误");
        }

        int i = palletDeviceBindingMapper.unbindDeviceByCalibrationUnbindStatus(palletDeviceBindingDb.getPalletDeviceBindingId());
        if (i > 0) {
            return AjaxResult.success();
        }
        return AjaxResult.error();
    }

    // 成功之后 判断 是否还有设备，如果没有设备的话则 初始化托盘状态
//    int count = palletDeviceBindingMapper.countDeviceByTrayId(palletDeviceBindingDb.getTrayId());
//    if(count == 0) {
//        tTrayInfoMapper.initStatusByTrayId(palletDeviceBindingDb.getTrayId());
//    }

    /**
     * 初始化MES数据并上传
     */
    private void initMesDataAndUpload(Long trayId) {

        List<PalletDeviceBinding> palletDeviceBindings = palletDeviceBindingMapper.listByTrayId(trayId);

        if(palletDeviceBindings == null || palletDeviceBindings.size() == 0)  return;

        List<PalletDeviceBinding> mesDeviceDomains = palletDeviceBindings.stream().filter(item -> item.getMotherboardCode() != null).collect(Collectors.toList());
        if(mesDeviceDomains.size() == 0) return;

        String productStandardInspectionNumber = mesDeviceDomains.get(0).getProductStandardInspectionNumber();
        if(StringUtils.isBlank(productStandardInspectionNumber)) {
            throw new RuntimeException("产品标准检验编号不能为空");
        }

        ProductStandardInspection productStandardInspection = productStandardInspectionMapper.selectByProductStandardInspectionNumber(productStandardInspectionNumber);
        if(productStandardInspection == null) {
            throw new RuntimeException("标检单不存在");
        }
        // 统计合格数量 (1)
        long qualifiedCount = mesDeviceDomains.stream()
                .filter(device -> "1".equals(device.getStandardInspectResult()))
                .count();

        // 统计不合格数量 (0)
        long unqualifiedCount = mesDeviceDomains.stream()
                .filter(device -> "0".equals(device.getStandardInspectResult()))
                .count();

        Long qualifiedNum = productStandardInspection.getQualifiedNum();
        if(qualifiedNum == null) {
            qualifiedNum = 0L;
        }
        Long unQualifiedNum = productStandardInspection.getUnQualifiedNum();
        if(unQualifiedNum == null) {
            unQualifiedNum = 0L;
        }

        productStandardInspection.setQualifiedNum(qualifiedCount + qualifiedNum);
        productStandardInspection.setUnQualifiedNum(unqualifiedCount + unQualifiedNum);

        if(productStandardInspection.getQualifiedNum() >= productStandardInspection.getQuantity()) {
            productStandardInspection.setStatus("STANDARD_INSPECTION_COMPLETED");
        }

        productStandardInspectionMapper.updateProductStandardInspection(productStandardInspection);

        // 20251210 领导说 先 保存所有历史数据
        palletDeviceUploadHistoryService.batchInsertRealTimeData(mesDeviceDomains);

        String mesUploadAddress = sysConfigService.directSelectConfigByKey(RoboticArmConstans.UPLOAD_MES_ADDRESS);
        if(StringUtils.isNotBlank(mesUploadAddress)) {
            try {
                String result = HttpUtils.sendPost(mesUploadAddress, JSON.toJSONString(mesDeviceDomains));
                UploadMesResultHistory uploadMesResultHistory = new UploadMesResultHistory();
                uploadMesResultHistory.setMessage(result);
                uploadMesResultHistoryService.insertUploadMesResultHistory(uploadMesResultHistory);
                if(StringUtils.isNotBlank(result)) {
                    JSONObject jsonObject = JSON.parseObject(result);
                    if(jsonObject.getInteger("code") != 200) {
                        String data = jsonObject.getString("data");
                        // 处理错误数据逻辑，再弄个错误数据的表
                        if(StringUtils.isNotBlank(data)) {
                            // 存失败记录
                            processPalletDeviceUploadFailure(mesDeviceDomains,data);
                        } else{
                            iPalletDeviceUploadFailureService.batchInsertRealTimeData(mesDeviceDomains);
                        }
                    }
                }
            } catch (Exception e) {
                iPalletDeviceUploadFailureService.batchInsertRealTimeData(mesDeviceDomains);
            }
        }
    }

    /**
     * 处理托盘设备上传历史数据
     */
    private void processPalletDeviceUploadFailure(List<PalletDeviceBinding> palletDeviceBindings,String data){
        JSONObject jsonObject = JSON.parseObject(data);

        if (!jsonObject.containsKey("failedCodes")) {
            return;
        } else {
            log.info("上传失败；没有返回正确数据");
        }

        JSONArray failedCodes = jsonObject.getJSONArray("failedCodes");
        if (failedCodes == null || failedCodes.isEmpty()) {
            return;
        }

        // 使用Set提高查找效率
        Set<String> failedCodeSet = failedCodes.stream()
                .map(Object::toString)
                .collect(Collectors.toSet());

        List<PalletDeviceBinding> palletDeviceUploadFailureList = palletDeviceBindings.stream()
                .filter(binding -> failedCodeSet.contains(binding.getMotherboardCode()))
                .collect(Collectors.toList());

        if (!palletDeviceUploadFailureList.isEmpty()) {
            iPalletDeviceUploadFailureService.batchInsertRealTimeData(palletDeviceUploadFailureList);
        }
    }
}
