<?php


namespace App\Server;

use AlibabaCloud\Iot\V20180120\RRpc;
use App\Model\DeliverInfo;
use App\Model\DeviceInfo;
use App\Model\SystemConfig;
use App\Model\WaringMessage;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Cache;

class DeviceServer
{
    private $conf;
    private $property;
    private $blueProperty;

    const CLOSE = 0;
    const OPEN = 1;
    const AGENTOPEN = 2;
    const AGENTCLOSE = 3;

    public function __construct()
    {
        $this->property = [
            'CurrentTemperature' => 'device_tem',
            'IMEI' => 'imei',
           // 'GeoLocation' => 'location',
            'MagDoorSwitch' => 'lock_switch',
            'RodSwitch' => 'deliver_lock_switch',
            'RunningState' => 'runningStatus',
            'Weight' => 'device_weight',
            'RestCapacity' => 'rest_capacity',
        ];
        $this->blueProperty = [
            'CurrentTemperature' => 'device_tem',
            'IMEI' => 'imei',
            //'GeoLocation' => 'location',
            'MagDoorSwitch' => 'lock_switch',
            'RodSwitch' => 'deliver_lock_switch',
            'RunningState' => 'runningStatus',
            'Weight' => 'device_weight',
            'RestCapacity' => 'rest_capacity',
        ];
        $this->conf = SystemConfig::get('ali_config');
    }

    /**
     * 刷新所有设备列表
     * @return string|bool
     */
    public function refreshList()
    {
        $conf = $this->conf;
        if (!isset($conf['appSecret']) || empty($conf['appSecret'])) {
            return '请先配置阿里云app秘钥';
        }
        if (!isset($conf['appKey']) || empty($conf['appKey'])) {
            return '请先配置阿里云appKey';
        }
        if (!isset($conf['productKey']) || empty($conf['productKey'])) {
            return '请先配置阿里云产品识别码';
        }

        $ali = new AliYunIotServer($conf['appKey'], $conf['appSecret']);
        $list = $ali->getDeviceList($conf['productKey'], 100);
        $deviceList = $list['Data']['DeviceInfo'];
        if ($list['Page'] < $list['PageCount']) {
            for ($i = ($list['Page'] + 1); $i <= $list['PageCount']; $i++) {
                $list = $ali->getDeviceList($conf['productKey'], 100, $i);
                $deviceList = array_merge($deviceList, $list['Data']['DeviceInfo']);
            }
        }
        foreach ($deviceList as $key => $val) {
            $check = DeviceInfo::where([['device_name', $val['DeviceName']], ['product_key', $val['ProductKey']]])
                ->orWhere('iot_id', $val['IotId'])->first(['id', 'status']);
            $status = 0;
            switch ($val['DeviceStatus']) {
                case 'ONLINE':
                    $status = DeviceInfo::ONLINE;
                    break;
                case 'OFFLINE':
                    $status = DeviceInfo::OFFLINE;
                    break;
                case 'UNACTIVE':
                    $status = DeviceInfo::UNACTIVE;
                    break;
                case 'DISABLE':
                    $status = DeviceInfo::DISABLE;
                    break;
            }
            if ($check) {
                $check->status = $status;
                $check->save();
            } else {
                $create = [
                    'status' => $status,
                    'iot_id' => $val['IotId'],
                    'product_key' => $val['ProductKey'],
                    'device_secret' => $val['DeviceSecret'],
                    'device_name' => $val['DeviceName'],
                ];
                if ($status != 3) {
                    DeviceInfo::insert($create);
                }
            }
            $this->refreshDevice($val['IotId']);
        }
        return true;
    }

