package com.shkj.wms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shkj.common.constant.RedisConstant;
import com.shkj.common.core.domain.Result;
import com.shkj.common.utils.DateUtils;
import com.shkj.common.utils.SecurityUtils;
import com.shkj.plc.sdk.device.PLCReadAndWrite;
import com.shkj.plc.sdk.device.PlcOperate;
import com.shkj.wms.bo.WcsPlcConnectAddBo;
import com.shkj.wms.bo.WcsPlcPropertyAddBo;
import com.shkj.wms.bo.WcsPlcPropertyResetBo;
import com.shkj.wms.domain.WcsPlcConnect;
import com.shkj.wms.domain.WcsPlcProperty;
import com.shkj.wms.mapper.WcsPlcConnectMapper;
import com.shkj.wms.mapper.WcsPlcPropertyMapper;
import com.shkj.wms.plc.PlcInit;
import com.shkj.wms.service.IWcsPlcConnectService;
import com.shkj.wms.service.IWcsPlcPropertyService;
import com.shkj.wms.vo.WcsPlcConnectVo;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

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

/**
 * PLC连接Service业务层处理
 *
 * @author zjx
 * @date 2023-04-20
 */
@Service
public class WcsPlcConnectServiceImpl extends ServiceImpl<WcsPlcConnectMapper, WcsPlcConnect> implements IWcsPlcConnectService {
    @Resource
    WcsPlcConnectMapper wcsPlcConnectMapper;

    @Resource
    IWcsPlcPropertyService iWcsPlcPropertyService;

    @Resource
    WcsPlcPropertyMapper wcsPlcPropertyMapper;


    @Autowired
    PLCReadAndWrite plcReadAndWrite;

    @Resource
    RedisTemplate redisTemplate;

    @Resource
    PlcInit plcInit;


    /**
     * 查询PLC连接
     *
     * @param id PLC连接主键
     * @return PLC连接
     */
    @Override
    public WcsPlcConnect selectWcsPlcConnectById(Long id) {
        //根据PLCid获取连接信息
        WcsPlcConnect plcConnect = BeanUtil.toBean(redisTemplate.opsForValue().get(RedisConstant.redisPlcConnect + id),WcsPlcConnect.class);
        if (plcConnect == null){
            plcConnect =  wcsPlcConnectMapper.selectWcsPlcConnectById(id);
        }
        return plcConnect;
    }

    /**
     * 查询PLC连接列表
     *
     * @param wcsPlcConnect PLC连接
     * @return PLC连接
     */
    @Override
    public List<WcsPlcConnectVo> selectWcsPlcConnectList(WcsPlcConnect wcsPlcConnect) {
        return wcsPlcConnectMapper.selectWcsPlcConnectList(wcsPlcConnect);
    }


    /**
     * 新增PLC连接
     *
     * @param wcsPlcConnect PLC连接
     * @return 结果
     */
    @Override
    public Result<Boolean> insertWcsPlcConnect(WcsPlcConnectAddBo wcsPlcConnect) {

        List<WcsPlcPropertyAddBo> plcPropertyList = wcsPlcConnect.getPlcPropertyList();

        // 货位id是否重复
        List<String> listLocationCodes = plcPropertyList.stream().map(
                s -> (  s.getAddress())).distinct().collect(Collectors.toList());

        if (CollectionUtils.isEmpty(listLocationCodes)
                || listLocationCodes.size() != plcPropertyList.size()) {
            return Result.err().msg("设备属性，PLC地址重复!");
        }

        WcsPlcConnect wcsPlcConnectAdd = BeanUtil.toBean(wcsPlcConnect, WcsPlcConnect.class);
        wcsPlcConnectAdd.setCreateTime(DateUtils.getNowDate());
        wcsPlcConnectAdd.setBranchId(SecurityUtils.getCurrentBranchId());

        LambdaQueryWrapper<WcsPlcConnect> wrapper = new LambdaQueryWrapper<WcsPlcConnect>()
                .eq(WcsPlcConnect::getDevCode, wcsPlcConnectAdd.getDevCode())
                .or().eq(WcsPlcConnect::getConnectName,wcsPlcConnectAdd.getConnectName()).last("limit 1");
        WcsPlcConnect one = getOne(wrapper);
        if ( one!= null && one.getDevCode().equals(wcsPlcConnectAdd.getDevCode())) {
            return Result.err().msg("设备已绑定PLC连接");
        }
        if ( one!= null && one.getConnectName().equals(wcsPlcConnectAdd.getConnectName())) {
            return Result.err().msg("连接名称已经存在");
        }

        Map<String,String> pointMap=new HashMap<>(plcPropertyList.size());

        for (WcsPlcPropertyAddBo wcsPlcPropertyAddBo : plcPropertyList) {
            pointMap.put(wcsPlcPropertyAddBo.getAddress(),wcsPlcPropertyAddBo.getValueType());
        }

        wcsPlcConnectAdd.setPointTables(JSON.toJSONString(pointMap));
        wcsPlcConnectMapper.insertWcsPlcConnect(wcsPlcConnectAdd);
        Long id = wcsPlcConnectAdd.getId();

        List<WcsPlcProperty> plcPropertyAddList = new ArrayList<>();

        for (WcsPlcPropertyAddBo wcsPlcPropertyAddBo : plcPropertyList) {
            WcsPlcProperty wcsPlcProperty = BeanUtil.toBean(wcsPlcPropertyAddBo, WcsPlcProperty.class);
            wcsPlcProperty.setPlcId(id);
            wcsPlcProperty.setDevCode(wcsPlcConnect.getDevCode());
            pointMap.put(wcsPlcPropertyAddBo.getAddress(),wcsPlcPropertyAddBo.getValueType());
            plcPropertyAddList.add(wcsPlcProperty);
        }

        if(!iWcsPlcPropertyService.saveBatch(plcPropertyAddList)){
            return  Result.err().msg("保存plc连接属性失败");
        }

      //  redisTemplate.opsForHash().put(RedisConstant.redisPlcListConnect,wcsPlcConnectAdd.getId().toString(),wcsPlcConnectAdd);

        redisTemplate.opsForValue().set(RedisConstant.redisPlcConnect+wcsPlcConnectAdd.getId().toString(),wcsPlcConnectAdd);
        return Result.ok();
    }

