<?php
namespace app\api\controller;

use think\Controller;
use think\Db;

/**
 * 订单支付回调
 */
class Notify extends Controller
{
    protected $noNeedLogin = ['*'];
    protected $noNeedRight = ['*'];

    public function checkNotify($args = []){

        $secret = config('hitpay.salt');

        $input_hmac = $args['hmac'];
        unset($args['hmac']);

        //hitpay/client/generateSignatureArray
        $hmacSource = [];
        foreach ($args as $key => $val) {
            $hmacSource[$key] = "{$key}{$val}";
        }
        ksort($hmacSource);
        $sig = implode("", array_values($hmacSource));
        $new_hmac = hash_hmac('sha256', $sig, $secret);

        //判断相等
        if($new_hmac == $input_hmac){
            return true;
        }else{
            return false;
        }
    }

    //主动获取一次
    private function getPaymentStatus($payment_request_id){
        $apiKey = config('hitpay.apikey');
        $hitPayClient = new \HitPay\Client($apiKey, true);
        $data = $hitPayClient->getPaymentStatus($payment_request_id);
        return $data->status;
    }

    //充值金币 异步回调对外方法
    public function recharge_notify_base(){

        //日志
        $paytype = 'hitpay';
        $notify_file = $this->notify_log_start($paytype);

        //接参
        $field = ['payment_id','payment_request_id','phone','amount','currency','status','reference_number','hmac'];
        $notify_data = request_post_hub($field);

        //验签
        $checkNotify = $this->checkNotify($notify_data);
        if ($checkNotify !== true) {
            echo '签名错误';
            exit;
        }

        //检查支付完成 completed / failed
        if($notify_data['status'] != 'completed'){
            $now_status = $this->getPaymentStatus($notify_data['payment_request_id']);
            if($now_status != 'completed'){
                echo '没有支付完成';
                exit;
            }
        }

        //验证,拿订单号等信息
        $out_trade_no       = $notify_data['reference_number'];
        $payment_request_id = $notify_data['payment_request_id'];
        $payment_id         = $notify_data['payment_id'];
        //订单查询
        $map = [
            'out_trade_no'       => $out_trade_no,
            'payment_request_id' => $payment_request_id,
        ];
        $info = Db::name('pay_order')->where($map)->find();

        if(empty($info)){
            echo 'success';
            exit;
        }

        if($info['order_status'] != 0)
        {
            echo 'success';
            exit;
        }
        //你可以在此编写订单逻辑
        $rs = $this->recharge_notify_do($out_trade_no,$payment_request_id,$payment_id);
        if($rs === false){
            //不论结果都应返回success
            echo 'success';
            exit;
        }else{
            //不论结果都应返回success
            echo 'success';
            exit;
        }

        //默认
        echo 'success';
        exit;
    }

