<?php

namespace App\Http\Controllers;

use App\Exceptions\AlertException;
use App\Jobs\GrowingIO\ActivateSvipReportJob;
use App\Jobs\OrderCloseJob;
use App\Services\Pay\CouponService;
use App\Services\Pay\OrderService;
use App\Services\User\VipService;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Core\Auth;
use App\Http\Controllers\Fpdx\PairController;
use App\Http\Controllers\Miniprogram\Auth as MiniAuth;
use App\Models\OrderModel;
use Illuminate\Http\Request;
use Ixudra\Curl\Facades\Curl;

/**
 * 订单及微信支付
 * Class Order
 * @package App\Http\Controllers
 */
class Order extends Controller
{
    private $orderModel;

    public function __construct()
    {
        $this->orderModel = new OrderModel();
    }

    // 商品信息
    public const GOODS = [
        1 => [
            'goods_id' => 1,
            'desc' => '金fa充值',
            'total_fee' => 100,
            'gold_flower' => 1,
            'red_flower' => 0,
            'body' => '卖室友充值',
            'notify_url' => "/api/core/pay/notify"
        ],
        2 => [
            'goods_id' => 2,
            'desc' => '卖室友表白',
            'total_fee' => 100,
            'gold_flower' => 0,
            'red_flower' => 0,
            'body' => '卖室友表白',
            'notify_url' => "/api/core/pay/notify"
        ],
        3 => [
            'goods_id' => 3,
            'desc' => '72小时恋爱体验入场券',
            'total_fee' => 990,
            'gold_flower' => 0,
            'red_flower' => 0,
            'body' => '72小时入场券',
            'notify_url' => "/api/core/pay/notify"
        ],
        9 => [
            'goods_id' => 9,
            'desc' => '购买小fa充值',
            'total_fee' => 900,
            'gold_flower' => 10,
            'red_flower' => 0,
            'body' => '卖室友充值',
            'notify_url' => "/api/core/pay/notify"
        ],
        10 => [
            'goods_id' => 10,
            'desc' => '购买小fa充值',
            'total_fee' => 8800,
            'gold_flower' => 100,
            'red_flower' => 0,
            'body' => '卖室友充值',
            'notify_url' => "/api/core/pay/notify"
        ],
        12 => [
            'goods_id' => 12,
            'desc' => "「1个月」超级会员充值",
            'total_fee' => 2990,
            'gold_flower' => 0,
            'red_flower' => 0,
            'body' => '分配对象「1个月」超级会员充值',
            'notify_url' => "/api/pay/notify/supervip"
        ],
        13 => [
            'goods_id' => 13,
            'desc' => "「3个月」超级会员充值",
            'total_fee' => 7200,
            'gold_flower' => 0,
            'red_flower' => 0,
            'body' => '分配对象「3个月」超级会员充值',
            'notify_url' => "/api/pay/notify/supervip"
        ],
        14 => [
            'goods_id' => 14,
            'desc' => "「12个月」超级会员充值",
            'total_fee' => 25200,
            'gold_flower' => 0,
            'red_flower' => 0,
            'body' => '分配对象「12个月」超级会员充值',
            'notify_url' => "/api/pay/notify/supervip"
        ],
    ];

