package com.kym.service.aliyun.lot;

import com.aliyun.iot20180120.models.*;
import com.aliyun.tea.TeaModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import jakarta.annotation.PostConstruct;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Base64;
import java.util.List;

/**
 * 阿里云物联网平台
 *
 * @author skyline
 */
@Slf4j
@Component
public class AliyunLotClient {

    private static com.aliyun.iot20180120.Client rRpcClient;

    private static final Base64.Encoder encoder = Base64.getEncoder();
    private static String iotInstanceId;
    private static String productKey;
    @Value("${aliyun.lot.amqp.accessKey}")
    private String accessKey;
    @Value("${aliyun.lot.amqp.accessSecret}")
    private String accessSecret;

    @Value("${aliyun.lot.amqp.iotInstanceId}")
    public void setIotInstanceId(String iotInstanceId) {
        AliyunLotClient.iotInstanceId = iotInstanceId;
    }

    @Value("${aliyun.lot.productKey}")
    public void setProductKey(String productKey) {
        AliyunLotClient.productKey = productKey;
    }

    public static String getProductKey() {
        return productKey;
    }

    /**
     * 调用Iot20180120客户端发送请求
     * 2.CreateSubscribeRelation 创建MNS或AMQP服务端订阅
     */
    public static CreateSubscribeRelationResponseBody createSubscribeRelation(com.aliyun.iot20180120.Client client, String instanceId, String productKey, String type, Boolean deviceDataFlag, Boolean deviceLifeCycleFlag, Boolean deviceStatusChangeFlag, Boolean deviceTagFlag, Boolean deviceTopoLifeCycleFlag, Boolean foundDeviceListFlag, Boolean otaEventFlag, Boolean otaJobFlag, Boolean otaVersionFlag, Boolean thingHistoryFlag, String mnsConfiguration, String consumerGroupIds) throws Exception {
        CreateSubscribeRelationRequest request = new CreateSubscribeRelationRequest().setProductKey(productKey).setType(type).setIotInstanceId(instanceId).setThingHistoryFlag(thingHistoryFlag).setOtaVersionFlag(otaVersionFlag).setOtaJobFlag(otaJobFlag).setOtaEventFlag(otaEventFlag).setFoundDeviceListFlag(foundDeviceListFlag).setDeviceTopoLifeCycleFlag(deviceTopoLifeCycleFlag).setDeviceTagFlag(deviceTagFlag).setDeviceStatusChangeFlag(deviceStatusChangeFlag).setDeviceLifeCycleFlag(deviceLifeCycleFlag).setDeviceDataFlag(deviceDataFlag).setMnsConfiguration(mnsConfiguration);
        // 创建的AMQP订阅中的消费组ID，Type为AMQP时必填。
        if (!com.aliyun.teautil.Common.empty(consumerGroupIds)) {
            request.consumerGroupIds = Arrays.stream(consumerGroupIds.split(",", 100)).toList();
        }

        log.info("-------------------2.CreateSubscribeRelation 创建MNS或AMQP服务端订阅--------------------");
        CreateSubscribeRelationResponse response = client.createSubscribeRelation(request);
        log.info(com.aliyun.teautil.Common.toJSONString(TeaModel.buildMap(response.body)));
        return response.body;
    }

    /**
     * 调用Iot20180120客户端发送请求
     * 3.UpdateSubscribeRelation 修改MNS或AMQP服务端订阅
     */
    public static UpdateSubscribeRelationResponseBody updateSubscribeRelation(com.aliyun.iot20180120.Client client, String iotInstanceId, String productKey, String type, Boolean deviceDataFlag, Boolean deviceLifeCycleFlag, Boolean deviceStatusChangeFlag, Boolean deviceTagFlag, Boolean deviceTopoLifeCycleFlag, Boolean foundDeviceListFlag, Boolean otaEventFlag, Boolean otaJobFlag, Boolean otaVersionFlag, Boolean thingHistoryFlag, String mnsConfiguration, String consumerGroupIds) throws Exception {
        UpdateSubscribeRelationRequest request = new UpdateSubscribeRelationRequest().setProductKey(productKey).setType(type).setIotInstanceId(iotInstanceId).setThingHistoryFlag(thingHistoryFlag).setOtaVersionFlag(otaVersionFlag).setOtaJobFlag(otaJobFlag).setOtaEventFlag(otaEventFlag).setFoundDeviceListFlag(foundDeviceListFlag).setDeviceTopoLifeCycleFlag(deviceTopoLifeCycleFlag).setDeviceTagFlag(deviceTagFlag).setDeviceStatusChangeFlag(deviceStatusChangeFlag).setDeviceLifeCycleFlag(deviceLifeCycleFlag).setDeviceDataFlag(deviceDataFlag).setMnsConfiguration(mnsConfiguration);
        // 创建的AMQP订阅中的消费组ID，Type为AMQP时必填。
        if (!com.aliyun.teautil.Common.empty(consumerGroupIds)) {
            request.consumerGroupIds = Arrays.stream(consumerGroupIds.split(",", 100)).toList();
        }

        log.info("-------------------3.UpdateSubscribeRelation 修改MNS或AMQP服务端订阅--------------------");
        UpdateSubscribeRelationResponse response = client.updateSubscribeRelation(request);
        log.info(com.aliyun.teautil.Common.toJSONString(TeaModel.buildMap(response.body)));
        return response.body;
    }