    /**
     * 刷新设备属性
     * @param String $iot_id
     * @return bool|string|array
     */
    public function refreshDevice(string $iot_id)
    {
        $conf = $this->conf;
        if (!isset($conf['appSecret']) || empty($conf['appSecret'])) {
            return '请先配置阿里云app秘钥';
        }
        if (!isset($conf['appKey']) || empty($conf['appKey'])) {
            return '请先配置阿里云appKey';
        }
        $ali = new AliYunIotServer($conf['appKey'], $conf['appSecret']);
        $deviceProperty = $ali->getDeviceProperty($iot_id);
        Log::info("设备数据刷新[1]：" . json_encode($deviceProperty));
        if (isset($deviceProperty['Success']) && $deviceProperty['Success']) {
            $data = [];
            foreach ($deviceProperty['Data']['List']['PropertyStatusInfo'] as $index => $item) {
                if (isset($this->property[$item['Identifier']])) {
                    if (isset($item['Value'])) {
                        $data[$this->property[$item['Identifier']]] = $item['Value'];
                    } else {
                        return ['data' => ['ErrorMessage' => "请检查设备属性[{$item['Identifier']}]是否初始化"], 'code' => 4];
                    }
                }
            }

            if (empty($data)) {
                return ['data' => ['ErrorMessage' => '未获取到设备属性'], 'code' => 3];
            }
            //修复
//            if ($data['deliver_lock_switch'] == 1) {
//                return ['data' => ['ErrorMessage' => '当前设备已开启，请等待'], 'code' => '2'];
//            }
      /*      if (isset($data['location'])) {
                $location = json_decode($data['location'], true);
                $data['device_latitude'] = $location['latitude'];
                $data['device_longitude'] = $location['longitude'];
                unset($data['location']);
            }*/
            /*if ($data['rest_capacity'] == 0) {
                $data['status'] = DeviceInfo::MAX;
            } else {
                $data['status'] = DeviceInfo::WELL;
            }*/
            $insert['device_item'] = $data['device_tem'];
            $insert['imei'] = $data['imei'];
            if ($data['device_tem'] >= 80) {
                $id = DeviceInfo::where('iot_id', $iot_id)->first(['id'])->id;
//                Log::info("设备温度【{$id}】:{$data['device_tem']}" );
//                WaringMessage::temWaring($id);
            }

            $res = DeviceInfo::where('iot_id', $iot_id)->update($insert);
            if (!$res) {
                Log::info('设备数据刷新[2]：' . json_encode($data));
            }
            return ['data' => $data, 'code' => '0'];
        } else {
            return ['data' => $deviceProperty, 'code' => 1];
        }
    }

    /**
     * 获取设备属性
     * @param String $iot_id
     * @return bool|string|array
     */
    public function getProperty(string $iot_id)
    {
        $conf = $this->conf;
        //Todo 全局 两个if合并
        if (!isset($conf['appSecret']) || empty($conf['appSecret'])) {
            return '请先配置阿里云app秘钥';
        }
        if (!isset($conf['appKey']) || empty($conf['appKey'])) {
            return '请先配置阿里云appKey';
        }
        $ali = new AliYunIotServer($conf['appKey'], $conf['appSecret']);
        $deviceProperty = $ali->getDeviceProperty($iot_id);
        dd($deviceProperty);
        if (isset($deviceProperty['Success']) && $deviceProperty['Success']) {
            $data = [];
            foreach ($deviceProperty['Data']['List']['PropertyStatusInfo'] as $index => $item) {
                if (isset($this->property[$item['Identifier']])) {
                    if (isset($item['Value'])) {
                        $data[$this->property[$item['Identifier']]] = $item['Value'];
                    } else {
                        return ['data' => ['ErrorMessage' => "请检查设备属性[{$item['Identifier']}]是否初始化"], 'code' => 4];
                    }
                }
            }
            if (empty($data)) {
                return ['data' => ['ErrorMessage' => '未获取到设备属性'], 'code' => 3];
            }

            /*if (isset($data['location'])) {
                $location = json_decode($data['location'], true);
                $data['device_latitude'] = $location['latitude'];
                $data['device_longitude'] = $location['longitude'];
                unset($data['location']);
            }*/
            /*if ($data['rest_capacity'] == 0) {
                $data['status'] = DeviceInfo::MAX;
            } else {
                $data['status'] = DeviceInfo::WELL;
            }*/
            return ['data' => $data, 'code' => '0'];

        } else {
            return ['data' => $deviceProperty, 'code' => 1];
        }
    }
    //蓝牙链接 传输加密数据
    public function getDecodeProperty(string $base64_data, string $iot_id)
    {
        Log::info($base64_data);
        $conf = $this->conf;
        if (!isset($conf['appSecret']) || empty($conf['appSecret'])) {
            return '请先配置阿里云app秘钥';
        }
        if (!isset($conf['appKey']) || empty($conf['appKey'])) {
            return '请先配置阿里云appKey';
        }
        $dataDecode = ToolServer::decode($base64_data, '1234567890123456');
        //$dataDecode = json_decode($base64_data, true);
        Log::info("蓝牙设备数据刷新：" . json_encode($dataDecode));
        $data = [];
        if (!$dataDecode["P"]) {
            return ['message' => '未获取到设备属性', 'code' => 3];
        }
        $updateIotData = [];
        foreach ($dataDecode["P"] as $index => $item) {
            if (isset($this->property[$item['I']])) {
                if (isset($item['V'])) {
                    $data[$this->property[$item['I']]] = $item['V'];
                    $updateIotData[$item['I']] = $item['V'];
                } else {
                    return ['data' => ['ErrorMessage' => "请检查设备属性[{$item['Identifier']}]是否初始化"], 'code' => 4];
                }
            }
        }
        if (empty($data)) {
            return ['message' => '未获取到设备属性', 'code' => 3];
        }
        $iotService = new AliYunIotServer($conf['appKey'], $conf['appSecret']);
        $resUpload = $iotService->setDeviceProperty($iot_id, $updateIotData);
        /*if (!$resUpload['Success']) {
            return ['message' => '设备数据上报物联网失败', 'code' => 4];
        }*/

        if ($data['device_tem'] >= 80) {
            $id = DeviceInfo::where('iot_id', $iot_id)->first(['id'])->id;
            WaringMessage::temWaring($id);
        }

        $res = DeviceInfo::where('iot_id', $iot_id)->update($data);
        if (!$res) {
            Log::info('设备数据刷新[3]：' . json_encode($data));
        }

        return ['data' => $data, 'code' => '0'];
    }