    //充值金币 逻辑
    private function recharge_notify_do($out_trade_no,$payment_request_id,$payment_id){

        $time = time();

        Db::startTrans();
        $orderInfo = Db::name('pay_order')->where(['out_trade_no' => $out_trade_no])->lock(true)->find();
        if (empty($orderInfo)) {
            Db::rollback();
            return false;
        }

        if($orderInfo['order_status'] != 0){
            Db::rollback();
            return false;
        }

        //逻辑开始
        //试课预约
        if($orderInfo['table_name'] == 'trylesson_order'){
            $update = [
                'order_status' => 10,
                'paytime'      => $time,
                'updatetime'   => $time,
            ];
            $rs = Db::name('trylesson_order')->where('id',$orderInfo['table_id'])->update($update);
            if($rs === false){
                Db::rollback();
                return false;
            }
        }
        //售课预约
        if($orderInfo['table_name'] == 'lesson_order'){
            $update = [
                'order_status' => 10,
                'paytime'      => $time,
                'updatetime'   => $time,
            ];
            $rs = Db::name('lesson_order')->where('id',$orderInfo['table_id'])->update($update);
            if($rs === false){
                Db::rollback();
                return false;
            }
        }
        //售课预约买套餐
        if($orderInfo['table_name'] == 'package_order'){
            //修改套餐单
            $update = [
                'order_status' => 1,
                'paytime'      => $time,
                'updatetime'   => $time,
            ];
            $rs = Db::name('package_order')->where('order_no',$orderInfo['out_trade_no'])->update($update); //这里不用id,是因为另有赠品单,两个一起更新
            if($rs === false){
                Db::rollback();
                return false;
            }

            //修改预约单。这一块最好搬到计划任务里
            $args = json_decode($orderInfo['args'],true);
            if(isset($args['lesson_order_id']) && !empty($args['lesson_order_id'])){

                $package_order = Db::name('package_order')->where('order_no',$orderInfo['out_trade_no'])->where('is_gift',0)->find();
                $lesson_order  = Db::name('lesson_order')->where('id',$args['lesson_order_id'])->find();

                //课时能够支撑报名人数
                if($package_order['remain'] >= $lesson_order['usernumber']){

                    //扣除一节
                    $update = [
                        'remain'     => $package_order['remain'] - $lesson_order['usernumber'],
                        'updatetime' => time(),
                    ];
                    $rs1 = Db::name('package_order')->where('id',$package_order['id'])->update($update);
                    if($rs1 === false){
                        Db::rollback();
                        return false;
                    }

                    //修改预约单状态
                    $update = [
                        'order_status' => 10,
                        'paytime'      => $time,
                        'updatetime'   => $time,
                        'package_order_id' => $package_order['id'],
                        'paytype' => 1,  //从购买套餐中3,改为 课程套餐1
                    ];
                    if($lesson_order['usernumber'] > 1){
                        $update['package_remark'] = ($package_order['sessions'] - $package_order['remain'] + 1) . '-' . ($package_order['sessions'] - $package_order['remain'] + $lesson_order['usernumber']) .'/'. $package_order['sessions'];
                    }else{
                        $update['package_remark'] = ($package_order['sessions'] - $package_order['remain'] + 1) .'/'. $package_order['sessions'];
                    }
                    $rs = Db::name('lesson_order')->where('id',$args['lesson_order_id'])->update($update);
                    if($rs === false){
                        Db::rollback();
                        return false;
                    }
                }else{
                    //新买的课时不足以支撑这次的报名人数,不处理
                }
            }

        }

        //逻辑结束

        //状态
        $ros = Db::name('pay_order')->where(['out_trade_no' => $out_trade_no])->update(['order_status'=>1,'notifytime'=>$time,'payment_id'=>$payment_id]);
        if($ros === false) {
            Db::rollback();
            return false;
        }

        //默认提交
        Db::commit();
        return true;
    }

    //异步日志
    private function notify_log_start($paytype = 'wechat'){
        //记录支付回调数据
        ignore_user_abort(); // run script in background
        set_time_limit(30);
        // 日志文件 start
        $log_base_dir = '../paylog/'.$paytype.'/';
        if (!is_dir($log_base_dir))
        {
            mkdir($log_base_dir, 0770, true);
            @chmod($log_base_dir, 0770);
        }
        $notify_file = $log_base_dir.'notify.txt';
        if(!file_exists($notify_file)) {
            @touch($notify_file);
            @chmod($notify_file, 0770);
        }
        if(filesize($notify_file)>5242880)//大于5M自动切换
        {
            rename($notify_file, $log_base_dir.'notify_'.date('Y_m_d_H_i_s').'.txt');
        }
        if(!file_exists($notify_file)) {
            @touch($notify_file);
            @chmod($notify_file, 0770);
        }
        // 日志文件 end
        //开始写入
        $xml = file_get_contents("php://input");
        file_put_contents($notify_file, "\r\n\r\n".date('Y-m-d H:i:s')." [notify][入口接收php://input流原始数据] \n".$xml, FILE_APPEND);

        ini_set('display_errors','On');

        return $notify_file;

    }
}