    /**
     * 调用Iot20180120客户端发送请求
     * 4.DeleteSubscribeRelation 删除MNS或AMQP服务端订阅
     */
    public static DeleteSubscribeRelationResponseBody deleteSubscribeRelation(com.aliyun.iot20180120.Client client, String iotInstanceId, String productKey, String type) throws Exception {
        DeleteSubscribeRelationRequest request = new DeleteSubscribeRelationRequest().setProductKey(productKey).setType(type).setIotInstanceId(iotInstanceId);
        log.info("-------------------4.DeleteSubscribeRelation 删除MNS或AMQP服务端订阅--------------------");
        DeleteSubscribeRelationResponse response = client.deleteSubscribeRelation(request);
        log.info(com.aliyun.teautil.Common.toJSONString(TeaModel.buildMap(response.body)));
        return response.body;
    }

    public static RRpcResponse rRpc(String productKey, String deviceName, String requestJson) throws Exception {
        var requestBase64Byte = new String(encoder.encode(requestJson.getBytes()));
        var request = new RRpcRequest().setIotInstanceId(iotInstanceId).setProductKey(productKey).setDeviceName(deviceName).setRequestBase64Byte(requestBase64Byte);
        // 等待设备回复消息的时间，单位是毫秒，取值范围是1,000 ~8,000。
        // 校验integer型入参
        Integer iTimeout = 8000;
        request.setTimeout(iTimeout);
        log.info("-------------------1.RRpc：向指定设备发送请求消息，并同步返回响应--------------------");
        RRpcResponse response = rRpcClient.rRpc(request);
        log.info(com.aliyun.teautil.Common.toJSONString(TeaModel.buildMap(response)));
        return response;
    }

    /**
     * 调用Iot20180120客户端发送请求
     * 1.RRpc：向指定设备发送请求消息，并同步返回响应
     */
    public static RRpcResponse rRpc(com.aliyun.iot20180120.Client client, String iotInstanceId, String productKey, String deviceName, String requestBase64Byte, String timeout, String topic) throws Exception {
        var request = new RRpcRequest().setIotInstanceId(iotInstanceId).setProductKey(productKey).setDeviceName(deviceName).setRequestBase64Byte(requestBase64Byte).setTopic(topic);
        // 等待设备回复消息的时间，单位是毫秒，取值范围是1,000 ~8,000。
        // 校验integer型入参
        Integer iTimeout = Integer.parseInt(timeout);
        request.setTimeout(iTimeout);
        log.info("-------------------1.RRpc：向指定设备发送请求消息，并同步返回响应--------------------");
        RRpcResponse response = client.rRpc(request);
        log.info(com.aliyun.teautil.Common.toJSONString(TeaModel.buildMap(response)));
        return response;
    }

    /**
     * 调用Iot20180120客户端发送请求
     * 2.PubBroadcast 向指定产品所有设备，或向订阅了指定Topic的所有设备发布广播消息
     */
    public static PubBroadcastResponse pubBroadcast(com.aliyun.iot20180120.Client client, String iotInstanceId, String productKey, String messageContent, String topic) throws Exception {
        PubBroadcastRequest request = new PubBroadcastRequest().setIotInstanceId(iotInstanceId).setProductKey(productKey).setMessageContent(messageContent).setTopicFullName(topic);
        log.info("-------------------2.PubBroadcast 向指定产品所有设备，或向订阅了指定Topic的所有设备发布广播消息--------------------");
        PubBroadcastResponse response = client.pubBroadcast(request);
        log.info(com.aliyun.teautil.Common.toJSONString(TeaModel.buildMap(response)));
        return response;
    }

    /**
     * 调用Iot20180120客户端发送请求
     * 3.SubscribeTopic 为指定设备订阅Topic
     */
    public static SubscribeTopicResponse subscribeTopic(com.aliyun.iot20180120.Client client, String iotInstanceId, String productKey, String deviceName, String topicStr) throws Exception {
        // 要订阅的Topic，最多订阅10个Topic。
        // Topic的操作权限必须为订阅或发布和订阅。
        List<String> arrTopic = Arrays.stream(topicStr.split(",", 10)).toList();
        SubscribeTopicRequest request = new SubscribeTopicRequest().setIotInstanceId(iotInstanceId).setProductKey(productKey).setDeviceName(deviceName).setTopic(arrTopic);
        log.info("-------------------3.SubscribeTopic 为指定设备订阅Topic--------------------");
        SubscribeTopicResponse response = client.subscribeTopic(request);
        log.info(com.aliyun.teautil.Common.toJSONString(TeaModel.buildMap(response)));
        return response;
    }