    public function getBase64Property(string $base64_data)
    {

        $dataDecode = json_decode(base64_decode($base64_data), true);
//        Log::debug($dataDecode);
        if ( empty($dataDecode)|| !is_array($dataDecode) || !isset($dataDecode['identifier']) ) {
            return true;
        }
        if ($dataDecode['identifier'] == 'errorEvent') {
            $id = DeviceInfo::where('iot_id', $dataDecode['iotId'])->first(['id'])->id;
            WaringMessage::normalWarning($id, $dataDecode['value']['errorEvent'], WaringMessage::ALARM);
            return true;
        }
        if ($dataDecode['identifier'] == 'warnEvent') {
            $device = DeviceInfo::where('iot_id', $dataDecode['iotId'])->first(['id', 'device_comment']);
            $last = WaringMessage::where([['no', $device->id], ['message', $dataDecode['value']['warnEvent']], ['type', WaringMessage::WARN]])->first(['created_at']);
            $mobile = SystemConfig::get('system_config', 'admin_mobile', 18981831779);
            if ($mobile && (!$last || ($last && strtotime($last->created_at) + 1800 <= time()))) {
                $type = SystemConfig::get('sms_config', 'sms_type', 'AliSmsServer');
                $template = SystemConfig::get('ali_config', 'sms', '');
                $template = json_decode($template, true);
                if ($template['DeviceTmpId'] && $template['sign']) {
                    $type = '\App\Server\Sms\\' . $type;
                    $sms = new SmsServer(new $type($mobile, $template['DeviceTmpId'], $template['sign'], ['deviceId' => $device->id, 'deviceName' => $device->device_comment, 'warnInfo' => $dataDecode['value']['warnEvent']]));
                    $sms->send();
                }
            }
            WaringMessage::normalWarning($device->id, $dataDecode['value']['warnEvent'], WaringMessage::WARN);
            return true;
        }
        if ($dataDecode['identifier'] == 'commoneEvent') {
            //toDO 开/关门
            $device = DeviceInfo::where('iot_id', $dataDecode['iotId'])->first(['id']);
            if(!$device){
                return true;
            }
            $order = DeliverInfo::where('device_id', $device->id)->orderBy('id', 'Desc')->first();
            //优化关门统一走回调
            if(!$order || $order->status != DeliverInfo::UNFINISHED){
                return true;
            }
            Log::info('Cache：' . 'device-msg-'.$dataDecode['iotId'].'-'.$dataDecode['requestId']);
            //处理设备发送重复消息
            if (Cache::has('device-msg-'.$dataDecode['iotId'].'-'.$dataDecode['requestId'])) {
                Log::info('关门回调通知重复消息：' .$dataDecode['requestId']);
                return true;
            }
            if($dataDecode['value']['action']=='open') {
                //开门回调通知
                Log::info('开门回调通知：' . json_encode($dataDecode));
                $order->open_weight = $dataDecode['value']['weight'];
                $order->save();
                Cache::put('device-msg-'.$dataDecode['iotId'].'-'.$dataDecode['requestId'], $dataDecode['requestId'], 3600);
                return true;
            }
            if($dataDecode['value']['action']=='close'){
                //关门回调通知
                Log::info('关门回调通知：' . json_encode($dataDecode));
                $close_weight = $dataDecode['value']['weight'];
                $weight = $close_weight - $order->open_weight;
                $order->close_weight = $close_weight;
                $order->weight = $weight;
                $order->finished_at = date('Y-m-d H:i:s');
                Log::info('关门回调变化重量：'.$weight);
                Log::info('关门回调关门重量：'.$close_weight);
                Log::info('关门回调获得金额：'.$order->money);
                Log::info('关门回调变化重量：'.($weight <= 0));
                Cache::forget('deviceUse_' . $device->id);


                $fetch_price= SystemConfig::get('system_config', 'fetch_per_g', '0.1');
                $price = SystemConfig::get('system_config', 'put_per_g', '0.06');

                //如果有小区加个就取小区价格
                $deviceInfo = DeviceInfo::with('communities')->where(['id'=>$order['device_id']])->first();
                if(!empty($deviceInfo->communities)) {
                    if(!empty($deviceInfo->communities->put_per_g)) $price = $deviceInfo->communities->put_per_g;
                    if(!empty($deviceInfo->communities->fetch_per_g)) $fetch_price = $deviceInfo->communities->fetch_per_g;
                }

                $order->deliver_price  = $price;
                $order->transport_price  = $fetch_price;

                if ($weight <= 0) {
                    $order->status=DeliverInfo::LOSS;
                    $order->income = 0;
                    if($weight < -5000){
                        $order->status=DeliverInfo::UNNORMAL;
                        WaringMessage::deliverWarning($order->no);
                    }
                    $order->save();
                    Log::info('关门回调失效订单：' . json_encode($order));
                    Cache::put('device-msg-'.$dataDecode['iotId'].'-'.$dataDecode['requestId'], $dataDecode['requestId'], 3600);
                    return true;
                }
                $start = date('Y') . '-' . date('m') . '-' . date('d') . ' 00:00:00';
                $checkCount = DeliverInfo::where([['user_id', $order->user_id], ['status', DeliverInfo::SUCCESS]])
                    ->where('created_at', '>', $start)->count();
                $deliverLimit = SystemConfig::get('system_config', 'deliver_limit', 10);
                $deliverWeight = SystemConfig::get('system_config', 'deliver_weight', 0);


                //To Do 地区价格计算公式
                Log::info('筛选时间:' . $start);
                Log::info('投递次数:' . $checkCount);
                Log::info('投递限制:' . $deliverLimit);
                Log::info('地区价格:' . $price);
                if (($deliverWeight != 0 && $weight > $deliverWeight) || $checkCount > $deliverLimit) {
                    $order->status = DeliverInfo::WAIT_CHECK;
                } else {
                    $order->status = DeliverInfo::SUCCESS;
                }
                $order->money = $price*$weight;
                $order->income = ($fetch_price - $price)*$weight;
                if ($order->save()) {
                    Cache::put('device-msg-'.$dataDecode['iotId'].'-'.$dataDecode['requestId'], $dataDecode['requestId'], 3600);
                    return true;
                } else {
                    return false;
                }

            }
        }
        if (isset($dataDecode['items'])) {
            $property = $dataDecode['items'];
            $data = [];
            if (!$property) {
                return ['message' => '未获取到设备属性', 'code' => 3];
            }
            foreach ($property as $index => $item) {
                if (isset($this->property[$index])) {
                    if (isset($item['value'])) {
                        $data[$this->property[$index]] = $item['value'];
                    } else {
                        return ['data' => ['ErrorMessage' => "请检查设备属性[{$item['Identifier']}]是否初始化"], 'code' => 4];
                    }
                }
            }
            if (empty($data)) {
                return ['message' => '未获取到设备属性', 'code' => 3];
            }
            if ($data['device_tem'] >= 80) {
                $id = DeviceInfo::where('iot_id', $dataDecode['iotId'])->first(['id'])->id;
                WaringMessage::temWaring($id);
            }

            $res = DeviceInfo::where('iot_id', $dataDecode['iotId'])->update($data);
            $this->getDeviceStatus($dataDecode['iotId']);
            if (!$res) {
                Log::info('设备数据刷新[4]：' . json_encode($data));
            }
            Log::info('success');
            return ['data' => $data, 'code' => '0'];
        }
        return true;
    }

