package com.yuchen.saas.park.service.iot;

import com.alibaba.fastjson.JSON;
import com.google.gson.reflect.TypeToken;
import com.thinkunion.park.service.common.iot.capability.devicemodel.DeviceModel;
import com.thinkunion.park.service.common.iot.util.ModelGsonUtils;
import com.thinkunion.sdk.iot.bean.api.QueryProductProfileRequest;
import com.thinkunion.sdk.iot.bean.api.QueryProductProfileResponse;
import com.thinkunion.sdk.iot.bean.pojo.DeviceInfo;
import com.yuchen.saas.integration.feign.api.vo.DeviceInfoVO;
import com.yuchen.saas.integration.feign.api.vo.ProductInfoVO;
import com.yuchen.saas.park.api.entity.device.PmgBatSmartEquipment;
import com.yuchen.saas.park.api.event.GateEvent;
import com.yuchen.saas.park.api.vo.responsevo.ResponseVo;
import com.yuchen.saas.park.service.service.PmgBatSmartEquipmentService;
import lombok.extern.slf4j.Slf4j;
import org.nest.springwrap.core.tool.utils.Func;
import org.nest.springwrap.core.tool.utils.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * 根据productkey 查询设备列表
 * @author 刘通
 * @date 2020/12/26 0:26
 */
@Service
@Slf4j
public class IotClientServiceImpl implements IotClientService {

    @Resource
    private PmgBatSmartEquipmentService pmgBatSmartEquipmentService;

    @Autowired
    private IoTRemoteService ioTRemoteService;

    @Autowired
    private ApplicationContext applicationContext;

    private final Set<String> stubPlateNos = new HashSet<>();

    @Override
    public void providerStubPlateNo(String deviceName, String plateNo) {
        if (StringUtil.isNotBlank(deviceName) && StringUtil.isNotBlank(plateNo)) {
            this.stubPlateNos.add(deviceName.concat(plateNo));
        } else {
            log.warn("测试桩车牌号被忽略，值不能为空");
        }
    }

    @Override
    public void clearStubPlateNo() {
        this.stubPlateNos.clear();
    }

    /**
     * 通过 product key 获取其对应的设备列表，除应用端添加的设备外。
     * @param productKey
     * @return
     */
    @Override
    public ResponseVo getList(String productKey) {
        // 定义返回类
        ResponseVo responseVo = new ResponseVo();
        if (Func.isEmpty(productKey)) {
            return responseVo;
        }
        List<DeviceInfo> result = new ArrayList<>();
        List<DeviceInfo> deviceInfoList = ioTRemoteService.findDeviceList(productKey);
        List<PmgBatSmartEquipment> smartEquipmentList = pmgBatSmartEquipmentService.getDevicesListByKey(productKey);
        final List<String> names = new ArrayList<>();
        smartEquipmentList.forEach(smartEquipment -> {
            names.add(smartEquipment.getDeviceName());
        });
        deviceInfoList.stream().filter(deviceInfo -> !(names.contains(deviceInfo.getDeviceName())))
                .forEach(deviceInfo -> result.add(deviceInfo));
        responseVo.setData(result);
        return responseVo;
    }

    /**
     * 通过product key 获取 对应的设备集合
     * @param productKey
     * @return
     */
    @Override
    public ResponseVo getAllByProductKey(String productKey) {
        // 定义返回类
        ResponseVo responseVo = new ResponseVo();
        if (Func.isEmpty(productKey)) {
            return responseVo;
        }
        List<DeviceInfoVO> result = new ArrayList<>();
        ioTRemoteService.findDeviceList(productKey).forEach(deviceInfo -> {
            DeviceInfoVO deviceInfoVO = new DeviceInfoVO();
            deviceInfoVO.setProductKey(deviceInfo.getProductKey());
            deviceInfoVO.setDeviceName(deviceInfo.getDeviceName());
            deviceInfoVO.setAliasName(deviceInfo.getAliasName());
            deviceInfoVO.setDeviceSecret(deviceInfo.getDeviceSecret());
            result.add(deviceInfoVO);
        });
        responseVo.setData(result);
        return responseVo;
    }

    /**
     * 查询所有产品
     * @return
     */
    @Override
    public ResponseVo findAllProducts() {
        ResponseVo responseVo = new ResponseVo();
        final List<ProductInfoVO> result = new ArrayList<>();
        ioTRemoteService.findAllProduct().forEach(productInfo -> {
            ProductInfoVO productInfoVO = new ProductInfoVO();
            productInfoVO.setProductKey(productInfo.getProductKey());
            productInfoVO.setName(productInfo.getName());
            productInfoVO.setProductSecret(productInfo.getProductSecret());
            result.add(productInfoVO);
        });
        responseVo.setData(result);
        return responseVo;
    }

    @Override
    public DeviceModel getDeviceModel(String productKey) {
        return ioTRemoteService.getDeviceModel(productKey);
    }

    /**
     * 设备属性设置
     * @param body
     * @return
     */
    @Override
    public ResponseVo propertySet(Map<String, Object> body) {
        ioTRemoteService.setProperty(body);
        return new ResponseVo();
    }

    /**
     * 设备服务调用
     * @param body
     * @return
     */
    @Override
    public ResponseVo serviceCall(Map<String, Object> body) {
        ResponseVo responseVo = new ResponseVo();
        String deviceName = body.get("deviceName") != null ? body.get("deviceName").toString() : null;
        String plateNo = null;
        Object obj = body.get("params");
        if (obj instanceof Map) {
            Object plateNoObj = ((Map) obj).get("plateNo");
            if (plateNoObj != null) {
                plateNo = plateNoObj.toString();
            }
        }
        log.info("AIoT-[{}]接口调用 {}", body.get("identify").toString(), JSON.toJSONString(body));
        // 测试车牌号下发
        if (StringUtil.isNotBlank(deviceName) && StringUtil.isNotBlank(plateNo) && stubPlateNos
                .contains(deviceName.concat(plateNo))) {
            responseVo.setCode("200");
            responseVo.setMessage("操作成功");
            log.info("测试桩数据, 执行设备 {} 下发指令, 车牌号为 {}", deviceName, plateNo);
            applicationContext.publishEvent(new GateEvent(deviceName.concat(plateNo), body.get("identify").toString()));
        } else {
            Integer number = 1;
            do {
                number++;
                if (ioTRemoteService.callService(body)) {
                    number = 200;
                }
            } while (number < 6);

            if (number == 200) {
                responseVo.setCode("200");
                responseVo.setMessage("操作成功");
            } else {
                responseVo.setCode("400");
                responseVo.setMessage("操作失败");
            }
        }
        return responseVo;
    }


}