    /**
     * 注册设备到阿里云物联网平台
     *
     * @param productKey 产品Key
     * @param deviceName 设备名称
     * @return RegisterDeviceResponseBody.Data 包含 deviceName, deviceSecret, iotId 等
     */
    public static RegisterDeviceResponseBody.RegisterDeviceResponseBodyData registerDevice(String productKey, String deviceName) throws Exception {
        RegisterDeviceRequest request = new RegisterDeviceRequest()
                .setIotInstanceId(iotInstanceId)
                .setProductKey(productKey)
                .setDeviceName(deviceName);
        log.info("-------------------RegisterDevice 注册设备：productKey={}, deviceName={}--------------------", productKey, deviceName);
        RegisterDeviceResponse response = rRpcClient.registerDevice(request);
        log.info(com.aliyun.teautil.Common.toJSONString(TeaModel.buildMap(response.body)));
        if (!response.body.success) {
            throw new RuntimeException("阿里云物联网平台注册设备失败: " + response.body.errorMessage);
        }
        return response.body.data;
    }

    /**
     * 从阿里云物联网平台删除设备
     *
     * @param productKey 产品Key
     * @param deviceName 设备名称
     */
    public static void deleteDevice(String productKey, String deviceName) throws Exception {
        DeleteDeviceRequest request = new DeleteDeviceRequest()
                .setIotInstanceId(iotInstanceId)
                .setProductKey(productKey)
                .setDeviceName(deviceName);
        log.info("-------------------DeleteDevice 删除设备：productKey={}, deviceName={}--------------------", productKey, deviceName);
        DeleteDeviceResponse response = rRpcClient.deleteDevice(request);
        log.info(com.aliyun.teautil.Common.toJSONString(TeaModel.buildMap(response.body)));
        if (!response.body.success) {
            throw new RuntimeException("阿里云物联网平台删除设备失败: " + response.body.errorMessage);
        }
    }

    /**
     * 调用Iot20180120客户端发送请求
     * 1.QuerySubscribeRelation 查询MNS或AMQP服务端订阅
     * Type取值:MNS,AMQP
     */
    public static void querySubscribeRelation(com.aliyun.iot20180120.Client client, String instanceId, String productKey, String type) throws Exception {
        QuerySubscribeRelationRequest request = new QuerySubscribeRelationRequest().setProductKey(productKey).setType(type).setIotInstanceId(instanceId);
        log.info("-------------------1.QuerySubscribeRelation 查询MNS或AMQP服务端订阅--------------------");
        QuerySubscribeRelationResponse response = client.querySubscribeRelation(request);
        log.info(com.aliyun.teautil.Common.toJSONString(TeaModel.buildMap(response.body)));
    }

    /**
     * 初始化IoT(Iot20180120)客户端
     */
    @PostConstruct
    public void init() throws Exception {
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
                .setRegionId("cn-shanghai")
                .setAccessKeyId(accessKey)
                .setAccessKeySecret(accessSecret)
                .setConnectTimeout(5000)
                .setReadTimeout(10000);
        rRpcClient = new com.aliyun.iot20180120.Client(config);
    }

