<?php


namespace App\Http\logic\api;


use App\Http\helper\HttpCurl;
use App\Models\GamePhoneVerityCode;
use App\Util;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;

class SendCodeLogic extends BaseApiLogic
{
    const IP_DAILY_LIMIT_PREFIX = 'ip_daily_limit_';

    const PHONE_DAILY_LIMIT_PREFIX = 'phone_daily_limit_';

    /** @var string 每分钟频率限制key前缀 */
    const PHONE_FREQUENT_LIMIT_PREFIX = 'phone_frequent_limit_';
    const PHONE_SEND_LASTCONFIG_PREFIX = 'phone_send_last_';

    const FREQUENT_IP_LIMIT_NUM = 20;

    const FREQUENT_PHONE_LIMIT_NUM = 10;

    protected $config; // 天一宏 -- 不卡
    protected $kmiConfig; // kmi
    protected $zrConfig; // ZhangRong
    protected $plantsConfig; // ZhangRong

    public function __construct()
    {
        // 天一宏 -- 不卡
        $this->config = config('InterfaceAPI.short_message');

        $this->kmiConfig = config('InterfaceAPI.kmi_message');
        $this->zrConfig = config('InterfaceAPI.zr_message');
        $this->plantsConfig = config('InterfaceAPI.plant_message');
    }

    public function send($phone, $ip, $UserID, $Content)
    {

        $model = new GamePhoneVerityCode();

        // 生成验证码
        $code = $this->code($phone);
        $content = urlencode(str_replace('{code}', $code, $Content));

        $appKey = $this->config['appKey'];
        $password = $this->config['key'];
        $time = time();

        $sign = md5($appKey . $password . $time);

        $data = [
            'appId' => $this->config['appId'],
            'numbers' => $phone,
            'content' => $content,
            'senderId' => $code,
        ];


        $model->addCode($UserID, $code, $phone, $ip);


        $build = http_build_query($data);
        Log::info('buka发送验证码参数 ' . $build);
        $gateway = $this->config['gateway'] . '?' . $build;

        $header = ['Sign' => $sign, 'Timestamp' =>$time, 'Api-Key' => $appKey];
        Log::info('bukaheader-签名 ' . json_encode($header)."###".$appKey .'-'. $password .'-'. $time);
        $HttpCurl = new HttpCurl();
        $res = $HttpCurl->curl_get($gateway, $header);

        Log::info('buka发送验证码结果：' . $res);

        try {
            $data = \GuzzleHttp\json_decode($res, true);
        }catch (\Exception $e){
            $data=[];
        }
        if (isset($data['status']) && $data['status'] == 0){
            $this->setFrequent($ip, $phone,1);
            return true;
        }

        $this->error = ['web.verify.send_error','Falha ao obter o código de verificação'];
        return false;

    }


    public function zr_send($phone, $ip, $UserID, $Content)
    {

        $model = new GamePhoneVerityCode();

        // 生成验证码
        $code = $this->code($phone);
        $content = urlencode(str_replace('{code}', $code, $Content));
        $accesskey = $this->zrConfig['accesskey'];
        $secret = $this->zrConfig['secret'];
        $time = time();


        $data = [
            'accesskey' => $accesskey,
            'secret' => $secret,
            'mobile' => $phone,
            'content' => $content,
        ];


        $model->addCode($UserID, $code, $phone, $ip);


        $build = http_build_query($data);
        Log::info('zr发送验证码参数 ' . $build);
        $gateway = $this->zrConfig['gateway'] ;

//        $header = ['sign' => $sign, 'Timestamp' =>$time, 'Api-Key' => $appKey];
//        Log::info('header-签名 ' . json_encode($header)."###".$appKey .'-'. $password .'-'. $time);
        $HttpCurl = new HttpCurl();
        $res = $HttpCurl->curlPost($gateway, $build);

        Log::info('zr发送验证码结果：' . $res);

        $data = \GuzzleHttp\json_decode($res, true);
        if (isset($data['status']) && $data['status'] == 0){
            $this->setFrequent($ip, $phone,2);
            return true;
        }

        $this->error = ['web.verify.send_error','Falha ao obter o código de verificação'];
        return false;

    }
    public function plants_send($phone, $ip, $UserID, $Content)
    {

        $model = new GamePhoneVerityCode();

        // 生成验证码
        $code = $this->code($phone);
        $content = urlencode(str_replace('{code}', $code, $Content));
        $accesskey = $this->plantsConfig['appKey'];
        $secret = $this->plantsConfig['secretKey'];
        $time = time();


        $data = [
            'appkey' => $accesskey,
            'secretkey' => $secret,
            'phone' => $phone,
            'content' => $content,
        ];


        $model->addCode($UserID, $code, $phone, $ip);


        $build = http_build_query($data);
        Log::info('plants发送验证码参数 ' . $build);
        $gateway = $this->plantsConfig['gateway'] ;

//        $header = ['sign' => $sign, 'Timestamp' =>$time, 'Api-Key' => $appKey];
//        Log::info('header-签名 ' . json_encode($header)."###".$appKey .'-'. $password .'-'. $time);
        $HttpCurl = new HttpCurl();
        $res = $HttpCurl->curlPost($gateway, $build);

        Log::info('plants发送验证码结果：' . $res);

        try {
            $data = \GuzzleHttp\json_decode(trim($res), true);
            if (isset($data['code']) && $data['code'] == 0) {
                $this->setFrequent($ip, $phone, 3);
                return true;
            }
        }catch (\Exception $exception){
            if (strstr($res,'"code":"0"')) {
                $this->setFrequent($ip, $phone, 3);
                return true;
            }
        }

        $this->error = ['web.verify.send_error','Falha ao obter o código de verificação'];
        return false;

    }

