<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/9/21
 * Time: 16:53
 */

namespace app\api\controller;

use app\common\utils\WXSendMessage;
use think\Db;
use think\Exception;
use think\Loader;
use think\Validate;
use app\common\model\Project as ProjectModel;
use app\common\model\Order as OrderModel;
use app\common\model\User as UserModel;
use app\common\model\Refund as RefundModel;


Loader::import('wxpay.Api');

class Order extends Base
{
    /**
     * 活动下单
     * @url /api/Order/projectOrder
     * @param pid
     * @param nickname
     * @param phone
     * @param adult_number
     * @param children_number
     * @param children_age
     * @param sign_limits
     * @param remark
     * @return json
     */
    public function projectOrder()
    {

        //检验参数
        $validate = Validate::make([
            'pid'             => 'require',
            'nickname'        => 'require',
            'phone'           => 'require',
            'adult_number'    => 'require',
            'children_number' => 'require',
            'children_age'    => 'require',
            'sign_limits'     => 'require',
        ]);
        $res      = $validate->check(input('post.'));
        if (!$res) return ['code' => 1, 'msg' => $validate->getError()];
        $project = ProjectModel::get(input('post.pid'));
        if (!$project) {
            return ['code' => 1, 'msg' => '该活动不存在'];
        }
        //检验该活动是否有效期
        if (time() > strtotime($project->sign_endtime)) {
            //活动过期
            return ['code' => 1, 'msg' => '活动已截止报名'];
        }
        //生成订单
        try {
            //开始事务
            Db::startTrans();
            //检验家庭组限制->已上锁
            $res = OrderModel::getGroupNumberByProject(input('post.pid'), input('post.sign_limits'));
            if (!$res) throw new \Exception('该活动报名已满!');
            //生成订单入库
            $order        = new OrderModel();
            $order->type  = config('order_type.project');
            $order->uid   = $this->userinfo[0];
            $order->pid   = $project['id'];
            $order->title = $project['title'];
            //查看是否为会员
            $user = UserModel::get($this->userinfo[0]);
            //活动总价
            $price            = $user['is_vip'] ? $project['vip_price'] : $project['price'];
            $order->total_fee = $price * 100 * input('post.sign_limits') / 100;
            $order->status    = config('order_status.no_pay');
            $order->extras    = [
                'nickname'        => input('post.nickname'),
                'phone'           => input('post.phone'),
                'adult_number'    => input('post.adult_number'),
                'children_number' => input('post.children_number'),
                'children_age'    => input('post.children_age'),
                'sign_limits'     => input('post.sign_limits'),
                'address'         => input('post.address'),
                'price'           => $price,
                'remark'          => input('post.remark'),
            ];
            if (!$order->save()) {
                throw new \Exception('报名失败,请稍后再试');
            }
            $data['order_id']  = intval($order->id);
            $data['total_fee'] = doubleval($order->total_fee);
            //生成订单
            // 更新订单号-防止签名失败
            $order->out_trade_no = (new \WxPayConfig())->GetMerchantId() . time() . $order->id;
            $config              = new \WxPayConfig();
            $input               = new \WxPayUnifiedOrder();
            $input->SetBody($order->title);
            $input->SetAttach($order->id);
            $input->SetOut_trade_no($order->out_trade_no);
            $input->SetTotal_fee(floatval($order->total_fee) * 100);  // 单位为分
            $input->SetTime_start(date("YmdHis"));
            $input->SetTime_expire(date("YmdHis", time() + 600));
            //$input->SetGoods_tag("wx-xcx");
            $input->SetNotify_url(config('wx_pay.notify_url'));
            $input->SetTrade_type("JSAPI");
            $input->SetOpenid($this->userinfo[2]);
            $unifiedOrder = \WxPayApi::unifiedOrder($config, $input);
            if ($unifiedOrder["return_code"] == 'FAIL') {
                return ['code' => 1, 'msg' => $unifiedOrder['return_msg']];
            }
            // 保存 prepay_id 用于发送模版消息
            $order->prepay_id = $unifiedOrder['prepay_id'];
            $order->save();
            $jsApiParameters = $this->GetJsApiParameters($unifiedOrder);
            if ($jsApiParameters) {
                Db::commit();
                return ['code' => 0, 'msg' => '支付参数', 'data' => $data, 'result' => json_decode($jsApiParameters)];
            } else {
                throw new \Exception('订单签名失败');
            }
        } catch (\Exception $e) {
            Db::rollback();
            return ['code' => 1, 'msg' => $e->getMessage()];
        }

    }

