<?php



declare(strict_types=1);



namespace app\common\library\finance;

use app\common\service\DepositOrderExpireService;

/**

 * 模拟支付（无真实商户网关）：用于开发/联调充值与提现审核。

 */

final class MockPay

{

    public const CHANNEL_CODE = 'mock';



    /** 待审核（用户已在模拟页确认支付，等待后台审核） */

    public const DEPOSIT_STATUS_PENDING_REVIEW = 3;



    public static function isEnabled(): bool

    {

        $raw = getenv('FINANCE_MOCK_PAY_ENABLED');

        if (is_string($raw) && trim($raw) !== '') {

            $norm = strtolower(trim($raw));

            if (in_array($norm, ['0', 'false', 'no', 'off'], true)) {

                return false;

            }

            if (in_array($norm, ['1', 'true', 'yes', 'on'], true)) {

                return true;

            }

        }



        $cfg = config('app.finance_mock_pay_enabled', null);

        if ($cfg === true) {

            return true;

        }

        if ($cfg === false) {

            return false;

        }



        $debugRaw = getenv('APP_DEBUG');

        if (is_string($debugRaw) && trim($debugRaw) !== '') {

            return in_array(strtolower(trim($debugRaw)), ['1', 'true', 'yes', 'on'], true);

        }



        return false;

    }

    /**
     * 提现审核后是否走模拟出金（不调用 DDPay）。
     * - pay_channel=mock：始终模拟；
     * - FINANCE_MOCK_PAY_ENABLED 开启：ddpay/空 一律模拟（审核通过即成功）；
     * - 未开启 mock 且未配置 DDPay：ddpay/空 也模拟，避免误调网关。
     */
    public static function shouldSimulateWithdrawPayout(string $payChannel): bool
    {
        $ch = strtolower(trim($payChannel));
        if ($ch === self::CHANNEL_CODE) {
            return true;
        }
        if ($ch !== '' && $ch !== 'ddpay') {
            return false;
        }
        if (self::isEnabled()) {
            return true;
        }

        return !DDPayGateway::isConfigured();
    }

    /**

     * 计算链接过期时间与签名（防猜单号）

     *

     * @return array{expire_at: int, sign: string}

     */

    public static function buildDepositLinkAuth(string $orderNo, int $createTime): array

    {

        $expireAt = $createTime + DepositOrderExpireService::pendingExpireSeconds();



        return [

            'expire_at' => $expireAt,

            'sign'      => self::signDepositLink($orderNo, $expireAt),

        ];

    }



    public static function signDepositLink(string $orderNo, int $expireAt): string

    {

        $params = [

            'expire_at' => strval($expireAt),

            'order_no'  => $orderNo,

            'secret'    => self::linkSecret(),

        ];

        ksort($params);

        $pairs = [];

        foreach ($params as $key => $value) {

            $pairs[] = $key . '=' . $value;

        }



        return strtoupper(md5(implode('&', $pairs)));

    }



    public static function verifyDepositLink(string $orderNo, int $expireAt, string $sign): bool

    {

        $signNorm = strtoupper(trim($sign));

        if ($signNorm === '' || $orderNo === '' || $expireAt <= 0) {

            return false;

        }



        return hash_equals(self::signDepositLink($orderNo, $expireAt), $signNorm);

    }



    /**

     * 前端静态收银台 URL（优先于服务端内联页）

     *

     * @param string $amountDisplay 2 位小数字符串，供页面展示

     * @param string $bonusDisplay  2 位小数字符串

     */

    public static function depositPageUrl(

        string $orderNo,

        string $publicOrigin,

        int $expireAt,

        string $sign,

        string $amountDisplay = '',

        string $bonusDisplay = ''

    ): string {

        $htmlBase = self::resolveHtmlBase($publicOrigin);

        $apiBase = rtrim($publicOrigin, '/');



        $query = [

            'order_no'  => $orderNo,

            'expire_at' => strval($expireAt),

            'sign'      => $sign,

            'api_base'  => $apiBase,

        ];

        if ($amountDisplay !== '') {

            $query['amount'] = $amountDisplay;

        }

        if ($bonusDisplay !== '') {

            $query['bonus'] = $bonusDisplay;

        }



        return $htmlBase . '/mock-deposit.html?' . http_build_query($query, '', '&', PHP_QUERY_RFC3986);

    }



    /**

     * 模拟页内确认支付接口（无需 auth-token；须携带 sign + expire_at）

     */

    public static function depositConfirmUrl(string $orderNo, string $publicOrigin, int $expireAt, string $sign): string

    {

        $base = rtrim($publicOrigin, '/');

        $query = http_build_query([

            'order_no'  => $orderNo,

            'expire_at' => strval($expireAt),

            'sign'      => $sign,

        ], '', '&', PHP_QUERY_RFC3986);



        return $base . '/api/finance/mockDepositConfirm?' . $query;

    }



    /**

     * 解析前端静态页根地址：MOCK_DEPOSIT_HTML_BASE > DDPAY_PUBLIC_BASE_URL > API 公网根

     */

    public static function resolveHtmlBase(string $publicOrigin): string

    {

        $raw = getenv('MOCK_DEPOSIT_HTML_BASE');

        if (is_string($raw) && trim($raw) !== '') {

            return rtrim(trim($raw), '/');

        }



        $ddpayPublic = getenv('DDPAY_PUBLIC_BASE_URL');

        if (is_string($ddpayPublic) && trim($ddpayPublic) !== '') {

            return rtrim(trim($ddpayPublic), '/');

        }



        $cfg = config('app.ddpay_public_base_url', '');

        if (is_string($cfg) && trim($cfg) !== '') {

            return rtrim(trim($cfg), '/');

        }



        return rtrim($publicOrigin, '/');

    }



    private static function linkSecret(): string

    {

        $raw = getenv('FINANCE_MOCK_PAY_LINK_SECRET');

        if (is_string($raw) && trim($raw) !== '') {

            return trim($raw);

        }

        $auth = getenv('AUTH_TOKEN_SECRET');

        if (is_string($auth) && trim($auth) !== '') {

            return trim($auth);

        }



        return 'mock-deposit-link-dev-secret';

    }

}


