<?php

/**
 * 统一的预创建订单请求对象
 * @version
 *          1.0.0 Created at 2017-12-21. by --gwang
 * @author gwang (mail@wanggangzero.cn)
 * @copyright ? 2017-12-21, SJZ LoyalSoft Corporation & gwang. All rights reserved.
 */
class PayRequest extends loyalsoft\Object_ext {

    const orderTab = 'tpl_order_tab';

    /**
     * @var bool 是否测试(金额降低100倍)(线上版千万别瞎改)
     */
    const isTest = false;

    /**
     * @var string 充值回调透传参数(len=250)
     */
    public $callbackInfo;

    /**
     * 各平台取自己的配置信息
     * @var string 充值回调地址(len=100)
     */
    public $notifyUrl;

    /**
     * @var string 订单ID (len=30)
     */
    public $cpOrderId;

    /**
     * @var float 充值金额 (单位:元) (特:入库时会x100转为分)
     */
    public $amount;

    /**
     * @var string 货币类型(默认:CNY)
     */
    public $currency = 'CNY';

    /**
     * @var string 平台UID
     */
    public $accountId;

    /**
     * @var int 游戏中的分区id
     */
    public $zoneid;

    /**
     * @var string 渠道
     */
    public $channel;

    /**
     * @var string 道具id
     */
    public $product_id;

    /**
     * @var string 道具名称
     */
    public $product_name;

    /**
     *
     * @var string 道具描述
     */
    public $product_desc;

    /**
     * @var string 道具单价
     */
    public $product_price;

    /**
     * @var int (购买)道具数量
     */
    public $product_count;

    /**
     * @var 防沉迷年龄段 ( -1 未实名, 0(0~7) 8(8~16) 16(16~18) 18(18+成年)
     * #[optional]
     */
    public $ageRange = -1;

    /**
     * @var string 公会id
     */
    public $party_id;
    public $party_name;

    /**
     * @var string 签名算法, 目前固定为MD5
     */
    public $signType = "MD5";

    /**
     *
     * @var string MD5(签名内容+apiKey)
     */
    public $sign;

    /**
     * @var int 订单编号
     */
    private $order_id;

    /**
     *
     * @return array 订单写入数据库
     */
    public function InserDataBase() {
//        return false;                                                           # 2019.10.9 关闭充值
        if (self::isTest) {
            $this->channel = 'tester';                                          # 测试
        }
        $arr = get_object_vars($this);                                          # 转为数组
        $arr["uid"] = $arr["accountId"];                                        # 转换下变量名称
        $arr["amount"] = $arr["amount"] * 100;                                  # 拉起平台时传的单位是元,比如UC还有易接,而游戏后台存储的是分
        unset($arr["signType"]);                                                # 毙掉后台不需要的数据
        unset($arr["sign"]);
        unset($arr["accountId"]);
        unset($arr['order_id']);
        unset($arr['ageRange']);
        unset($arr['product_desc']);
        $n = loyalsoft\daoInst()->update(self::orderTab)
                ->data($arr)
                ->where('id')->eq($this->order_id)
                ->exec();
        return $n == 1;
    }

    /**
     * @return array 拉取签名参数数组
     */
    public function uc_GetData2Sign() {
        $sid = array('callbackInfo', 'amount', 'notifyUrl', 'cpOrderId', 'accountId');
        $arr = array();
        foreach (get_object_vars($this) as $key => $value) {
            if (in_array($key, $sid)) {
                $arr[$key] = $value;
            }
        }
        return $arr;
    }

    /**
     * @return array 普通返回值数组
     */
    public function retData() {
        $sid = array('callbackInfo', 'amount', 'product_price', 'product_count', 'notifyUrl', 'cpOrderId');
        $arr = array();
        foreach (get_object_vars($this) as $key => $value) {
            if (in_array($key, $sid)) {
                $arr[$key] = $value;
            }
        }
        return $arr;
    }