    void t1() {
        java.util.List<String> args = java.util.Arrays.asList("");
        // * param.1:IotInstanceId 实例ID
        // 您可在物联网平台控制台的实例概览页面，查看当前实例的ID。若有ID值，必须传入该ID值，否则调用会失败。
        // 如何获取到实例ID:https://help.aliyun.com/document_detail/267533.htm
        String argIotInstanceId = "";
        // * param.2:ProductKey 产品KEY
        String argProductKey = "";
        // * param.3:Type 订阅类型
        // 取值：MNS，AMQP。
        String argType = "";
        // * param.4:MnsConfiguration MNS队列的配置信息
        // Type为MNS时必填。
        // 具体要求和示例见API[CreateSubscribeRelation]或[UpdateSubscribeRelation]说明文档中的“MnsConfiguration定义”。
        String argMnsConfiguration = "";
        // * param.5:ConsumerGroupIds 创建的AMQP订阅中的消费组ID
        // Type为AMQP时必填。多个内容用半角逗号[,]分隔。
        // 调用CreateConsumerGroup创建消费组成功后，会返回消费组ID。
        // 您可以调用QueryConsumerGroupList按消费组名称查询消费组ID，也可以在物联网平台控制台对应实例下，选择规则引擎>服务端订阅>消费组列表，查看消费组ID。
        String argConsumerGroupIds = "";
        // * param.6:DeviceTopoLifeCycleFlag 推送消息类型是否选择设备拓扑关系变更。
        // 默认值为false。true:仅对网关产品有效
        Boolean argDeviceTopoLifeCycleFlag = false;
        // * param.7:FoundDeviceListFlag 推送消息类型是否选择网关子设备发现上报。
        // 默认值为false。true:仅对网关产品有效
        Boolean argFoundDeviceListFlag = false;
        // * param.8:DeviceLifeCycleFlag 推送消息类型是否选择设备生命周期变更
        // 默认值为false
        Boolean argDeviceLifeCycleFlag = false;
        // * param.9:ThingHistoryFlag 推送消息类型是否选择物模型历史数据上报。
        // 默认值为false
        Boolean argThingHistoryFlag = false;
        // * param.10:OtaEventFlag 推送消息类型是否选择OTA升级状态通知。
        // 默认值为false
        Boolean argOtaEventFlag = false;
        // * param.11:DeviceTagFlag 推送消息类型是否选择设备标签变更。
        // 默认值为false。true:仅当Type为AMQP时有效。
        Boolean argDeviceTagFlag = false;
        // * param.12:OtaVersionFlag 推送消息类型是否选择OTA模块版本号上报。
        // 默认值为false。true:仅当Type为AMQP时有效。
        Boolean argOtaVersionFlag = false;
        // * param.13:OtaJobFlag 推送消息类型是否选择OTA升级批次状态通知。
        // 默认值为false。true:仅当Type为AMQP时有效。
        Boolean argOtaJobFlag = false;
        // * param.14:DeviceDataFlag 推送消息类型是否选择设备上报消息。
        // 默认值为false
        Boolean argDeviceDataFlag = false;
        // * param.15:DeviceStatusChangeFlag 推送消息类型是否选择设备状态变化通知。
        // 默认值为false
        Boolean argDeviceStatusChangeFlag = false;
        log.info("hello world!");
        // 【发起客户端调用】
        try {
            com.aliyun.iot20180120.Client client = null;
            log.info("第一步：查询服务端订阅 ---> 初始状态");
            this.querySubscribeRelation(client, argIotInstanceId, argProductKey, argType);
            log.info("第二步：创建服务端订阅");
            CreateSubscribeRelationResponseBody createResponseBody = this.createSubscribeRelation(client, argIotInstanceId, argProductKey, argType, argDeviceDataFlag, argDeviceLifeCycleFlag, argDeviceStatusChangeFlag, argDeviceTagFlag, argDeviceTopoLifeCycleFlag, argFoundDeviceListFlag, argOtaEventFlag, argOtaJobFlag, argOtaVersionFlag, argThingHistoryFlag, argMnsConfiguration, argConsumerGroupIds);
            if (!createResponseBody.success) {
                log.info("创建服务端订阅失败。");
                return;
            }

            log.info("第三步：查询服务端订阅 ---> 创建结果");
            this.querySubscribeRelation(client, argIotInstanceId, argProductKey, argType);
            log.info("第四步：修改服务端订阅");
            Boolean bOtaEventFlag = true;
            Boolean bOtaJobFlag = true;
            UpdateSubscribeRelationResponseBody updateResponseBody = this.updateSubscribeRelation(client, argIotInstanceId, argProductKey, argType, argDeviceDataFlag, argDeviceLifeCycleFlag, argDeviceStatusChangeFlag, argDeviceTagFlag, argDeviceTopoLifeCycleFlag, argFoundDeviceListFlag, bOtaEventFlag, bOtaJobFlag, argOtaVersionFlag, argThingHistoryFlag, argMnsConfiguration, argConsumerGroupIds);
            if (!updateResponseBody.success) {
                log.info("修改服务端订阅失败。");
                // 为避免遗留测试用数据，修改失败时不终止程序，继续执行下一步的删除逻辑。
            }

            log.info("第五步：查询服务端订阅 ---> 修改结果");
            this.querySubscribeRelation(client, argIotInstanceId, argProductKey, argType);
            log.info("第六步：删除服务端订阅");
            DeleteSubscribeRelationResponseBody deleteResponseBody = this.deleteSubscribeRelation(client, argIotInstanceId, argProductKey, argType);
            if (!deleteResponseBody.success) {
                log.info("删除服务端订阅失败。");
            }

            log.info("第七步：查询服务端订阅 ---> 删除结果");
            this.querySubscribeRelation(client, argIotInstanceId, argProductKey, argType);
        } catch (Exception error) {
            log.info(error.getMessage());
        }
    }
}
