package com.mvc.iot.onenet;

import com.alibaba.fastjson.JSON;
import com.mvc.iot.onenet.auth.Token;
import com.mvc.iot.onenet.config.OneNetConfig;
import com.mvc.iot.onenet.model.OneNetApiResponseModel;
import com.mvc.iot.onenet.model.OneNetDeviceApiModel;
import com.mvc.utils.DateUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 移动OneNet平台API处理
 * 基于HTTP
 */
@Component
public class OneNetApiHelper {
    private static final Logger logger = LoggerFactory.getLogger(OneNetApiHelper.class);

    public static final String RESPONSE_MSG_SUCC = "succ";//响应结果成功的返回值

    private static final String API_DEVICE_CREATE = "https://iot-api.heclouds.com/device/create";//创建设备
    private static final String API_DEVICE_DELETE = "https://iot-api.heclouds.com/device/delete";//删除设备
    private static final String API_COMMAND_EXECUTE = "https://iot-api.heclouds.com/nb-iot/execute/offline";//缓存命令下发
    private static final String API_COMMAND_CANCEL = "https://iot-api.heclouds.com/nb-iot/offline/cancel/";//缓存命令取消

    private static final String API_COMMAND_IMMEDIATE = "https://iot-api.heclouds.com/nb-iot/execute";//即时命令下发
    private static final String API_LATEST_LOCATION = "https://iot-api.heclouds.com/fuse-lbs/latest-location/";//基站定位获取最新位置

    private static final String API_SIGN_VERSION = "2022-05-01";//签名算法版本

    private static long signExpirationTime;//本次鉴权过期时间
    private static String authorization;//鉴权字符串

    @Resource
    private OneNetConfig oneNetConfig;

    @Resource
    private RestTemplate restTemplate;

    /**
     * 创建设备
     *
     * @param model
     */
    public OneNetApiResponseModel createDevice(OneNetDeviceApiModel model) {
        String json = JSON.toJSONString(model);
        return postData(API_DEVICE_CREATE, json);
    }

    /**
     * 删除设备
     *
     * @param model
     */
    public OneNetApiResponseModel deleteDevice(OneNetDeviceApiModel model) {
        String json = JSON.toJSONString(model);
        return postData(API_DEVICE_DELETE, json);
        /* 删除的响应结果
        {
          "code": 0,
          "data": {
            "did": 2380340144,
            "pid": "U163RT0ok5",
            "access_pt": 4,
            "auth_info": "6",
            "data_pt": 2,
            "name": "6",
            "desc": "",
            "status": 2,
            "create_time": "2024-10-14T10:26:46.343588623+08:00",
            "activate_time": "0001-01-01T00:00:00Z",
            "last_time": "0001-01-01T00:00:00Z",
            "imsi": "864606065696782",
            "imei": "864606065696782",
            "psk": "ADAxx9xERiIt6HCV",
            "group_id": "",
            "enable_status": true,
            "tags": null,
            "lat": "",
            "lon": "",
            "auth_code": "",
            "sec_key": "ZWRFZUdxa1JsRmVabzFSNGhnNjJJS0RVclU4c1dCV24=",
            "chip": 0,
            "obsv": true,
            "obsv_st": false,
            "private": false,
            "imsi_old": [
              "864606065696782"
            ],
            "imsi_mt": "0001-01-01T00:00:00Z",
            "intelligent_way": 1
          },
          "msg": "succ",
          "request_id": "f6e9197e2be74d23bd9b8c5e3412848e"
        }*/
    }

    public OneNetApiResponseModel sendCommand(String imei, String message) {
        String et = DateUtil.formateDate(DateUtil.getOtherDateByCurrentDate(new Date(), 3), "yyyy-MM-dd'T'HH:mm:ss");
        Map<String, Object> map = new HashMap<>();
        map.put("imei", imei);//必选 nbiot设备的身份码
        map.put("obj_id", 3200);//必选 设备objectId，根据终端SDK确定 ?
        map.put("obj_inst_id", 5505);//必选 设备object下具体一个instance的id,对应到平台模型中数据点key值的一部分 ?
        map.put("res_id", 3);//必选 nbiot设备的资源id ?
        //map.put("valid_time",imei);//命令开始生效时间，可选（不填时默认为OneNET当前时间），填写必须大于OneNET服务器的当前时间
        map.put("expired_time", et);//必选 命令过期时间，必须大于valid_time
        //map.put("retry",imei);//表示失败重试次数（等待下一次设备update或者上线），可选（不填时默认为3），填写时必须在[0, 10]之间
        //map.put("timeout",imei);//超时时间,可选,默认25秒，取值范围[5,40]
        //map.put("trigger_msg",imei);//命令触发的上行消息类型，填写时必须在[1,7]之间；不填写默认为7

        // 构建带有查询参数的URL
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(API_COMMAND_EXECUTE);
        map.forEach((key, value) -> builder.queryParam(key, value));
        String fullUrl = builder.toUriString();

        Map<String, String> bodyMap = new HashMap<>();
        bodyMap.put("args", message);//命令字符串，大小限制2KB
        String json = JSON.toJSONString(bodyMap);

        return postData(fullUrl, json);
    }