    /**
     * 超级会员充值
     * @param  Request  $request
     * @param  int  $goods_type
     * @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
     * @throws AlertException
     * @throws \App\Exceptions\ApiException
     */
    public function unifyBySuperVip(Request $request, int $goods_type)
    {
        $uid = Auth::auth();
        if (!in_array($goods_type, [1, 3, 9, 10, 12, 13, 14])) {
            throw new AlertException("商品类型不存在", 404001);
        }

        $agent = $request->header('user-agent');
        $os = 'other';
        if (
            strpos($agent, 'macintosh')
            || strpos($agent, 'iPod')
            || strpos($agent, 'iPhone')
            || strpos($agent, 'iPad')
        ) {
            $os = "ios";
        }
        if (strpos($agent, 'Android')) {
            $os = 'android';
        }

        $goods = self::GOODS[$goods_type];
        $total_fee = $goods['total_fee'];
        $coupon_id = $request->input('coupon_id', 0);
        if ($coupon_id) {
            $couponService = new CouponService();
            $total_fee = $couponService->setUid($uid)
                ->setCouponId($coupon_id)
                ->setGoodsId($goods['goods_id'])
                ->use();
        }

        $params = [
            'uid' => $uid,
            'body' => $goods['body'],
            'total_fee' => $total_fee,
            'notify_url' => config('api.msy_url') . $goods['notify_url']
        ];
        $url = config('api.pay_url') . "/payments/unify";
        $result = Curl::to($url)->withContentType("application/x-www-form-urlencoded")->withData($params)->asJsonResponse()->post();
        if (isset($result->code) && $result->code == 200) {
            $fill = [
                'flower' => $goods['gold_flower'],
                'out_trade_no' => $result->data->order_id,
                'total_amount' => $goods['total_fee'],
                'total_fee' => $total_fee,
                'uid' => $uid,
                'type' => $goods['goods_id'],
                'coupon_id' => $coupon_id,
                'device' => $os,
                'create_at' => time(),
            ];
            $media_id = $request->get('media_id', null);
            if (!is_null($media_id)) {
                $fill['attach_data'] = json_encode(['media_id' => $media_id]);
            }
            $order = $this->orderModel->fill($fill);
            if ($order->save()) {
                OrderCloseJob::dispatch($order->id)->onQueue('{order:close}')->delay(now()->addMinute(5));
                return response([
                    'code' => 200,
                    'message' => 'OK',
                    'data' => [
                        'order_id' => $order->id
                    ],
                ]);
            } else {
                throw new AlertException("系统异常", 505);
            }
        } else {
            throw new AlertException("系统异常", 505);
        }
    }

    /**
     * 用户充值任意小fa下单
     * @param  Request  $request
     * @param  float  $gold_flower
     * @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
     */
    public function unifyByFlower(Request $request, $gold_flower = 1.00)
    {
        $uid = Auth::auth();
        // 支付设备
        $agent = $request->header('user-agent');
        $os = 'other';
        if (
            strpos($agent, 'macintosh')
            || strpos($agent, 'iPod')
            || strpos($agent, 'iPhone')
            || strpos($agent, 'iPad')
        ) {
            $os = "ios";
        }
        if (strpos($agent, 'Android')) {
            $os = 'android';
        }

        $goods = self::GOODS[1];
        $params = [
            'uid' => $uid,
            'body' => $goods['body'],
            'total_fee' => $gold_flower * 100,
            'notify_url' => config('api.msy_url') . "/api/core/pay/notify"
        ];
        $url = config('api.pay_url') . "/payments/unify";
        $result = \Curl::to($url)->withContentType("application/x-www-form-urlencoded")->withData($params)->asJsonResponse()->post();
        if (isset($result->code) && $result->code == 200) {
            $order = $this->orderModel->fill([
                'flower' => $gold_flower,
                'out_trade_no' => $result->data->order_id,
                'total_amount' => $gold_flower * 100,
                'total_fee' => $gold_flower * 100,
                'uid' => $uid,
                'type' => $goods['goods_id'],
                'device' => $os,
                'create_at' => time(),
            ]);
            if ($order->save()) {
                return response([
                    'code' => 200,
                    'message' => 'OK',
                    'data' => [
                        'order_id' => $order->id
                    ],
                ]);
            } else {
                return response([
                    'code' => 505,
                    'message' => '数据库异常'
                ]);
            }
        } else {
            return response([
                'code' => $result->code ?? 505,
                'message' => $result->message ?? "系统异常"
            ]);
        }
    }

