<?php

namespace App\Server;

use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
use Illuminate\Support\Facades\Log;

class AliYunIotServer
{

    protected $errMsg;
    private $appKey;
    private $appSecret;
    private $regionId;

    const DISABLE = 0;
    const ENABLE = 1;

    /**
     * AliYunIotServer constructor.
     * @param string $appKey
     * @param string $appSecret
     * @param string $regionId
     */
    public function __construct(string $appKey, string $appSecret, string $regionId = 'cn-hangzhou')
    {
        $this->appKey = $appKey;
        $this->appSecret = $appSecret;
        $this->regionId = $regionId;
    }

    /**
     * 获取服务列表
     * @param int $pageSize
     * @param int $currentPage
     * @return array|string
     */
    public function getProductList(int $pageSize = 5, int $currentPage = 1)
    {
        $params = [
            'RegionId' => $this->regionId,
            'PageSize' => "$pageSize",
            'CurrentPage' => "$currentPage",
        ];
        return $this->AliCurl("post", "QueryProductList", $params);
    }

    /**
     * 获取设备列表
     * @param string $productKey
     * @param int $pageSize
     * @param int $currentPage
     * @return array|string
     */
    public function getDeviceList(string $productKey, int $pageSize = 5, int $currentPage = 1)
    {
        $params = [
            'RegionId' => $this->regionId,
            'PageSize' => "$pageSize",
            'ProductKey' => "$productKey",
            'CurrentPage' => "$currentPage",
        ];
        return $this->AliCurl("post", "QueryDevice", $params);
    }

    /**
     * 获取设备属性
     * @param string $iotId
     * @param string $iotInstanceId
     * @return array|string
     */
    public function getDeviceProperty(string $iotId, string $iotInstanceId = '')
    {
        $params['IotId'] = $iotId;
        $params['RegionId'] = $this->regionId;
        /*foreach ($identifier as $key => $val) {
            $params['Identifier.' . ($key + 1)] = $val;
        }*/
        if ($iotInstanceId) {
            $params['IotInstanceId'] = $iotInstanceId;
        }
        return $this->AliCurl("post", "QueryDevicePropertyStatus", $params);
    }

    /**
     * 获取设备状态
     * @param string $iotId
     * @param string $iotInstanceId
     * @return array|string
     */
    public function getDeviceStatus(string $iotId, string $iotInstanceId = '')
    {
        $params['IotId'] = $iotId;
        $params['RegionId'] = $this->regionId;
        /*foreach ($identifier as $key => $val) {
            $params['Identifier.' . ($key + 1)] = $val;
        }*/
        if ($iotInstanceId) {
            $params['IotInstanceId'] = $iotInstanceId;
        }
        return $this->AliCurl("post", "GetDeviceStatus", $params);
    }

    /**
     * 设置设备属性
     * @param string $iotId
     * @param array $property
     * @param string $iotInstanceId
     * @return array|string
     */
    public function setDeviceProperty(string $iotId, array $property, string $iotInstanceId = '')
    {
        /*if ($this->checkProperty($property)) {
            return $this->errMsg;
        }*/
        $params['Items'] = json_encode($property);
        //dd($params);
        Log::info("手动上报设备属性" . $params['Items']);
        $params['IotId'] = $iotId;
        if ($iotInstanceId) {
            $params['IotInstanceId'] = $iotInstanceId;
        }
        //dd($params);
        return $this->AliCurl("post", "SetDeviceProperty", $params);
    }

    /**
     * 调用设备服务
     * @param string $iotId
     * @param string $identifier
     * @param object $args
     * @param string $iotInstanceId
     * @return array|string
     */
    public function invokeThingService(string $iotId, string $identifier, object $args, string $iotInstanceId = '')
    {
        $params['IotId'] = $iotId;
        $params['Identifier'] = $identifier;
        $params['Args'] = json_encode($args);
        if ($iotInstanceId) {
            $params['IotInstanceId'] = $iotInstanceId;
        }
        return $this->AliCurl("post", "InvokeThingService", $params);
    }

    /**
     * 禁用&解禁设备
     * @param int $status
     * @param string $iotId
     * @param string $iotInstanceId
     * @return array|string
     */
    public function switchDevice(int $status, string $iotId, string $iotInstanceId = '')
    {
        $params['IotId'] = $iotId;
        if ($iotInstanceId) {
            $params['IotInstanceId'] = $iotInstanceId;
        }
        if ($status == self::DISABLE) {
            return $this->AliCurl("post", "DisableThing", $params);
        } else if ($status == self::ENABLE) {
            return $this->AliCurl("post", "EnableThing", $params);
        }
    }

    /**
     * @param string $method
     * @param string $action
     * @param array $params
     * @return array|string
     */
    private function AliCurl(string $method, string $action, array $params = [])
    {
        try {
            AlibabaCloud::accessKeyClient($this->appKey, $this->appSecret)
                ->regionId($this->regionId)
                ->asDefaultClient();
            $result = AlibabaCloud::rpc()
                ->product('Iot')
                // ->scheme('https') // https | http
                ->version('2018-01-20')
                ->action($action)
                ->method(strtoupper($method))
                ->host('iot.cn-shanghai.aliyuncs.com')
                ->options([
                    'query' => $params
                ])
                ->request();
            return $result->toarray();
        } catch (ClientException $e) {
            return $e->getErrorMessage() . PHP_EOL;
        } catch (ServerException $e) {
            return $e->getErrorMessage() . PHP_EOL;
        }
    }

    /**
     * @param array $params
     * @return bool
     */
    protected function checkProperty(array $params)
    {
        $initialProperty = ['LockSwitch' => 'is_bool'];
        foreach ($params as $key => $val) {
            if (!isset($initialProperty[$key])) {
                $this->errMsg = '该属性未定义';
                return false;
            }
            if ($initialProperty[$key]($val)) {
                $this->errMsg = '该属性数据类型异常';
                return false;
            }
            if ($val == '' || $val == [] || $val == null) {
                $this->errMsg = '属性不能为空';
                return false;
            }
        }
        return true;
    }
}
