<?php

namespace app\api\service;
use think\facade\Db;
use Yansongda\Pay\Pay;
use think\facade\Log;
class PayService
{
    // 支付方式映射
    const PAY_METHOD_ALIPAY = 1;
    const PAY_METHOD_WECHAT = 2;

    // 支付状态 未支付
    const PAY_STATUS_UNPAID = 0;

    //成功
    const PAY_STATUS_SUCCESS = 1;

    //失败
    const PAY_STATUS_FAILED = 2;

    //超时
    const PAY_STATUS_TIMEOUT = 3;

    // 订单类型
    const ORDER_TYPE_COURSE = 1;
    const ORDER_TYPE_CERT = 2;

    // 订单超时时间（单位：秒）
    const ORDER_TIMEOUT = 7200;

    // 每次处理的订单数量限制
    const BATCH_LIMIT = 100;

    /**
     * 创建支付订单
     * @param int $userId 用户ID
     * @param int $orderId 关联订单ID
     * @param float $amount 支付金额
     * @param int $payMethod 支付方式
     * @param int $orderType 订单类型
     * @param array $reqInfo 请求参数
     * @return array
     */
    public static function createPayment($userId, $orderId, $amount, $payMethod, $orderType, $reqInfo = [])
    {
        try {

            if($orderType == self::ORDER_TYPE_COURSE) {
                $title = Db::name('course')->where('id', $orderId)->value('title');
            }else{
                $title = Db::name('cert')->where('id', $orderId)->value('title');
            }
            $orderNoType = match($orderType) {
                1 => 'kc',
                2 => 'zs',
                default => null,
            };
            // 生成支付订单号
            $orderNo = UtilService::generateCompactOrderNo($userId,$orderNoType);


            // 支付订单数据
            $paymentData = [
                'order_id' => $orderId,
                'pay_method' => $payMethod,
                'order_no' => $orderNo,
                'pay_status' => self::PAY_STATUS_UNPAID,
                'pay_amount' => $amount,
                'order_price' => $amount,
                'order_type' => $orderType,
                'user_id' => $userId,
                'subject' => $title,
                'req_info' => json_encode($reqInfo, JSON_UNESCAPED_UNICODE),
                'createtime' => time(),
                'updatetime' => time(),
                'expire_time' => time() + self::ORDER_TIMEOUT // 2小时过期
            ];
            // 写入数据库
            $paymentId = Db::name('payment')->insertGetId($paymentData);

            return [
                'status' => true,
                'data' => [
                    'payment_id' => $paymentId,
                    'order_no' => $orderNo
                ]
            ];
        } catch (\Exception $e) {
            Log::error('创建支付订单失败: ' . $e->getMessage());
            return [
                'status' => false,
                'msg' => '创建支付订单失败'
            ];
        }
    }

    /**
     * 生成支付订单号
     * @param int $payMethod 支付方式
     * @return string
     */
    private static function generateOrderNo($payMethod)
    {
        $prefix = $payMethod == self::PAY_METHOD_ALIPAY ? 'ALI' : 'WX';
        return $prefix . date('YmdHis') . mt_rand(1000, 9999);
    }

    /**
     * 处理支付回调
     * @param string $orderNo 支付订单号
     * @param array $notifyData 回调数据
     * @return bool
     */
    public static function handlePaymentNotify($orderNo, $notifyData)
    {

        Db::startTrans();
        try {
            // 查询支付订单
            $payment = Db::name('payment')
                ->where('order_no', $orderNo)
                ->lock(true)
                ->find();

            if (!$payment) {
                throw new \Exception("支付订单不存在: {$orderNo}");
            }

            // 已处理过的订单不再处理
            if ($payment['pay_status'] == self::PAY_STATUS_SUCCESS) {
                Db::commit();
                return true;
            }

            // 检查订单是否过期
            if (isset($payment['expire_time']) && $payment['expire_time'] > 0
                && $payment['expire_time'] < time()) {
                throw new \Exception("支付订单已过期: {$orderNo}");
            }

            // 验证金额
            $amount = $payment['pay_method'] == self::PAY_METHOD_ALIPAY ?
                $notifyData['total_amount'] : ($notifyData['amount']['total'] / 100);


            if (bccomp($amount, $payment['pay_amount'], 2) !== 0) {
                throw new \Exception("金额不一致: 订单{$payment['pay_amount']}, 回调{$amount}");
            }
            $pay_time = $payment['pay_method'] == self::PAY_METHOD_ALIPAY ?
                strtotime($notifyData['send_pay_date']) : strtotime($notifyData['gmt_payment'] ?? date('Y-m-d H:i:s'));

            $pay_no = $payment['pay_method'] == self::PAY_METHOD_ALIPAY ?
                $notifyData['trade_no'] : ($notifyData['transaction_id']);

            // 更新支付状态
            $updateData = [
                'pay_status' => self::PAY_STATUS_SUCCESS,
                'pay_time' => $pay_time,
                'pay_info' => json_encode($notifyData, JSON_UNESCAPED_UNICODE),
                'updatetime' => time(),
                'pay_no'=>$pay_no
            ];

            $result = Db::name('payment')
                ->where('order_no', $orderNo)
                ->update($updateData);

            if (!$result) {
                throw new \Exception("更新支付状态失败");
            }

            // 根据订单类型处理业务逻辑
            self::handleBusinessAfterPayment($payment);

            Db::commit();
            return true;
        } catch (\Exception $e) {
            Db::rollback();
            Log::error("支付回调处理失败: {$orderNo} - " . $e->getMessage());
            return false;
        }
    }