    /**
     * 分配对象下单
     * @param  int  $total_fee  费用
     * @param  array  $attach  附加数据包
     * @param  Request  $request
     * @return int
     * @throws AlertException
     */
    public function unifyByFpdx(int $total_fee, array $attach, Request $request)
    {
        $uid = Auth::auth();
        // 支付设备
        $agent = $request->header('user-agent');
        $os = 'other';
        if (
            strpos($agent, 'macintosh')
            || strpos($agent, 'iPod')
            || strpos($agent, 'iPhone')
            || strpos($agent, 'iPad')
        ) {
            $os = "ios";
        }
        if (strpos($agent, 'Android')) {
            $os = 'android';
        }

        $goods = self::GOODS[3];
        // 使用优惠券
        $coupon_id = $request->input('coupon_id', 0);
        if ($coupon_id) {
            $couponService = new CouponService();
            $total_fee = $couponService->setUid($uid)
                ->setCouponId($coupon_id)
                ->setGoodsId($goods['goods_id'])
                ->use();
        }
        $params = [
            'uid' => $uid,
            'body' => "72小时恋爱体验报名",
            'total_fee' => $total_fee,
            'notify_url' => config('api.msy_url') . "/api/core/pay/notify/fpdx",
            'attach' => json_encode($attach)
        ];
        $url = config('api.pay_url') . "/payments/unify";
        $result = \Curl::to($url)->withData($params)->asJsonResponse()->post();
        if (isset($result->code) && $result->code == 200) {
            $order = $this->orderModel->fill([
                'out_trade_no' => $result->data->order_id,
                'total_amount' => $goods['total_fee'],
                'total_fee' => $total_fee,
                'uid' => $uid,
                'type' => $goods['goods_id'],
                'type_id' => $attach['stage_id'] ?? 0,
                'coupon_id' => $coupon_id,
                'attach_data' => json_encode($attach),
                'device' => $os,
                'create_at' => time(),
            ]);
            if ($order->save()) {
                OrderCloseJob::dispatch($order->id)->onQueue('{order:close}')->delay(now()->addMinute(5));
                if ($total_fee == 0) {
                    $params = [
                        'out_trade_no' => $result->data->order_id,
                    ];
                    $url = config('api.pay_url') . "/payments/notify/koudai";
                    \Curl::to($url)->withContentType("application/x-www-form-urlencoded")->withData($params)->post();
                    return 0;
                }
                return $order->id;
            } else {
                throw new AlertException("数据库异常", 505);
            }
        } else {
            throw new AlertException(isset($result->message) ? $result->message : "发起支付失败", $result->code ?? 505);
        }
    }

    /**
     * 表白下单
     * @param  int  $total_fee  表白费用
     * @param  int  $confess_id  表白记录id
     * @param  Request  $request
     * @return mixed
     * @throws AlertException
     */
    public function unifyByConfess(int $total_fee, int $confess_id, Request $request)
    {
        $uid = Auth::auth();
        // 支付设备
        $agent = $request->header('user-agent');
        $os = 'other';
        if (
            strpos($agent, 'macintosh')
            || strpos($agent, 'iPod')
            || strpos($agent, 'iPhone')
            || strpos($agent, 'iPad')
        ) {
            $os = "ios";
        }
        if (strpos($agent, 'Android')) {
            $os = 'android';
        }

        $goods = self::GOODS[2];
        $params = [
            'uid' => $uid,
            'body' => '卖室友表白',
            'total_fee' => $total_fee,
            'notify_url' => config('api.msy_url') . "/api/core/pay/notify/confess"
        ];
        $pay_url = config('api.pay_url') . "/payments/unify";
        $result = \Curl::to($pay_url)->withContentType("application/x-www-form-urlencoded")->withData($params)->asJsonResponse()->post();
        if (isset($result->code) && $result->code == 200) {
            $order = $this->orderModel->fill([
                'out_trade_no' => $result->data->order_id,
                'total_amount' => $total_fee,
                'total_fee' => $total_fee,
                'uid' => $uid,
                'type' => $goods['goods_id'],
                'type_id' => $confess_id,
                'device' => $os,
                'create_at' => time(),
            ]);
            if ($order->save()) {
                OrderCloseJob::dispatch($order->id)->onQueue('{order:close}')->delay(now()->addMinute(5));
                return $order->id;
            } else {
                throw new AlertException("数据库异常", 505);
            }
        } else {
            throw new AlertException($result->message ?? "系统异常", $result->code ?? 505);
        }
    }