    /**
     * @return array 小七手游订单结构(未签名)
     * @deprecated since version 0 已废弃
     */
    public function x7sy_retData() {
        $ret = array(
            'extends_info_data' => $this->callbackInfo, //                      // 透传参数
            'game_area' => $this->zoneid,
            'game_guid' => $this->accountId,
            'game_level' => 0,
            'game_orderid' => $this->cpOrderId,
            'game_price' => $this->product_price, //                            // 对方要求单位:元
            'game_role_id' => "no",
            'game_role_name' => "no",
            'notify_id' => "3788", //                                             // 如果只有一个可以设置为-1,但不可以设置为0
            'subject' => $this->product_name
        );
        return $ret;
    }

    /**
     * @return array 易接返回值数组
     * @deprecated since version 0 已废弃
     */
    public function yijie_retData() {
        return $this->retData();
    }

    /**
     * 华为 订单通知魔改版
     * @param type $params 参考:https://developer.huawei.com/consumer/cn/doc/development/HMSCore-References/server-data-model-0000001050986133#section264617465219
     */
    static function From_HW($params) {
        $infoArr = array();
        \loyalsoft\CLog::pay($params);
        $callbackInfo = $params['developerPayload'];
        $infos = explode(',', $callbackInfo);                                                                                                                                     # uid,zoneid,cpOrderId,productId

        $infoArr['orderId'] = $params['orderId'];
        $infoArr['accountId'] = $infos[0];                                                                                                                                         # uid
        $infoArr['amount'] = number_format($params['price'] / 100, 2, '.', ''); # 分转元                                                                                                                               # 华为给过来是分, 这里先转换为元, 入库时再统一以分为单位
        $infoArr['currency'] = $params['currency'];                                                                                                                         # 如果是海外会有不同的货币类型
        $infoArr['product_id'] = $params['productId'];
        $infoArr['product_count'] = 1;
        $infoArr['channel'] = "huawei";                                                                                                                                            # 华为
        $infoArr['zoneid'] = (int) $infos[1];                                                                                                                                       # 分区信息
        $infoArr['callbackInfo'] = $callbackInfo;

        $o = new payRequest($infoArr);
        $o->cpOrderId = $infos[2];                                                                                                                                                  # 重新修订下cpOrderId
        return $o;
    }

    public function __construct($arg = null) {
        parent::__construct($arg);
        if (!$this->accountId || !$this->product_id || !$this->amount || !$this->channel) {
            \loyalsoft\CLog::pay('参数缺失');
            exit('{"err":1,"msg":"参数缺失!"}');
        }
        $this->callbackInfo = $this->accountId . "," . $this->zoneid;
        if (self::isTest) {
            $this->amount *= 0.01;  // 也可以改成固定值 0.01, 更省钱些.
        }
//        if ($this->channel == "mi") {
//            $this->amount = 1;
//        }
        if ($this->amount) {
//            $this->amount = number_format($this->amount, 2, '.', '');
//            if ('soft' == $this->channel) {                                     # 2018年1月15号以前固定为1分钱测试
//                $this->amount = number_format(0.01, 2, '.', '');
//                $this->product_price = 0.01;
//            } else  //
//            if ($this->amount != loyalsoft\GameConfig::shop_getItem($this->product_id)->price) {
//                var_dump($this->product_id);
//                var_dump(loyalsoft\GameConfig::shop_getItem($this->product_id)->price);
//                \loyalsoft\CLog::pay('金额不符' . $this->amount . " ");
//                exit('{"err":1,"msg":"金额不符!"}');
//            }
        }
        loyalsoft\daoInst()->insert(self::orderTab)                                                                                                                          # 创建一个新的订单
                ->data(array('order_ts' => loyalsoft\now()))
                ->exec();
        $this->order_id = loyalsoft\daoInst()->select('last_insert_id() as id')->fetch('id');                                                           # 取刚才创建的订单的自增id
        $this->cpOrderId = LoyalsoftAPPID . \date('ymdHi') . substr(sprintf("%1$06d", $this->order_id), -6);                          # 商户唯一id(尾部附加自增id后6位数)
        $this->callbackInfo .= "," . $this->cpOrderId;                                                                                                                     # 将cpOrderId追加到透传参数中
        $this->notifyUrl = $this::get_notify_url();                                                                                                                              # 自动提取支付回调地址
    }

