<?php

namespace App\Services;

use App\Util;

class WDPay
{
    public $config;
    public $key;
    public $customerNo;
    public $apiUrl;

    public function __construct()
    {
        $payConfigService = new PayConfig();
        $this->config = $payConfigService->getConfig('WDPay');
        
        $this->key = $this->config['key'] ?? '';
        $this->customerNo = $this->config['customerNo'] ?? '';
        // WDPay官方接口：/charging/create-pay-in
        $this->apiUrl = $this->config['apiUrl'] ?? '';
    }

    /**
     * 签名 - WDPay专用签名算法
     * 
     * 规则：
     * 1. 按参数名ASCII码从小到大排序（字典序）
     * 2. 空值不参与签名
     * 3. sign参数不参与签名
     * 4. 拼接格式：key1=value1&key2=value2&key=商户密钥
     * 5. MD5后转大写
     */
    public function sign(array $params): array
    {
        // 移除sign和空值
        $signParams = [];
        foreach ($params as $key => $value) {
            if ($key !== 'sign' && $value !== null && $value !== '') {
                // 如果是对象或数组，需要递归处理
                if (is_array($value) || is_object($value)) {
                    $signParams[$key] = $this->buildObjectString($value);
                } else {
                    $signParams[$key] = $value;
                }
            }
        }
        
        // 按ASCII码排序
        ksort($signParams);
        
        // 拼接字符串：key1=value1&key2=value2
        $stringA = urldecode(http_build_query($signParams));
        
        // 拼接商户密钥：stringA&key=商户密钥
        $stringSignTemp = $stringA . '&key=' . $this->key;
        
        // MD5并转大写
        $sign = strtoupper(md5($stringSignTemp));
        
        // 将签名添加到参数中
        $params['sign'] = $sign;
        
        Util::WriteLog('WDPay_sign', "待签名字符串: " . $stringSignTemp);
        Util::WriteLog('WDPay_sign', "签名结果: " . $sign);
        
        return $params;
    }

    /**
     * 验签 - WDPay专用验签算法
     */
    public function verifySign(array $params): bool
    {
        if (!isset($params['sign'])) {
            return false;
        }
        
        $receivedSign = $params['sign'];
        
        // 移除sign和空值
        $signParams = [];
        foreach ($params as $key => $value) {
            if ($key !== 'sign' && $value !== null && $value !== '') {
                if (is_array($value) || is_object($value)) {
                    $signParams[$key] = $this->buildObjectString($value);
                } else {
                    $signParams[$key] = $value;
                }
            }
        }
        
        // 按ASCII码排序
        ksort($signParams);
        
        // 拼接字符串
        $stringA = urldecode(http_build_query($signParams));
        
        // 拼接商户密钥
        $stringSignTemp = $stringA . '&key=' . $this->key;
        
        // MD5并转大写
        $calculatedSign = strtoupper(md5($stringSignTemp));
        
        Util::WriteLog('WDPay_verify', "待验签字符串: " . $stringSignTemp);
        Util::WriteLog('WDPay_verify', "计算签名: " . $calculatedSign);
        Util::WriteLog('WDPay_verify', "接收签名: " . $receivedSign);
        
        return $calculatedSign === $receivedSign;
    }
    
    /**
     * 递归处理对象/数组为字符串
     */
    private function buildObjectString($data): string
    {
        if (is_array($data)) {
            $parts = [];
            ksort($data);
            foreach ($data as $k => $v) {
                if ($v !== null && $v !== '') {
                    if (is_array($v) || is_object($v)) {
                        $parts[] = $k . '=' . $this->buildObjectString($v);
                    } else {
                        $parts[] = $k . '=' . $v;
                    }
                }
            }
            return implode('&', $parts);
        }
        return (string)$data;
    }

    /**
     * 生成随机字符串
     */
    public function getNonceStr($length = 16): string
    {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    /**
     * POST请求 - application/x-www-form-urlencoded
     */
    public function curlPost($url, $payload)
    {
        $timeout = 20;
        
        // WDPay使用 application/x-www-form-urlencoded 格式
        $data = http_build_query($payload);
        
        $requestUa = request()->userAgent() ?: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';
        $headers = [
            'Content-Type: application/x-www-form-urlencoded; charset=UTF-8',
            'User-Agent: ' . $requestUa,
        ];

        $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);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

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

        if ($httpCode != 200) {
            Util::WriteLog('WDPay_error', 'HTTP Code: ' . $httpCode . " | Response: " . $result);
        }

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