    public function getDeviceStatus($iotId)
    {
        $conf = $this->conf;
        if (!isset($conf['appSecret']) || empty($conf['appSecret'])) {
            return '请先配置阿里云app秘钥';
        }
        if (!isset($conf['appKey']) || empty($conf['appKey'])) {
            return '请先配置阿里云appKey';
        }
        if (!isset($conf['productKey']) || empty($conf['productKey'])) {
            return '请先配置阿里云产品识别码';
        }

        $ali = new AliYunIotServer($conf['appKey'], $conf['appSecret']);
        $res = $ali->GetDeviceStatus($iotId);
        if ($res['Success'] == true) {
            $check = DeviceInfo::Where('iot_id', $iotId)->first(['status']);
            $status = 0;
            switch ($res['Data']['Status']) {
                case 'ONLINE':
                    $status = DeviceInfo::ONLINE;
                    break;
                case 'OFFLINE':
                    $status = DeviceInfo::OFFLINE;
                    break;
                case 'UNACTIVE':
                    $status = DeviceInfo::UNACTIVE;
                    break;
                case 'DISABLE':
                    $status = DeviceInfo::DISABLE;
                    break;
            }
            //////  dd($val);
            $check->status = $status;
            $check->save();
            return $status;
        } else {
            return 'fail';
        }
    }