    /**
     * vip购买
     * @url /api/Order/vipOrder
     * @param year
     * @return json
     */
    public function vipOrder()
    {

        //检验参数
        $validate = Validate::make([
            'year' => 'require',
        ]);
        $res      = $validate->check(input('post.'));
        if (!$res) return ['code' => 1, 'msg' => $validate->getError()];
        //生成订单

        try {
            //开始事务
            Db::startTrans();
            $year = intval(input('post.year'));
            //生成订单入库
            $order        = new OrderModel();
            $order->type  = config('order_type.vip');
            $order->uid   = $this->userinfo[0];
            $order->title = config('wx_pay.vip_title');
            //活动总价
            $order->total_fee = config('wx_pay.vip_price') * 100 * $year / 100;
            //查看vip有效期
            $user = UserModel::get($this->userinfo[0]);
            if ($user->is_vip == 1) {
                if (strtotime($user->vip_endtime) > time()) {//累加
                    $vip_endtime = strtotime("{$user->vip_endtime} +{$year} year");
                } else {
                    $vip_endtime = strtotime("+{$year} year");
                }
            } else {
                $vip_endtime = strtotime("+{$year} year");
            }
            $vip_endtime   = date('Y-m-d H:i:s', $vip_endtime);
            $order->status = config('order_status.no_pay');
            $order->extras = [
                'year'        => $year,
                'vip_endtime' => $vip_endtime,
                'price'       => config('wx_pay.vip_price'),
                'remark'      => input('post.remark'),
            ];
            if (!$order->save()) {
                throw new \Exception('购买失败,请稍后再试');
            }
            $data['order_id']  = intval($order->id);
            $data['total_fee'] = doubleval($order->total_fee);
            // 生成订单
            // // 更新订单号-防止签名失败
            $order->out_trade_no = (new \WxPayConfig())->GetMerchantId() . time() . $order->id;
            $config              = new \WxPayConfig();
            $input               = new \WxPayUnifiedOrder();
            $input->SetBody($order->title);
            $input->SetAttach($order->id);
            $input->SetOut_trade_no($order->out_trade_no);
            $input->SetTotal_fee(floatval($order->total_fee) * 100);  // 单位为分
            $input->SetTime_start(date("YmdHis"));
            $input->SetTime_expire(date("YmdHis", time() + 600));
            // $input->SetGoods_tag("wx-xcx");
            $input->SetNotify_url(config('wx_pay.notify_url'));
            $input->SetTrade_type("JSAPI");
            $input->SetOpenid($this->userinfo[2]);
            $unifiedOrder = \WxPayApi::unifiedOrder($config, $input);
            if ($unifiedOrder["return_code"] == 'FAIL') {
                return ['code' => 1, 'msg' => $unifiedOrder['return_msg']];
            }
            // 保存 prepay_id 用于发送模版消息
            $order->prepay_id = $unifiedOrder['prepay_id'];
            $order->save();
            $jsApiParameters = $this->GetJsApiParameters($unifiedOrder);
            if ($jsApiParameters) {
                Db::commit();
                return ['code' => 0, 'msg' => '支付参数', 'data' => $data, 'result' => json_decode($jsApiParameters)];
            } else {
                throw new \Exception('订单签名失败');
            }

        } catch (\Exception $e) {
            Db::rollback();
            return ['code' => 1, 'msg' => $e->getMessage()];
        }
    }

    /**
     *
     * 获取jsapi支付的参数
     * @param array $UnifiedOrderResult 统一支付接口返回的数据
     * @throws WxPayException
     * @return json数据，可直接填入js函数作为参数
     */
    private function GetJsApiParameters($UnifiedOrderResult)
    {
        if (!array_key_exists("appid", $UnifiedOrderResult)
            || !array_key_exists("prepay_id", $UnifiedOrderResult)
            || $UnifiedOrderResult['prepay_id'] == "") {
            return null;
        }

        $jsapi = new \WxPayJsApiPay();
        $jsapi->SetAppid($UnifiedOrderResult["appid"]);
        $timeStamp = time();
        $jsapi->SetTimeStamp("$timeStamp");
        $jsapi->SetNonceStr(\WxPayApi::getNonceStr());
        $jsapi->SetPackage("prepay_id=" . $UnifiedOrderResult['prepay_id']);

        $config = new \WxPayConfig();
        $jsapi->SetPaySign($jsapi->MakeSign($config));
        $parameters = json_encode($jsapi->GetValues());
        return $parameters;
    }