    /**
     * PS. 仅限pay.php作为入口使用才行
     * @return string 获取支付回调地址,
     */
    public function get_notify_url() {
        $url = "https://" . $_SERVER['HTTP_HOST'] . $_SERVER["REQUEST_URI"];
        switch ($this->getPlatStr()) {
            case "hykb":
                $nurl = substr($url, 0, strpos($url, "pay.php")) . "notify_hykb.php";
                break;
            default:
                $nurl = substr($url, 0, strpos($url, "pay.php")) . "notify.php";
                break;
        }
        return $nurl;                                                           # 回调地址
    }

    /**
     * 未成年检查 (国内版)
     * @return type
     */
    public function AntiAdditionCheck() {
        $uid = $this->accountId;
        $ageRange = $this->ageRange;
        $amt = $this->amount;

        if (isset($uid) && isset($ageRange)) {
            $monthTS = loyalsoft\TimeUtil::tsMonthBegin();                                                             # 本月初起始时间戳
            $dayTS = loyalsoft\TimeUtil::tsDayBegin();                                                                       # 当天起始时间戳
            $monthTotal = loyalsoft\daoInst()
                    ->select("sum(`amount`)/100 as total")                                                                         # 总金额(单位:分转元)
                    ->from("tpl_order_tab")
                    ->where("uid")->eq($uid)                                                                                               # 该玩家
                    ->andWhere("status")->eq(1)                                                                                         # 成交订单
                    ->andWhere("order_ts")->ge($monthTS)                                                                      # 本月
                    ->fetch('total');
            if (!is_numeric($monthTotal)) {
                $monthTotal = 0;
            }
            $dayTotal = loyalsoft\daoInst()
                    ->select("sum(`amount`)/100 as total")                                                                         # 总金额(单位:分转元)
                    ->from("tpl_order_tab")
                    ->where("uid")->eq($uid)                                                                                               # 该玩家
                    ->andWhere("status")->eq(1)                                                                                        # 成交订单
                    ->andWhere("order_ts")->ge($dayTS)                                                                           # 今日
                    ->fetch('total');
            if (!is_numeric($dayTotal)) {
                $dayTotal = 0;
            }
            if ($ageRange < 0 || !is_numeric($ageRange)) {
                return \payResp::err(1, "未完成实名认证的用户暂不提供充值.");
            } else if ($ageRange < 8) {
                return \payResp::err(1, "未满8周岁的用户暂不提供充值.");
            } else if ($ageRange < 16) {                                                                # 单笔/每月: 50,200
                if ($amt > 50) {
                    return \payResp::err(1, "单笔充值金额不高于50￥");
                }
//            if (($amt + $dayTotal) > 100) {
//                return \Resp::err(1, "单日累计充值金额不高于100￥");
//            }
                if (($amt + $monthTotal) > 200) {
                    return \payResp::err(1, "当月累计充值金额不高于200￥");
                }
            } else if ($ageRange < 18) {                                                              # 单笔/每月: 100,400
                if ($amt > 100) {
                    return \payResp::err(1, "单笔充值金额不高于100￥");
                }
//            if (($amt + $dayTotal) > 100) {
//                return \Resp::err(1, "单日累计充值金额不高于100￥");
//            }
                if (($amt + $monthTotal) > 400) {
                    return \payResp::err(1, "当月累计充值金额不高于400￥");
                }
            }
            return \payResp::ok("ok");
        }
        return \payResp::err(-1, "参数不足");                                                   # 其他情况
    }

    /**
     * 获得用户的平台字符串
     * @return string
     */
    function getPlatStr() {
        if (strrpos($this->accountId, '_') > 0) {
            return substr($this->accountId, strrpos($this->accountId, '_') + 1); # 提取平台字符串
        } else {
            return "";
        }
        //PS. substr() 函数返回字符串的一部分 strrpos() 函数查找字符串在另一字符串中最后一次出现的位置。
    }

    /**
     * 获得用户的平台唯一id.
     * @return string
     */
    public function getPlatOid() {
        return substr($this->accountId, 0, strrpos($this->accountId, '_'));         # 提取平台字符串
        //PS. substr() 函数返回字符串的一部分 strrpos() 函数查找字符串在另一字符串中最后一次出现的位置。
    }
}