    /**
     * 小程序支付jssdk
     * @param  int  $order_id
     * @return array
     * @throws \Tymon\JWTAuth\Exceptions\JWTException
     */
    public function miniProgram(int $order_id)
    {
        $uid = MiniAuth::auth();
        $order = $this->orderModel->find($order_id);
        if (collect($order)->isEmpty()) {
            return response([
                'code' => 404,
                'message' => '订单号错误或者不存在'
            ]);
        }
        if ($order->trade_state != 0) {
            return response([
                'code' => 102,
                'message' => '订单失效' . json_encode($order->toArray())
            ]);
        }
        if ($uid != $order->uid) {
            return response([
                'code' => 403,
                'message' => '用户标识不一致'
            ]);
        }
        $public_id = config('miniprogram.public_id');
        $pay_url = config('api.pay_url') . "/payments/miniProgram/{$order->out_trade_no}";
        $result = \Curl::to($pay_url)->withHeader("app:{$public_id}")->asJsonResponse()->get();
        if (isset($result->code) && $result->code == 200) {
            return response([
                'code' => 200,
                'message' => 'Success',
                'data' => $result->data,
            ]);
        } else {
            return response([
                'code' => $result->code ?? 505,
                'message' => $result->message ?? "系统异常",
                'data' => $result
            ]);
        }
    }

    /**
     * 公众号支付jssdk
     * @param  int  $order_id
     * @return array
     */
    public function jssdk(int $order_id)
    {
        $uid = Auth::auth();
        $order = $this->orderModel->find($order_id);
        if (collect($order)->isEmpty()) {
            return response([
                'code' => 404,
                'message' => '订单号错误或不存在'
            ]);
        }
        if ($order->trade_state != 0) {
            return response([
                'code' => 102,
                'message' => '订单失效'
            ]);
        }
        if ($uid != $order->uid) {
            return response([
                'code' => 403,
                'message' => '用户标识不一致'
            ]);
        }
        $url = config('api.pay_url') . "/payments/jssdk/{$order->out_trade_no}";
        $result = \Curl::to($url)->asJsonResponse()->get();
        if (isset($result->code) && $result->code == 200) {
            return response([
                'code' => 200,
                'message' => 'Success',
                'data' => $result->data,
            ]);
        } else {
            return response([
                'code' => $result->code ?? 505,
                'message' => $result->message ?? "系统异常"
            ]);
        }
    }

    /**
     * app支付jssdk
     * @param  int  $order_id
     * @return array
     */
    public function app(int $order_id)
    {
        $uid = Auth::auth();
        $order = $this->orderModel->find($order_id);
        if (collect($order)->isEmpty()) {
            return response([
                'code' => 404,
                'message' => '订单号错误或者不存在'
            ]);
        }
        if ($order->trade_state != 0) {
            return response([
                'code' => 102,
                'message' => '订单失效' . json_encode($order->toArray())
            ]);
        }
        if ($uid != $order->uid) {
            return response([
                'code' => 403,
                'message' => '用户标识不一致'
            ]);
        }
        $pay_url = config('api.pay_url') . "/payments/app/{$order->out_trade_no}";
        $result = \Curl::to($pay_url)->asJsonResponse()->get();
        if (isset($result->code) && $result->code == 200) {
            return response([
                'code' => 200,
                'message' => 'Success',
                'data' => $result->data,
            ]);
        } else {
            return response([
                'code' => $result->code ?? 505,
                'message' => $result->message ?? "系统异常",
                'data' => $result
            ]);
        }
    }

    /**
     * 订单退款
     * @param  int  $order_id
     * @param  int  $refund_fee  退款金额:分
     * @param  string  $refund_desc
     * @param  bool  $all
     * @return array|bool
     * @throws AlertException
     */
    public function refund(int $order_id, int $refund_fee, $refund_desc = "", $all = false)
    {
        $order = $this->orderModel->find($order_id);
        if (collect($order)->isEmpty()) {
            throw new AlertException('订单错误或不存在', 101);
        }
        if (0 == $order->order_state) {
            throw new AlertException('订单未支付不可退款', 102);
        }
        if ($all && $order->create_at < 1533114000) {
            throw new AlertException("过期订单,请联系小向导微信:fpdxkf", 103);
            $pay_url = config('api.pay_url') . '/payments/transfer';
            $data = [
                'uid' => $order->uid,
                'amount' => $refund_fee,
                'app_order_id' => "fpdx_refund_" . uniqid(),
                'desc' => $refund_desc
            ];
        } else {
            $pay_url = config('api.pay_url') . "/payments/order/{$order->out_trade_no}/refund";
            $data = [
                'refund_fee' => $refund_fee,
                'refund_desc' => $refund_desc
            ];
        }
        $result = \Curl::to($pay_url)->withContentType("application/x-www-form-urlencoded")->asJsonResponse()->withData($data)->post();
        if (isset($result->code) && $result->code == 200) {
            // 使用优惠券逻辑
            if ($order->coupon_id) {
                $couponService = new CouponService();
                $couponService->setUid($order->uid)
                    ->setCouponId($order->coupon_id)
                    ->unUse();
            }
            return true;
        } else {
            throw new AlertException("退款失败", 500);
        }
    }

