<?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
{
    public const EVENT_LOGIN               = 100;
    public const DEFAULT_SMS_CODE_LENGTH   = 4;
    public const DEFAULT_SMS_CODE_EXP_TIME = 5 * 60;
    public const EVENTS_TO_TEMPLATE        = [
        '63' => [ // 菲律宾
            'login'  => 'SMS_234414831',
            'forget' => 'SMS_234414831',
        ],
        '86' => [ // 中国
            // 'login'  => 'SMS_137515003',
            // 'forget' => 'SMS_137515003',
            'login'  => 'SMS_227262168',
            'forget' => 'SMS_227262168',
        ],
    ];

    public const EVENT_ITEM_FUNCTION = [];

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

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

    public static 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,
                ],
            ]);
            // 缓存验证码
            $verifyKey = self::getVerifyKey();
            self::cacheSmsCodeByVerifyKey($mobile, $smsCode, $verifyKey);
            // 存入发送记录
            self::storeSmsRecord($prefix, $mobile, $event, $smsCode, $verifyKey, $result);

            return [
                'verifyKey' => $verifyKey,
                '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')];
        }
    }

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

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

    /**
     * 根据验证码，verifyKey 校验是否正确.
     *
     * @return bool
     *
     * @throws SmsException
     */
    public static function checkSmsCodeByVerifyKey(string $verifyKey, string $smsCode)
    {
        $record = Redis::get('smsCode:verifyCode' . $verifyKey);
        if (empty($record)) {
            throw new Exception('验证码过期或已失效');
        }
        $record = json_decode($record, true);
        if ($smsCode != $record['smsCode']) {
            throw new Exception('验证码错误');
        }
        Redis::del('smsCode:verifyCode' . $verifyKey);

        return true;
    }

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

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

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

        return true;
    }

    public static function storeSmsRecord(string $prefix, int $mobile, string $event, string $smsCode, string $verifyKey, $sendResult)
    {
        return SmsRecord::create([
            'prefix'     => $prefix,
            'mobile'     => $mobile,
            'event'      => $event,
            'sms_code'   => $smsCode,
            'verify_key' => $verifyKey,
            'sms_result' => $sendResult,
        ]);
    }
}
