<?php
namespace Core\Payment;

/**
 * 微信支付网关（NATIVE 扫码支付）
 * - demo：返回模拟支付入口
 * - live：调用统一下单接口获取 code_url，前端展示二维码
 */
class WechatGateway extends Gateway
{
    public function pay(array $order): array
    {
        $simulate = site_url('order/demo/' . $order['order_no']);
        $hasCred = !empty($this->config['mchid']) && !empty($this->config['appid']) && !empty($this->config['key']);

        if ($this->isDemo() || !$hasCred) {
            return [
                'mode'           => 'demo',
                'channel'        => 'wechat',
                'simulate'       => $simulate,
                'config_missing' => !$hasCred,
            ];
        }

        $params = [
            'appid'            => $this->config['appid'],
            'mch_id'           => $this->config['mchid'],
            'nonce_str'        => bin2hex(random_bytes(16)),
            'body'             => $order['product_name'] ?: '商品购买',
            'out_trade_no'     => $order['order_no'],
            'total_fee'        => (int) round((float) $order['amount'] * 100), // 分
            'spbill_create_ip' => $_SERVER['SERVER_ADDR'] ?? '127.0.0.1',
            'notify_url'       => site_url('pay/notify/wechat'),
            'trade_type'       => 'NATIVE',
        ];
        $params['sign'] = $this->sign($params);
        $xml = $this->toXml($params);

        $resp = @file_get_contents('https://api.mch.weixin.qq.com/pay/unifiedorder', false, stream_context_create([
            'http' => ['method' => 'POST', 'header' => 'Content-Type: text/xml', 'content' => $xml, 'timeout' => 8],
        ]));
        $res = $resp ? $this->fromXml($resp) : [];

        if (!empty($res['code_url'])) {
            return ['mode' => 'qrcode', 'channel' => 'wechat', 'qr' => $res['code_url']];
        }
        // 调用失败则回退演示，避免卡死
        return ['mode' => 'demo', 'channel' => 'wechat', 'simulate' => $simulate, 'config_missing' => false, 'api_error' => true];
    }

    /** HMAC-SHA256 签名 */
    private function sign(array $params): string
    {
        ksort($params);
        $str = '';
        foreach ($params as $k => $v) {
            if ($v === '' || $v === null) continue;
            $str .= $k . '=' . $v . '&';
        }
        $str .= 'key=' . ($this->config['key'] ?? '');
        return strtoupper(hash_hmac('sha256', $str, $this->config['key'] ?? ''));
    }

    private function toXml(array $params): string
    {
        $xml = '<xml>';
        foreach ($params as $k => $v) {
            $xml .= "<{$k}>" . htmlspecialchars($v, ENT_XML1) . "</{$k}>";
        }
        $xml .= '</xml>';
        return $xml;
    }

    private function fromXml(string $xml): array
    {
        $r = @simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
        return $r ? json_decode(json_encode($r), true) : [];
    }

    public function verifyNotify(array $data): ?string
    {
        if (empty($data['out_trade_no'])) return null;
        if (($data['result_code'] ?? '') === 'SUCCESS' && ($data['return_code'] ?? '') === 'SUCCESS') {
            // 生产环境应重新按 key 验签后返回
            return $data['out_trade_no'];
        }
        return null;
    }
}