    /**
     * 即时命令下发
     *
     * @param imei
     * @param message
     * @return
     */
    public OneNetApiResponseModel sendImmediateCommand(String imei, String message) {
        Map<String, Object> map = new HashMap<>();
        map.put("imei", imei);//必选 nbiot设备的身份码
        map.put("obj_id", 3200);//必选 设备objectId，根据终端SDK确定 ?
        map.put("obj_inst_id", 5505);//必选 设备object下具体一个instance的id,对应到平台模型中数据点key值的一部分 ?
        map.put("res_id", 3);//必选 nbiot设备的资源id ?
        //map.put("timeout",imei);//超时时间，可选，默认6秒，超时后会重试一次

        // 构建带有查询参数的URL
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(API_COMMAND_EXECUTE);
        map.forEach((key, value) -> builder.queryParam(key, value));
        String fullUrl = builder.toUriString();

        Map<String, String> bodyMap = new HashMap<>();
        bodyMap.put("args", message);//命令字符串，大小限制2KB
        String json = JSON.toJSONString(bodyMap);
        return postData(fullUrl, json);
    }

    public OneNetApiResponseModel cancelCommand(String uuid, String imei) {
        String fullUrl = API_COMMAND_CANCEL + uuid + "?imei=" + imei;
        HttpHeaders headers = new HttpHeaders();
        headers.add("authorization", getAuthorization());
        // 创建HTTP实体
        HttpEntity<String> entity = new HttpEntity<>(headers);

        // 发送PUT请求
        ResponseEntity<String> response = restTemplate.exchange(fullUrl, HttpMethod.PUT, entity, String.class);
        System.out.println(response.getBody());
        if (response.getStatusCode() == HttpStatus.OK) {
            //{"code":0,"msg":"succ","request_id":"781aa525adec40e3aafd1c266311e962"}
            OneNetApiResponseModel res = JSON.parseObject(response.getBody(), OneNetApiResponseModel.class);
            return res;
        } else {

        }
        return null;
    }

    /**
     * 获取设备最新位置信息
     *
     * @param imei
     * @return
     */
    public OneNetApiResponseModel getLatestLocation(String imei) {
        HttpHeaders headers = new HttpHeaders();
        headers.add("authorization", getAuthorization());
        String fullUrl = API_LATEST_LOCATION + imei;
        HttpEntity<String> entity = new HttpEntity<>(headers);
        ResponseEntity<String> response = restTemplate.postForEntity(fullUrl, entity, String.class);
        System.out.println(response.getBody());
        if (response.getStatusCode() == HttpStatus.OK) {
            OneNetApiResponseModel res = JSON.parseObject(response.getBody(), OneNetApiResponseModel.class);
            return res;
        }
        return null;

        //平台没有位置信息:{"timestamp":1729151783383,"status":404,"error":"Not Found","message":"No message available","path":"/latest-location/861999061544863"}
        /*
        {
            "code": 0,
            "msg": "succ",
            "request_id": "**********",
            "data": {
                "at": "2022-06-13 17:37:17.139",  //时间
                "accuracy": 20,   //准确度
                "lon": 106.48881,   //经度
                "lat": 29.62518   //纬度
            }
        }
        *  */
    }

    private OneNetApiResponseModel postData(String url, String json) {
        HttpHeaders headers = new HttpHeaders();
        headers.add("authorization", getAuthorization());
        headers.setContentType(MediaType.APPLICATION_JSON);

        try {
            HttpEntity<String> entity = new HttpEntity<>(json, headers);
            ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
            System.out.println(response.getBody());
            if (response.getStatusCode() == HttpStatus.OK) {
                OneNetApiResponseModel res = JSON.parseObject(response.getBody(), OneNetApiResponseModel.class);
                return res;
            } else {

            }
        } catch (Exception ex) {
            logger.error(ex.getMessage());
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * 获取鉴权字符串
     *
     * @return
     */
    private String getAuthorization() {
        long now = new Date().getTime();
        if (StringUtils.isEmpty(authorization) || now > signExpirationTime) {
            signExpirationTime = DateUtil.getZeroTimeOfDay(DateUtil.getOtherDateByCurrentDate(new Date(), 1)).getTime();//明日0点
            String res = "products/" + oneNetConfig.getIotProductId();
            try {
                authorization = Token.assembleToken(API_SIGN_VERSION, res, String.valueOf(signExpirationTime), Token.SignatureMethod.SHA1.name(), oneNetConfig.getIotProductKey());
            } catch (Exception e) {
                logger.error("getAuthorization error", e);
            }
        }
        return authorization;
    }
}