    /**
     * 启用和禁用
     * @param String $iot_id
     * @param int $state AliYunIotServer::ENABLE
     * @return array|string
     */
    public function switchDevice(string $iot_id, int $state = AliYunIotServer::ENABLE)
    {
        $conf = $this->conf;
        if (!isset($conf['appSecret']) || empty($conf['appSecret'])) {
            return '请先配置阿里云app秘钥';
        }
        if (!isset($conf['appKey']) || empty($conf['appKey'])) {
            return '请先配置阿里云appKey';
        }
        $ali = new AliYunIotServer($conf['appKey'], $conf['appSecret']);

        $res = $ali->switchDevice($state, $iot_id);
        if (isset($res['Success']) && $res['Success']) {
            if ($state == AliYunIotServer::ENABLE) {
                $state = 0;
            } else {
                $state = 2;
            }
            DeviceInfo::where('iot_id', $iot_id)->update(['status' => $state]);
            return 'success';
        } else {
            return $res['ErrorMessage'];
        }
    }


    /** 投递门/收运门 开关
     * @param string $iot_id
     * @param int $mode
     * @return string
     */
    public function doorOperation(string $iot_id, int $mode = self::OPEN)
    {
        $conf = $this->conf;
        if (!isset($conf['appSecret']) || empty($conf['appSecret'])) {
            return '请先配置阿里云app秘钥';
        }
        if (!isset($conf['appKey']) || empty($conf['appKey'])) {
            return '请先配置阿里云appKey';
        }
        $ali = new AliYunIotServer($conf['appKey'], $conf['appSecret']);
        if ($mode == self::OPEN) {
            $identifier = 'open1';
        } else if ($mode == self::CLOSE) {
            $identifier = 'close1';
        } else if ($mode == self::AGENTOPEN) {
            $identifier = 'RemoteAgentOpen';
        } else if ($mode == self::AGENTCLOSE) {
            $identifier = 'RemoteAgentClose';
        }
        $args = (object)[];
        $res = $ali->invokeThingService($iot_id, $identifier, $args);
        Log::info('doorOperation 参数：'. $iot_id .' '. $mode .'返回数据：'.json_encode($res));
        if (isset($res['Success']) && $res['Success']) {
            DeviceInfo::where('iot_id', $iot_id)->update(['deliver_lock_switch' => $mode]);
            return 'success';
        } else {
            return $res['ErrorMessage'];
        }
    }