    /**
     * 微信支付回调接口，由微信服务器主动调用
     * @return xml
     */
    public function callback()
    {

        $xml  = file_get_contents("php://input");
        $data = simplexml_load_string($xml);//将文件转换成 对象

        if (empty($data->transaction_id)) {
            echo $this->toXML(['return_code' => 'FAIL', 'return_msg' => '参数错误']);
            exit;
        }

        // 查询订单，判断订单真实性
        if (!$data->out_trade_no || !$this->Queryorder($data->transaction_id)) {
            echo $this->toXML(['return_code' => 'FAIL', 'return_msg' => '订单真实性存疑']);
            exit;
        }
        $order = OrderModel::where(['out_trade_no' => $data->out_trade_no])->find();

        if (!$order) {
            echo $this->toXML(['return_code' => 'FAIL', 'return_msg' => '订单不存在']);
            exit;

        }

        $succeed = false;

        Db::startTrans();

        try {
            // 订单状态更新 - 已支付
            $order->status       = config("order_status.pay");
            $order->trade_status = 'SUCCESS';
            $order->save();

            if ($order->type == config('order_type.vip')) {

                $order             = OrderModel::get($data->attach);
                $user              = UserModel::get($order->uid);
                $user->is_vip      = 1;
                $user->vip_endtime = $order['extras']['vip_endtime'];
                $user->save();
            } else {
                //限制组数加1
                //获取订单的项目
                $project           = ProjectModel::get($order->pid);
                $project->sign_num = $project->sign_num + $order['extras']['sign_limits'];
                $project->save();
            }

            // 提交事务
            Db::commit();
            $succeed = true;
        } catch (\Exception $e) {
            // 回滚事务
            Db::rollback();
            $succeed = false;

        }


        if ($succeed) {
            echo $this->toXML(['return_code' => 'SUCCESS', 'return_msg' => 'OK']);
        } else {
            echo $this->toXML(['return_code' => 'FAIL', 'return_msg' => '回调失败']);
        }
    }

    /**
     * 查询订单
     *
     * @param [type] $transaction_id
     * @return void
     */
    private function Queryorder($transaction_id)
    {
        $input  = new \WxPayOrderQuery();
        $config = new \WxPayConfig();
        $input->SetTransaction_id($transaction_id);
        $result = \WxPayApi::orderQuery($config, $input);
        if (array_key_exists("return_code", $result)
            && array_key_exists("result_code", $result)
            && $result["return_code"] == "SUCCESS"
            && $result["result_code"] == "SUCCESS") {
            return true;
        }
        return false;
    }

    /**
     * 获取vip一年价格
     * @url /api/Order/getVipPrice
     * @return json
     */
    public function getVipPrice()
    {
        return ['code' => 0, 'msg' => 'success', 'price' => number_format(config('wx_pay.vip_price'), 2)];
    }

    /**
     * 订单列表
     * @param p 页数
     * @param page 每页几条
     * @param status 状态
     * @return json
     */
    public function index()
    {
        $p      = input('post.p/d', 1);
        $page   = input('post.page/d', 8);
        $status = input('post.status/d', 1);
        $uid    = $this->userinfo[0];
        $order  = OrderModel::with('project')
            ->where('status', $status)
            ->where('uid', $uid)
            ->where('type', 1)
            ->page($p, $page)
            ->order('id', 'desc')
            ->select();
        $order  = collection($order);
        if ($order->isEmpty()) {
            return ['code' => 1, 'msg' => '没有更多'];
        }
        $order->visible(['id', 'pid', 'title', 'total_fee', 'project.poster', 'created_at', 'status', 'is_refund', 'is_comment'])->append(['status_text'])->toArray();
        return ['code' => 0, 'msg' => 'success', 'data' => $order];
    }

    /**
     * 退款申请
     * @url /api/Order/refundSubmit
     * @param id 订单id
     * @return json
     */
    public function refundSubmit()
    {
        $id    = input('post.id/d');
        $order = OrderModel::where('id', $id)
            ->where('uid', $this->userinfo[0])
            ->where('type', config('order_type.project'))
            ->where('status', config('order_status.pay'))
            ->where('is_refund', 'in', [config('refund_status.no'), config('refund_status.no_pass')])
            ->find();
        if (!$order) return ['code' => 1, 'msg' => '订单错误'];
        $order->is_refund = config('refund_status.to_examine');
        $order->save();
        //提交退款表
        RefundModel::create([
            'order_id' => $order->id,
            'uid'      => $this->userinfo[0]
        ]);
        return ['code' => 0, 'msg' => '提交成功'];
    }

    /**
     * array转xml
     *
     * @param [type] $value
     * @return void
     */
    private function toXML($values)
    {
        if (!is_array($values) || count($values) <= 0) {
            return "<xml></xml>";
        }

        $xml = "<xml>";
        foreach ($values as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }


    /**
     * 发送模板消息
     * @url /api/Order/sendTemplate
     *
     */
    public function sendTemplate()
    {
        //查看订单是否存在
        $id    = input('order_id', 0);
        $order = OrderModel::get($id);
        if (!$order) {
            return ['code' => 1, 'msg' => '订单不存在'];
        }
        //发送消息模板
        $openId      = UserModel::get($order->uid)['openid'];
        $template_id = config('wxapp.template_id_paied');
        $page        = config('wxapp.page');
        $form_id     = $order->prepay_id;
        $param       = [
            $order->out_trade_no,
            $order->title,
            $order->total_fee,
            $order->created_at,
        ];
        $result      = WXSendMessage::send_template_notice($openId, $template_id, $page, $form_id, $param);
        if ($result->errcode != 0) {
            return ['code' => 1, 'msg' => $result->errmsg];
        }
        return ['code' => 0, 'msg' => '支付成功'];
    }


}