<?php

namespace Server\sms;

use App\Services\HttpService;
use App\Services\MicroService;
use Illuminate\Support\Facades\DB;

class SmsService extends MicroService
{

    public $setting = [];
    public $uniacid = 0;
    function __construct($uniacid=0){
        parent::__construct('sms');
        if (empty($uniacid)){
            $uniacid = $GLOBALS['_W']['uniacid'];
        }
        $this->Unique=true;
        $this->uniacid = $uniacid;
    }
    public $tables = array(
        "sms"=>"sms_template",
        "code"=>"sms_code",
        "setting"=>"sms_setting",
    );

    /**
     * HTTP方式访问
     * @param string|null $platform 路由通道，可选web、app、api及自定义通道
     * @param string|null $route 路由名称
     * @return array|\error 返回接口数据或报错信息
     * @throws \Exception
     */
    public function HttpRequest($platform="web", $route=""){
        global $_GPC, $_W;
        if (empty($route)){
            $route = empty($_GPC['ctrl']) ? 'index' : trim($_GPC['ctrl']);
        }
        $route = str_replace(".","/",$route);
        list($controller, $method) = explode("/", $route);
        if (empty($method)) $method = 'main';

        $class = "Server\\{$this->identity}\\{$platform}\\" . ucfirst($controller) . "Controller";
        if (!class_exists($class)){
            $class = "Server\\{$this->identity}\\{$platform}\IndexController";
            $method = $controller;
            $controller = 'index';
        }

        $_W['controller'] = $controller;
        $_W['action'] = $method;

        if (!class_exists($class)) return error(-1,__('controllerNotFound', ['ctrl'=>$class]));
        $instance = new $class();
        if (!method_exists($instance,$method)) return error(-1,"Method $class::$method() dose not exist!");
        return $instance->$method();
    }

    public function getList($condition=array(),$page=1,$fetch='all'){
        $where = "is_deleted=0 and uniacid=".$this->uniacid;
        $params = array();
        if(!empty($condition['keyword'])){
            $params[':keyword'] = "%".trim($condition['keyword'])."%";
            $params[':keytext'] = trim($condition['keyword']);
            $where .= " and (name like :keyword or template_id=:keytext or id=:keytext)";
        }
        $order = " order by createtime desc";
        $pagesize = empty($condition['pagesize']) ? 15 : intval($condition['pagesize']);
        $list = [];
        if ($fetch=='list' || $fetch=='all'){
            $limit = "";
            if ($page!=-1){
                $page = max(1,intval($page));
                $limit = " limit ".($page-1)*$pagesize .",$pagesize";
            }
            $select = empty($condition['select']) ? "*" : trim($condition['select']);
            $list = pdo_fetchall("select $select from ".tablename($this->tables['sms'])." where ".$where.$order.$limit,$params);
            if(!empty($list)){
                foreach ($list as &$value){
                    $value['createdate'] = date('Y-m-d H:i', $value['createtime']);
                    if(empty($value['updatetime'])){
                        $value['updatedate'] = '--';
                    }else{
                        $value['updatedate'] = date('Y-m-d H:i', $value['updatetime']);
                    }

                }
            }
            if($fetch=='list') return $list;
        }
        if ($fetch=='total' || $fetch=='all'){
            $total = (int)pdo_fetchcolumn("select count(*) from ".tablename($this->tables['sms'])." where ".$where,$params);
            if($fetch=='total') return $total;
        }
        $pager = pagination($total, $page, $pagesize);
        return array($list, $total, $pager);
    }

    public function getOne($id){
        return (array)pdo_get($this->tables['sms'],array('id'=>$id,'uniacid'=>$this->uniacid,'is_deleted'=>0));
    }

    public function saveSmsConfig($uniacid,$key,$params){
        if (is_array($params)){
            $params = serialize($params);
        }
        $complete = DB::table('sms_setting')->updateOrInsert(['uniacid'=>$uniacid],[$key=>$params]);
        return $complete;
    }

