<?php

namespace App\Services;

use App\Exceptions\SmsException;
use Illuminate\Support\Facades\Redis;
use PHPUnit\Util\Exception;
use App\Models\SmsRecord;
use Illuminate\Support\Str;
use Overtrue\EasySms\EasySms;
//use Overtrue\EasySms\Exceptions\Exception;
use Overtrue\EasySms\Exceptions\NoGatewayAvailableException;

class SmsServer
{
    const EVENT_LOGIN = 100;
    const DEFAULT_SMS_CODE_LENGTH = 4;
    const DEFAULT_SMS_CODE_EXP_TIME = 5*60;
    const EVENTS_TO_TEMPLATE = [
        '63' => [ //菲律宾
            'login' => 'SMS_234414831',
            'forget' => 'SMS_234414831',
        ],
        '86' => [ //中国
            //'login'  => 'SMS_137515003',
            //'forget' => 'SMS_137515003',
            'login' => 'SMS_227262168',
            'forget' => 'SMS_227262168',
        ],
    ];

    const EVENT_ITEM_FUNCTION = [

    ];

    /**
     * 获取easySms配置
     * @return \Illuminate\Config\Repository|\Illuminate\Contracts\Foundation\Application|mixed
     */
    static public function getEasySmsConfig()
    {
        return config('easysms');
    }

    /**
     * 获取 easySms 实例
     * @return EasySms
     */
    static public function easySms()
    {
        return new EasySms(self::getEasySmsConfig());
    }

    static public function send(int $mobile, string $event, int $prefix)
    {
        try {
            $templateId = self::getTemplateIdByEvent($prefix, $event);
            $smsCode = self::getSmsCode();
            //注意！ 实际发送的电话号码，要加 国际号码前缀
            $result = self::easySms()->send($prefix.$mobile, [
                'template' => $templateId,
                'content' => 'null',
                'data' => [
                    'code' => $smsCode,
                    'expTime' => 5,
                ]
            ]);
            //缓存验证码
            self::cacheSmsCodeByVerifyKey($mobile, $smsCode);
            //存入发送记录
            self::storeSmsRecord($prefix, $mobile, $event, $smsCode, '', $result);
            return [
                'smsCode' => $smsCode
            ];

        } catch (SmsException $e) {
            return ['error' => $e->getMessage()];
        } catch (NoGatewayAvailableException $e) {
            return ['error' => trans('api.SMS_SENDING_FAILED')];
        } catch (Exception $e) {
            return ['error' => trans('api.SMS_SENDING_FAILED')];
        }
    }

    /**
     * 生成随机字符串用户校验验证码
     * @param int $length
     * @return string
     */
    static public function getVerifyKey(int $length = 10)
    {
        return Str::random($length);
    }

    /**
     * 生成短信验证码
     * @param int $length
     * @return int
     */
    static public function getSmsCode($length = self::DEFAULT_SMS_CODE_LENGTH)
    {
        return rand(1000, 9999);
    }

    /**
     * @param string $mobile
     * @param string $smsCode
     * @return bool
     */
    static public function checkSmsCodeByVerifyKey(string $mobile, string $smsCode)
    {
        $CacheSmsCode = Redis::get('smsCode:verifyCode' . $mobile);
        if (empty($CacheSmsCode)) {
            throw new Exception('验证码过期或已失效');
        }
        if ($smsCode != $CacheSmsCode) {
            throw new Exception('验证码错误');
        }
        Redis::del('smsCode:verifyCode' . $mobile);

        return true;
    }


    /**
     * 缓存短信验证码
     * @param int $mobile
     * @param string $smsCode
     * @param int $expTime
     * @return mixed
     */
    static public function cacheSmsCodeByVerifyKey(int $mobile, string $smsCode, int $expTime = self::DEFAULT_SMS_CODE_EXP_TIME)
    {
        return Redis::setex('smsCode:verifyCode' . $mobile, $expTime, $smsCode);
    }

    /**
     * 根据事件获取 短信模板ID
     * @param string $event
     * @return string
     * @throws SmsException
     */
    static public function getTemplateIdByEvent($prefix, string $event)
    {
        //self::verifySmsEvent($event);
        return self::EVENTS_TO_TEMPLATE[$prefix][$event];
    }

    /**
     * 验证发送事件
     * @param string $event
     * @return bool
     * @throws SmsException
     */
    static public function verifySmsEvent(string $event)
    {
        if (!array_key_exists($event, self::EVENTS_TO_TEMPLATE)) {
            throw new Exception(trans('api.WRONG_EVENT_TYPE'));
        }
        return true;
    }

    /**
     * 将发送记录存到数据库以便调试
     * @param string $prefix
     * @param int $mobile
     * @param string $event
     * @param string $smsCode
     * @param $sendResult
     * @return mixed
     */
    static public function storeSmsRecord(string $prefix, int $mobile, string $event, string $smsCode, $sendResult)
    {
        return SmsRecord::create([
            'prefix' => $prefix,
            'mobile' => $mobile,
            'event' => $event,
            'sms_code' => $smsCode,
            'verify_key' => '',
            'sms_result' => $sendResult
        ]);
    }
}