    /**
     * 支付结果核销处理
     * @param  Request  $request
     * @param  array  $callback
     * @return string
     */
    private function handlePaidNotify(Request $request, array $callback)
    {
        $orderModel = new OrderModel();
        /** @var OrderModel|null $order */
        $order = $orderModel->where('out_trade_no', $request->input('order_id'))->first();
        if (!$order) {
            return "fail";
        }
        if ($order->order_state != 0) {
            return "success";
        } else {
            $order->cash_fee = $request->input('cash_fee', 0);
            if ($request->input('trade_state') == 'SUCCESS') {
                $order->order_state = 1;
            }
            if ($order->save()) {
                dispatch_now(new ActivateSvipReportJob($order));
                call_user_func($callback, $order);
                return "success";
            } else {
                return "fail";
            }
        }
    }

    /**
     * 普通支付成功业务处理
     * @param  OrderModel  $order
     * @return bool
     * @throws \Exception
     */
    protected function payment(OrderModel $order)
    {
        DB::beginTransaction();
        try {
            // 增加花
            DB::table('kdgx_partner_charge_user')->where('uid', $order->uid)->increment(
                'red_flower',
                self::GOODS[$order->type]['red_flower']
            );
            DB::table('kdgx_partner_charge_user')->where('uid', $order->uid)->increment('gold_flower', $order->flower);
            // 日志
            DB::table('kdgx_partner_charge_pay_logs')->insert([
                'uid' => $order->uid,
                'create_at' => time(),
                'type' => 3,
                'gold_flower' => $order->flower,
                'red_flower' => self::GOODS[$order->type]['red_flower'],
                'type_id' => $order->total_fee,
                'remark' => "微信充值 {$order->total_fee}"
            ]);
            DB::commit();
            return true;
        } catch (\Exception $e) {
            DB::rollBack();
            return false;
        }
    }

    /**
     * 普通支付结果通知
     * @param  Request  $request
     * @return string
     * @throws \Exception
     */
    public function notify(Request $request)
    {
        return $this->handlePaidNotify($request, [$this, 'payment']);
    }

    // 超级VIP支付结果通知
    public function notifyBySuperVip(Request $request)
    {
        $vs = new VipService();
        return $this->handlePaidNotify($request, [$vs, 'payment']);
    }

    /**
     * 表白支付结果通知
     * @param  Request  $request
     * @return string
     */
    public function notifyByconfess(Request $request)
    {
        $confess = new Confess();
        return $this->handlePaidNotify($request, [$confess, 'payment']);
    }

    /**
     * 分配对象报名支付结果通知
     * @param  Request  $request
     * @return string
     */
    public function notifyByfpdx(Request $request)
    {
        $pairObj = new PairController();
        return $this->handlePaidNotify($request, [$pairObj, 'payment']);
    }


    /**
     * 后台退款接口
     * @param  int  $order_id
     * @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
     * @throws AlertException
     * @throws \App\Exceptions\ApiException
     */
    public function requestRefund(int $order_id)
    {
        $order = $this->orderModel->find($order_id);
        $orderService = new OrderService();
        $result = $orderService->refund($order_id, $order->cash_fee, '测试退款');
        return response([
            'code' => 200,
            'message' => 'OK',
            'data' => $result
        ]);
    }


    /**
     * 订单关闭
     * @param $id
     * @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
     * @throws \App\Exceptions\ApiException
     */
    public function closeOrder($id)
    {
        $orderService = new OrderService();
        $orderService->closeOrder($id);
        return response([
            'code' => 200,
            'message' => 'OK'
        ]);
    }
}