    public function kmiSend($phone, $ip, $UserID, $Content)
    {
        $model = new GamePhoneVerityCode();

        $code = $this->code($phone);

        $data = [
            'accessKey' => $this->kmiConfig['access_key'],
            'secretKey' => $this->kmiConfig['secret_key'],
            //'from' => $content->TemplateID ?? '',
            'to' => '0055' . $phone,
            'message' => str_replace('{code}', $code, $Content),
            'callbackUrl' => $this->kmiConfig['callbackUrl']
        ];

        Log::info('发送验证码参数 ' . \GuzzleHttp\json_encode($data));
        $model->addCode($UserID, $code, $phone, $ip);

        $gateway = $this->kmiConfig['gateway'];

        $curl = new HttpCurl();
        $res = $curl->curlPost($gateway, $data, 'json',true);

        Log::info('发送验证码结果：' . $res);

        $data = \GuzzleHttp\json_decode($res, true);
        if (isset($data['code']) && $data['code'] == 200) {
            $this->setFrequent($ip, $phone,4);
            return true;
        }

        $this->error = 'No se pudo obtener el código de verificación';
        return false;
    }

    // 生成验证码
    public function code($phone)
    {

        // 如果之前发送过验证码并且还没使用，还返回之前的验证码
        $query = DB::connection('write')->table('QPTreasureDB.dbo.GamePhoneVerityCode')
            ->where('PhoneNum', $phone)
            ->first();

        if ($query) return $query->Code;


        $length = $this->config['lengthNum'] ?: 4;

        $characters = '0123456789';

        if (!is_int($length) || $length < 0) {
            return false;
        }
        $characters_length = strlen($characters) - 1;//因为字符串的顺序是从0开始的，下面的mt_rand()从0开始取，所以最后一个字符串要取到就只能减一
        $string = '';
        for ($i = $length; $i > 0; $i--) {
            $string .= $characters[mt_rand(0, $characters_length)];
        }

        if ($string[0] == 0) $string[0] = mt_rand(1, 9);

        return $string;
    }
// 验证码
    public function sendVerify($phone, $ip, $Type, $Channel = 0)
    {


        $first = DB::connection('write')->table('QPAccountsDB.dbo.AccountPhone')
            ->where('PhoneNum', $phone)
            ->where('Channel', $Channel)
            ->first();

        // 注册发送验证码 -- 已经绑定过不允许发送
        if ($Type == 0) {
            if ($first) {
                $this->error = ['web.verify.phone_already_bound', 'The phone number has already been bound'];
                return false;
            }
        } elseif ($Type == 1) { // 修改密码发送验证码 -- 判断手机号是否已经绑定
            if (!$first) {
                $this->error = ['web.verify.account_not_exist', 'Failed to send code, account does not exist'];
                return false;
            }
        }

        $redis = Redis::connection();

        // 限制IP一天发10次
        if ($redis->get(self::IP_DAILY_LIMIT_PREFIX . $ip) >= self::FREQUENT_IP_LIMIT_NUM) {
            $this->error = ['web.verify.too_many_ip_requests', 'You have sent too many messages from this IP, sending is blocked'];
            return false;
        }

        // 同一个手机号发送次数不能超过5次
        if ($redis->get(self::PHONE_DAILY_LIMIT_PREFIX . $phone) >= self::FREQUENT_PHONE_LIMIT_NUM) {
            $this->error = ['web.verify.too_many_phone_requests', 'You have sent too many messages from this phone number, sending is blocked'];
            return false;
        }

        // 发送间隔时间
        if ($redis->exists(self::PHONE_FREQUENT_LIMIT_PREFIX . $phone . '_' . $Type)) {
            $this->error = ['web.verify.too_frequent_requests', 'You are sending too fast, please try again later'];
            return false;
        }

        return apiReturnSuc();
    }


    /**
     * 设置频率
     * @param string $ip
     * @param string $phone
     */
    public function setFrequent($ip, $phone,$SendCodeConfigType)
    {
        Redis::set(self::PHONE_SEND_LASTCONFIG_PREFIX . $phone, $SendCodeConfigType);
        Redis::expire(self::PHONE_SEND_LASTCONFIG_PREFIX . $phone, 300);
        Redis::set(self::PHONE_FREQUENT_LIMIT_PREFIX . $phone, 1);
        Redis::expire(self::PHONE_FREQUENT_LIMIT_PREFIX . $phone, 118);
        Redis::incr(self::PHONE_DAILY_LIMIT_PREFIX . $phone);
        Redis::expireAt(self::PHONE_DAILY_LIMIT_PREFIX . $phone, strtotime('today +1 day'));
        Redis::incr(self::IP_DAILY_LIMIT_PREFIX . $ip);
        Redis::expireAt(self::IP_DAILY_LIMIT_PREFIX . $ip, strtotime('today +1 day'));
    }
}
