<?php

namespace App\Services;

use App\Util;

class BotImPayService
{
    public $config;
    public $merNo;
    public $apiUrl;
    public $privateKey;
    public $platformPublicKey;

    public function __construct($configKey = 'BotImPay')
    {
        $payConfigService = new PayConfig();
        $this->config = $payConfigService->getConfig($configKey);

        $this->merNo = $this->config['mer_no'] ?? '';
        $this->apiUrl = $this->config['apiUrl'] ?? 'https://api.botimpay.top';
        $this->privateKey = $this->config['private_key'] ?? '';
        $this->platformPublicKey = $this->config['platform_public_key'] ?? '';
    }

    /**
     * 构建待签名数据（ASCII升序、QueryString格式、跳过sign和空值）
     */
    public function buildSignData(array $params): string
    {
        $signData = [];
        foreach ($params as $key => $value) {
            if ($key === 'sign') {
                continue;
            }
            if ($value === null || $value === '' || (is_array($value) && empty($value))) {
                continue;
            }
            if (is_array($value) || is_object($value)) {
                $signData[$key] = json_encode($value, JSON_UNESCAPED_UNICODE);
            } else {
                $signData[$key] = (string)$value;
            }
        }

        ksort($signData);

        $result = '';
        foreach ($signData as $key => $value) {
            $result .= '&' . $key . '=' . $value;
        }

        return substr($result, 1);
    }

    /**
     * RSA SHA256 签名（使用商户私钥）
     */
    public function sign(array $params): array
    {
        $signData = $this->buildSignData($params);
        $prvKeyPem = $this->convertPrivateKeyToPem($this->privateKey);

        $signature = '';
        $signed = openssl_sign($signData, $signature, $prvKeyPem, OPENSSL_ALGO_SHA256);

        if (!$signed) {
            throw new \Exception('BotImPay RSA签名失败');
        }

        $params['sign'] = base64_encode($signature);

        Util::WriteLog('BotImPay_sign', "待签名字符串: " . $signData);
        Util::WriteLog('BotImPay_sign', "签名结果: " . $params['sign']);

        return $params;
    }

    /**
     * RSA SHA256 验签（使用平台公钥）
     */
    public function verifySign(array $params): bool
    {
        $receivedSign = $params['sign'] ?? '';
        if (empty($receivedSign)) {
            Util::WriteLog('BotImPay', '验签失败：sign字段为空');
            return false;
        }

        $signData = $this->buildSignData($params);
        $pubKeyPem = $this->convertPublicKeyToPem($this->platformPublicKey);

        $isVerified = openssl_verify(
            $signData,
            base64_decode($receivedSign),
            $pubKeyPem,
            OPENSSL_ALGO_SHA256
        );

        Util::WriteLog('BotImPay_verify', "验签数据: " . $signData);
        Util::WriteLog('BotImPay_verify', "验签结果: " . ($isVerified === 1 ? '通过' : '失败'));

        return $isVerified === 1;
    }

    /**
     * 转换私钥为PEM格式
     */
    private function convertPrivateKeyToPem($privateKeyString)
    {
        if (strpos($privateKeyString, '-----BEGIN PRIVATE KEY-----') !== false) {
            return $privateKeyString;
        }
        $key = trim($privateKeyString);
        if (!preg_match('/^-----BEGIN/', $key)) {
            if (base64_decode($key, true)) {
                $key = base64_decode($key);
            }
            $key = "-----BEGIN PRIVATE KEY-----\n" . chunk_split(base64_encode($key), 64, "\n") . "-----END PRIVATE KEY-----";
        }
        return $key;
    }

    /**
     * 转换公钥为PEM格式
     */
    private function convertPublicKeyToPem($publicKeyString)
    {
        if (strpos($publicKeyString, '-----BEGIN PUBLIC KEY-----') !== false) {
            return $publicKeyString;
        }
        $key = trim($publicKeyString);
        if (!preg_match('/^-----BEGIN/', $key)) {
            if (base64_decode($key, true)) {
                $key = base64_decode($key);
            }
            $key = "-----BEGIN PUBLIC KEY-----\n" . chunk_split(base64_encode($key), 64, "\n") . "-----END PUBLIC KEY-----";
        }
        return $key;
    }

    /**
     * POST JSON请求
     */
    public function curlPost($url, $payload)
    {
        $timeout = 20;
        $data = json_encode($payload, JSON_UNESCAPED_UNICODE);

        $headers = [
            'Content-Type: application/json',
        ];

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

        $result = curl_exec($ch);

        if (curl_errno($ch)) {
            $error = curl_error($ch);
            Util::WriteLog('BotImPay_error', 'CURL Error: ' . $error);
            curl_close($ch);
            return false;
        }

        curl_close($ch);
        return $result;
    }
}