    public function getSmsConfig($uniacid){
        if (!empty($this->setting)){
            return is_error($this->setting) ? [] : $this->setting;
        }
        $res =  DB::table('sms_setting')->where('uniacid',$uniacid)->first();
        $setting = !empty($res['sms']) ? (array)unserialize($res['sms']) : array();
        $this->setting = $setting ?: error(-1, 'undefined');
        return $setting;
    }


    public function getSetting($key=""){
        if(empty($this->setting)){
            $setting = $this->SettingLoad($this->uniacid);
            $this->setting = $setting;
        }
        if (empty($key)) return $this->setting;
        return $this->setting[$key];
    }



    /**
     * 获取模板列表
     * @return array 查询结果
     */
    public function getTemplateList(){
        $where = "is_deleted=0 and uniacid=".$this->uniacid;
        $order = " order by createtime desc";
        $list = pdo_fetchall("select * from ".tablename($this->tables['sms'])." where ".$where.$order);
        return $list;
    }


    /**
     * 发送短信通知
     * @param string $phoneNumbers 支持对多个手机号码发送短信，手机号码之间以半角逗号（,）分隔
     * @param int $id 模板id
     * @param array|null $params 模板变量以及对应值
     * @return array|bool 发送结果
     */
    public function sendSms($phoneNumbers,$id,$params=array()){
        if(empty($phoneNumbers)){
            return error(-1,"手机号不能为空");
        }
        if(empty($id)){
            return error(-1,"模板id不能为空");
        }
        $template_info = $this->getOne($id);
        if (empty($template_info)) return error(-1,"模板不存在");
        //服务商  0 阿里云  1 腾讯云
        $provider = $template_info['provider'];
        $response = [];
        $this->Composer();
        switch ($provider){
            case 1 : {
                //腾讯云
                include_once MICRO_SERVER."sms/TencentService.php";
                $response = TencentService::sendTencentSMS($template_info,$phoneNumbers,$params);
                break;
            }
            case 2 : {
                //短信宝
                $response = $this->smsBaoSend($template_info, $phoneNumbers, $params);
                break;
            }
            default : {
                $response = AliService::sendAliSMS($template_info,$phoneNumbers,$params);
                break;
            }
        }
        if($response['code'] == 'OK'){
            return true;
        }else{
            return error(-1,$response['msg']);
        }
    }

    /**
     * 发送短信验证码
     * @param string $phoneNumber 接收验证码的手机号，只支持单个
     * @return array|bool 发送结果
     */
    public function sendVerifyCode($phoneNumber, $international=false, $code=0){
        if(empty($phoneNumber)){
            return error(-1,"手机号不能为空");
        }
        //获取短信配置
//        $setting = self::SettingLoad('sms',$this->uniacid);
        $setting = self::getSmsConfig($this->uniacid);
//        $template_info = $this->getOne($setting['sms']['verifytemplateid']);
        $verifytemplateid = $international ? $setting['verifytemplate_org'] : $setting['verifytemplateid'];
        $template_info = $this->getOne($verifytemplateid);
        if (empty($template_info)) return error(-1,"模板不存在");
        //服务商  0 阿里云  1 腾讯云
        $provider = $template_info['provider'];
        $this->Composer();

        //随机生成6位数字验证码
        $rand_code = $code ?: mt_rand(100000,999999);
        if(!empty($rand_code)){
            //存储到数据表
            $insert_data = array(
                'uniacid'=>$this->uniacid,
                'mobile'=>$phoneNumber,
                'verify_code'=>$rand_code,
                'createtime'=>TIMESTAMP,
            );
            $where = "uniacid=".$this->uniacid." and mobile=".$phoneNumber;
            $old_codes =  pdo_fetchall("select * from ".tablename($this->tables['code'])." where ".$where);
            if(!empty($old_codes)){
                foreach ($old_codes as $key=>$val){
                    pdo_delete($this->tables['code'], array('id'=>$val['id']));
                }
            }
            $inser_id = pdo_insertgetid($this->tables['code'], $insert_data);
        }
        $response = [];
        $params = array('code'=>$rand_code);
        switch ($provider){
            case 1 : {
                //腾讯云
                include_once MICRO_SERVER."sms/TencentService.php";
                $response = TencentService::sendTencentSMS($template_info,$phoneNumber, [$rand_code]);
                break;
            }
            case 2 : {
                //短信宝
                $response = $this->smsBaoSend($template_info, $phoneNumber, $params);
                break;
            }
            default : {
                //阿里云
                $response = AliService::sendAliSMS($template_info,$phoneNumber,$params);
                break;
            }
        }
        if($response['code'] == 'OK'){
            return true;
        }else{
            pdo_delete($this->tables['code'], array('uniacid'=>$this->uniacid,'id'=>$inser_id));
            return error(-1,$response['msg']);
        }

    }