    /**
     * 修改PLC连接
     *
     * @param wcsPlcConnect PLC连接
     * @return 结果
     */
    @Override
    public Result<Boolean> updateWcsPlcConnect(WcsPlcConnectAddBo wcsPlcConnect) {

        WcsPlcConnect wcsPlcConnectAdd = BeanUtil.toBean(wcsPlcConnect, WcsPlcConnect.class);
        wcsPlcConnectAdd.setUpdateTime(DateUtils.getNowDate());
        wcsPlcConnectMapper.updateById(wcsPlcConnectAdd);

        List<WcsPlcProperty> plcPropertyAddList = new ArrayList<>();
        List<WcsPlcPropertyAddBo> plcPropertyList = wcsPlcConnect.getPlcPropertyList();
        for (WcsPlcPropertyAddBo wcsPlcPropertyAddBo : plcPropertyList) {
            WcsPlcProperty wcsPlcProperty = BeanUtil.toBean(wcsPlcPropertyAddBo, WcsPlcProperty.class);
            wcsPlcProperty.setDevCode(wcsPlcConnect.getDevCode());
            plcPropertyAddList.add(wcsPlcProperty);
        }

        if(!iWcsPlcPropertyService.updateBatchById(plcPropertyAddList)){
            return  Result.err().msg("修改plc连接属性失败");
        }

        //redisTemplate.opsForHash().put(RedisConstant.redisPlcListConnect,wcsPlcConnectAdd.getId().toString(),wcsPlcConnectAdd);

        redisTemplate.opsForValue().set(RedisConstant.redisPlcConnect+wcsPlcConnectAdd.getId().toString(),wcsPlcConnectAdd);

        return Result.ok();
    }

    /**
     * 删除PLC连接
     *
     * @param id 需要删除的PLC连接主键
     * @return 结果
     */
    @Override
    public Result<Boolean> deleteWcsPlcConnectById(Long id) {
        this.baseMapper.deleteWcsPlcConnectById(id);
        wcsPlcPropertyMapper.deleteWcsPlcPropertyByPlcId(id);
        redisTemplate.opsForHash().delete(RedisConstant.redisPlcListConnect,id.toString());
        redisTemplate.delete(RedisConstant.redisPlcConnect+id.toString());
        return Result.ok();
    }


    @Override
    public Result<Boolean> writePlcPoint(WcsPlcPropertyResetBo bo) {
        PlcOperate plcOperate =plcInit.getPlcOperateByIp(bo.getPlcIp());
        plcReadAndWrite.execWrite(plcOperate, bo.getResetPoint());
        return Result.ok();
    }


    @Override
    public Result<Boolean> switchStatus(Long id, String status) {
        WcsPlcConnect wcsPlcConnect = new WcsPlcConnect();
        wcsPlcConnect.setId(id).setIsActive(status);
        return this.updateById(wcsPlcConnect) ? Result.ok() : Result.err();
    }
}
