<?php
/**
 * VoltPay PHP client — drop this file on any PHP site.
 * Keep the secret on the server. Never send it to the browser.
 *
 * $vp = new VoltPay('https://netmoov.com', 'sk_live_…');
 * $order = $vp->createOrder(['amount' => '10.00', 'merchant_order_id' => 'SKU-1']);
 * header('Location: ' . $order['payment_url']); // same Pay → I PAID → UTR UI
 * // or iframe $order['embed_url']
 * $paid = $vp->status($order['order_id']); // PENDING | SUCCESS | FAILED
 */

declare(strict_types=1);

class VoltPay
{
    public function __construct(
        private string $base,
        private string $secret,
        private int $timeout = 20
    ) {
        $this->base = rtrim($base, '/');
        if (!preg_match('#^https://#i', $this->base)) {
            throw new InvalidArgumentException('VoltPay base URL must be https://');
        }
        if (!str_starts_with($this->secret, 'sk_live_') && !str_starts_with($this->secret, 'sk_test_')) {
            throw new InvalidArgumentException('API secret is missing or invalid.');
        }
    }

    public function createOrder(array $payload, ?string $idempotencyKey = null): array
    {
        $headers = [];
        $key = $idempotencyKey ?: (string) ($payload['merchant_order_id'] ?? $payload['idempotency_key'] ?? '');
        if ($key !== '') {
            $headers[] = 'Idempotency-Key: ' . $key;
        }
        return $this->request('POST', '/api/v1/orders', $payload, $headers);
    }

    public function status(string $orderId): array
    {
        return $this->request('GET', '/api/v1/orders/' . rawurlencode($orderId));
    }

    public function verify(string $orderId, string $upiRef): array
    {
        return $this->request('POST', '/api/v1/payments/verify', [
            'order_id' => $orderId,
            'upi_ref'  => preg_replace('/\D+/', '', $upiRef),
        ]);
    }

    public function cancel(string $orderId): array
    {
        return $this->request('POST', '/api/v1/orders/' . rawurlencode($orderId) . '/cancel');
    }

    public function ping(): array
    {
        return $this->request('GET', '/api/v1/me');
    }

    /**
     * Validate an incoming VoltPay webhook.
     * Header: X-VoltPay-Signature: t=UNIX,v1=HEX
     */
    public static function validWebhook(string $rawBody, string $signatureHeader, string $webhookSecret, int $maxAge = 300): bool
    {
        if ($webhookSecret === '' || $signatureHeader === '') {
            return false;
        }
        $t = '';
        $v1 = '';
        foreach (explode(',', $signatureHeader) as $part) {
            [$k, $val] = array_pad(explode('=', trim($part), 2), 2, '');
            if ($k === 't') {
                $t = $val;
            }
            if ($k === 'v1') {
                $v1 = $val;
            }
        }
        if ($t === '' || $v1 === '' || !ctype_digit($t)) {
            return false;
        }
        if (abs(time() - (int) $t) > $maxAge) {
            return false;
        }
        $expect = hash_hmac('sha256', $t . '.' . $rawBody, $webhookSecret);
        return hash_equals($expect, $v1);
    }

    private function request(string $method, string $path, ?array $body = null, array $headers = []): array
    {
        $url = $this->base . $path;
        $hdr = array_merge([
            'Accept: application/json',
            'Content-Type: application/json',
            'Authorization: Bearer ' . $this->secret,
            'User-Agent: VoltPay-PHP/1.0',
        ], $headers);
        $ch = curl_init($url);
        $opts = [
            CURLOPT_CUSTOMREQUEST  => $method,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => $this->timeout,
            CURLOPT_CONNECTTIMEOUT => 8,
            CURLOPT_HTTPHEADER     => $hdr,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2,
        ];
        if ($body !== null) {
            $opts[CURLOPT_POSTFIELDS] = json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        }
        curl_setopt_array($ch, $opts);
        $raw = curl_exec($ch);
        $err = curl_error($ch);
        $code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        if ($raw === false) {
            throw new RuntimeException('VoltPay request failed: ' . $err);
        }
        $json = json_decode((string) $raw, true);
        if (!is_array($json)) {
            throw new RuntimeException('VoltPay returned a non-JSON response (HTTP ' . $code . ').');
        }
        if ($code >= 400 || empty($json['ok'])) {
            $msg = (string) ($json['message'] ?? $json['error'] ?? 'HTTP ' . $code);
            throw new RuntimeException($msg, $code);
        }
        return is_array($json['data'] ?? null) ? $json['data'] : $json;
    }
}