    public function smsBaoSend($template_info, $phoneNumber, $params){
        $setting = $this->getSmsConfig($this->uniacid);
        if (isset($setting['smsbao_status']) && empty($setting['smsbao_status'])){
            return ['code'=>"ERROR", 'msg'=>'未开启短信平台'];
        }
        $password = env('SMS_BAO_API_Key', $setting['smsbao_token']);
        $username = env('SMS_BAO_USERNAME', $setting['smsbao_user']);
        if (empty($password) || empty($username)) return ['code'=>"ERROR", 'msg'=>'未配置短信平台用户名或API Key'];
        $content = trim(htmlspecialchars_decode($template_info['template_id']));
        if (!empty($params)){
            foreach ($params as $key=>$value){
                $placeholder = '{' . $key . '}';
                $content = str_replace($placeholder, $value, $content);
            }
        }
        $content = "【{$template_info['sign']}】" . $content;
        $mobile = is_array($phoneNumber) ? implode(",", $phoneNumber) : trim($phoneNumber);
        $url = "https://api.smsbao.com/sms?u={$username}&p={$password}&m={$mobile}&c=" . urlencode($content);
        $result = HttpService::ihttp_request($url);
        if (is_error($result)){
            return ['code'=>"ERROR", 'msg'=>$result['message']];
        }

        $res = intval($result['content']);
        if ($res===0){
            return ['code'=>"OK", 'msg'=>"发送成功"];
        }
        $key = "error_" . $res;
        $errors = [
            "error_30"=>"错误密码",
            "error_40"=>"账号不存在",
            "error_41"=>"余额不足",
            "error_43"=>"IP地址限制",
            "error_50"=>"内容含有敏感词",
            "error_51"=>"手机号码不正确"
        ];
        return ['code'=>"ERROR", 'msg'=>$errors[$key]];
    }

    /**
     * 校验验证码
     * @param string $phoneNumber 接收验证码的手机号，只支持单个
     * @param string $verifyCode 验证码
     * @return array|bool 校验结果
     */
    public function checkVerifyCode($phoneNumber,$verifyCode){
        if(empty($phoneNumber)){
            return error(-1,"手机号不能为空");
        }
        if(empty($verifyCode)){
            return error(-1,"验证码不能为空");
        }
        $code_info =  pdo_get($this->tables['code'],array('uniacid'=>$this->uniacid,'mobile'=>$phoneNumber));
        if(empty($code_info)){
            return error(-1,"校验失败");
        }
        if($code_info['verify_code'] != $verifyCode){
            return error(-1,"验证码错误");
        }
        //有效期默认5分钟
        $expire_time = $code_info['createtime']+5*60;
        if($expire_time<TIMESTAMP){
            pdo_delete($this->tables['code'], array('id'=>$code_info['id']));
            return error(-1,"验证码已过期");
        }
        pdo_delete($this->tables['code'], array('id'=>$code_info['id']));
        return true;
    }

}