    /**
     * 支付成功后处理业务逻辑
     * @param array $payment 支付订单数据
     */
    private static function handleBusinessAfterPayment($payment)
    {
        try {
            if ($payment['order_type'] == self::ORDER_TYPE_COURSE) {
                // 处理课程购买逻辑
                // 例如: 更新课程订单状态, 分配课程权限等
                // Db::name('fj_course_order')->where('id', $payment['order_id'])->update(['status' => 1]);
                //增加销量

            } elseif ($payment['order_type'] == self::ORDER_TYPE_CERT) {
                // 处理证书购买逻辑
                $res = Db::name('cert_order')
                    ->where('cert_id', $payment['order_id'])
                    ->update(['status' => 1]);
            }

            // 可以添加其他业务逻辑，如发送通知等
        } catch (\Exception $e) {
            Log::error("支付后业务处理失败: " . $e->getMessage());
        }
    }

    /**
     * 获取支付配置
     * @param int $payMethod 支付方式
     * @return array
     */
    public static function getPayConfig($payMethod)
    {
        return $payMethod == self::PAY_METHOD_ALIPAY ?
            config('pay.alipay') : config('pay.wechat');
    }

    /**订单过期
     * @return array
     */
    public static function orderTimeOut()
    {
        $startTime = time();
        Log::info("开始执行支付超时订单检查任务");

        try {
            $expireTime = $startTime - self::ORDER_TIMEOUT;

            // 查询未支付且已过期的订单
            $orders = Db::name('payment')
                ->where('pay_status', '=', self::PAY_STATUS_UNPAID)
                ->where(function($query) use ($expireTime, $startTime) {
                    $query->where('expire_time', '<', $startTime)
                        ->where('expire_time', '>', 0)
                        ->whereOr('createtime', '<', $expireTime);
                })
                ->limit(self::BATCH_LIMIT)
                ->select();

            if (empty($orders)) {
                $msg = "没有需要处理的超时订单";
                Log::info($msg);
                return [
                    'status' => true,
                    'code' => 200,
                    'message' => $msg,
                    'data' => [
                        'processed_count' => 0,
                        'success_count' => 0
                    ]
                ];
            }

            $successCount = 0;

            foreach ($orders as $order) {
                Db::startTrans();
                try {
                    // 再次检查状态防止并发处理
                    $currentStatus = Db::name('payment')
                        ->where('id', $order['id'])
                        ->lock(true)
                        ->value('pay_status');

                    if ($currentStatus != self::PAY_STATUS_UNPAID) {
                        Db::commit();
                        continue;
                    }

                    // 更新为超时状态
                    $result = Db::name('payment')
                        ->where('id', $order['id'])
                        ->update([
                            'pay_status' => self::PAY_STATUS_TIMEOUT,
                            'updatetime' => time(),
                            'pay_info' => json_encode(['timeout_reason' => '系统自动取消'])
                        ]);

                    if ($result) {
                        // 处理订单取消后的业务逻辑
                        // self::handleBusinessAfterTimeout($order);
                        $successCount++;
                    }

                    Db::commit();
                } catch (\Exception $e) {
                    Db::rollback();
                    Log::error("处理超时订单失败: {$order['order_no']} - " . $e->getMessage());
                }
            }

            $msg = "支付超时订单处理完成";
            Log::info("{$msg}，共处理: " . count($orders) . "条，成功: {$successCount}条");

            return [
                'status' => true,
                'code' => 200,
                'message' => $msg,
                'data' => [
                    'total_count' => count($orders),
                    'processed_count' => count($orders),
                    'success_count' => $successCount,
                    'failed_count' => count($orders) - $successCount
                ]
            ];

        } catch (\Exception $e) {
            $errorMsg = "支付超时订单任务执行失败: " . $e->getMessage();
            Log::error($errorMsg);
            return [
                'status' => false,
                'code' => 500,
                'message' => $errorMsg,
                'data' => []
            ];
        }
    }

    /**
     * 订单超时后的业务处理
     */
    protected static function handleBusinessAfterTimeout($order)
    {
        // 根据你的业务需求实现
        // 例如：释放库存、通知用户等

        // 示例代码：
        try {
            // 1. 记录日志
            Log::info("订单超时处理: {$order['order_no']}");

            // 2. 如果是商品订单，可以释放库存
            // $this->releaseStock($order);

            // 3. 发送通知给用户
            // $this->sendTimeoutNotice($order);

        } catch (\Exception $e) {
            Log::error("订单超时后处理业务失败: {$order['order_no']} - " . $e->getMessage());
        }
    }

}