<?php

namespace App\Http\Controllers\Api;

use App\Http\logic\api\CoinPayCashierLogic;
use App\Http\logic\api\CoinPayLogic;
use App\Inter\PayMentInterFace;
use App\Notification\TelegramBot;
use App\Services\CoinPay;
use App\Util;
use App\Utility\SetNXLock;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redis;

class CoinPayController implements PayMentInterFace
{
    private $retryTimes = 0;

    public function pay_order($userId, $payAmt, $userName, $userEmail, $userPhone, $GiftsID, $buyIP, $AdId, $eventType, $pay_method = '')
    {
        $logic = new CoinPayLogic();

        try {
            $res = $logic->pay_order($userId, $payAmt, $userPhone, $userEmail, $userName, $GiftsID, $buyIP, $AdId, $eventType, $pay_method);
        } catch (\Throwable $exception) {
            Redis::set('PayErro_CoinPay', 1, 'EX', 600);
            Util::WriteLog('CoinPay_error', $exception->getMessage());
            TelegramBot::getDefault()->sendProgramNotify('CoinPay pay error', $exception->getMessage(), $exception);
            return apiReturnFail($logic->getError());
        }

        if (isset($res['code']) && (int)$res['code'] === 0) {
            $data = [
                'content' => $res['data']['url'] ?? '',
                'money' => $payAmt,
                'prdOrdNo' => $res['data']['orderNo'] ?? '',
            ];
            return apiReturnSuc($data);
        }

        if ($res === false) {
            return apiReturnFail($logic->getError());
        }

        if ($this->retryTimes > 0) {
            Redis::set('PayErro_CoinPay', 1, 'EX', 600);
            return apiReturnFail($logic->getError());
        }

        $this->retryTimes++;
        return $this->pay_order($userId, $payAmt, $userName, $userEmail, $userPhone, $GiftsID, $buyIP, $AdId, $eventType, $pay_method);
    }

    public function notify(Request $request)
    {
        $post = $request->all();
        Util::WriteLog('CoinPay', 'pay notify: ' . json_encode($post, JSON_UNESCAPED_UNICODE));

        $service = new CoinPay();
        if (!$service->verify($post)) {
            Util::WriteLog('CoinPay', 'pay notify verify failed');
            return 'fail';
        }

        $order_sn = $post['merchantOrderNo'] ?? '';
        if (empty($order_sn)) {
            Util::WriteLog('CoinPay', '缺少订单号');
            return 'fail';
        }

        // 代收回调加锁，防止并发重复处理
        $lockKey = 'pay_notify_CoinPay_' . $order_sn;
        if (!SetNXLock::getExclusiveLock($lockKey, 60)) {
            Util::WriteLog('CoinPay', '代收回调并发，订单已处理或处理中: ' . $order_sn);
            return 'SUCCESS';
        }

        $logic = new CoinPayLogic();
        try {
            return $logic->notify($post);
        } catch (\Throwable $exception) {
            Redis::set('PayErro_CoinPay', 1, 'EX', 600);
            return '{"success":false,"message":"internal error"}';
        } finally {
            SetNXLock::release($lockKey);
        }
    }

    public function sync_notify(Request $request)
    {
        Util::WriteLog('CoinPay', 'sync callback: ' . json_encode($request->all(), JSON_UNESCAPED_UNICODE));
        return 'success';
    }

    public function cash_notify(Request $request)
    {
        $post = $request->all();
        Util::WriteLog('CoinPay', 'cash notify: ' . json_encode($post, JSON_UNESCAPED_UNICODE));

        $service = new CoinPay('CoinPayOut');
        if (!$service->verify($post)) {
            Util::WriteLog('CoinPay', 'cash notify verify failed');
            return 'fail';
        }

        $logic = new CoinPayCashierLogic();
        try {
            return $logic->notify($post);
        } catch (\Throwable $exception) {
            return '{"success":false,"message":"internal error"}';
        }
    }
}