    /** 下发锁协议
     * @param string $device_name 设备名称
     * @param string $rules 下发规则
     **/

    public  function sendMsg(string $device_name, string $rules)
    {
        $conf = $this->conf;
        if (!isset($conf['appSecret']) || empty($conf['appSecret'])) {
            return '请先配置阿里云app秘钥';
        }
        if (!isset($conf['appKey']) || empty($conf['appKey'])) {
            return '请先配置阿里云appKey';
        }

        $ali = new AliYunIotServer($conf['appKey'], $conf['appSecret']);
        $args['Action'] = "Pub";
        $args['DeviceName'] =  $device_name;
        $args['ProductKey'] = 'a15yVIP0Onl';
        $args['MessageContent'] = base64_encode($rules);
        $args['TopicFullName'] = "/a15yVIP0Onl/{$device_name}/user/get";
//        $args['RequestBase64Byte'] = base64_encode($rules);
//        $args['Timeout'] = 7000;
//        $args['Topic'] = "/a15yVIP0Onl/{$device_name}/user/get";
        $data = $ali->RRpc($args);
        return $data;
    }

//    /** 投递门
//     * @param string $iot_id
//     * @param int $mode
//     * @return string
//     */RRpcRequestRRpcRequest
//    public function doorInOperation(string $iot_id, int $mode = self::OPEN)
//    {
//        $conf = $this->conf;
//
//        if (!isset($conf['appSecret']) || empty($conf['appSecret'])) {
//            return '请先配置阿里云app秘钥';
//        }
//
//        if (!isset($conf['appKey']) || empty($conf['appKey'])) {
//            return '请先配置阿里云appKey';
//        }
//        $ali = new AliYunIotServer($conf['appKey'], $conf['appSecret']);
//        if ($mode == self::CLOSE) {
//            $identifier = 'RemoteClose';
//        } else {
//            $identifier = 'RemoteOpen';
//        }
//        $args = (object)[];
//        $res = $ali->invokeThingService($iot_id, $identifier, $args);
//        Log::info(json_encode($res));
//        if (isset($res['Success']) && $res['Success']) {
//            DeviceInfo::where('iot_id', $iot_id)->update(['deliver_lock_switch' => $mode]);
//            return 'success';
//        } else {
//            return $res['ErrorMessage'];
//        }
//    }
//
//
//    /** 收运门
//     * @param string $iot_id
//     * @param int $mode
//     * @return string
//     */
//    public function doorOutOperation(string $iot_id, int $mode = self::OPEN)
//    {
//        $conf = $this->conf;
//
//        if (!isset($conf['appSecret']) || empty($conf['appSecret'])) {
//            return '请先配置阿里云app秘钥';
//        }
//
//        if (!isset($conf['appKey']) || empty($conf['appKey'])) {
//            return '请先配置阿里云appKey';
//        }
//        $ali = new AliYunIotServer($conf['appKey'], $conf['appSecret']);
//        if ($mode == self::CLOSE) {
//            $identifier = 'RemoteAgentClose';
//        } else {
//            $identifier = 'RemoteAgentOpen';
//        }
//        $args = (object)[];
//        $res = $ali->invokeThingService($iot_id, $identifier, $args);
//        if (isset($res['Success']) && $res['Success']) {
//            DeviceInfo::where('iot_id', $iot_id)->update(['lock_switch' => $mode]);
//            return 'success';
//        } else {
//            return $res['ErrorMessage'];
//        }
//    }
}
