<?php

namespace App\Libraries\PaymentGateways;

/**
 * JazzCash uses an HMAC-SHA256 "integrity salt" signed POST-redirect flow
 * rather than a REST API — the merchant builds a signed form, the customer
 * is redirected to JazzCash's page, and JazzCash POSTs back a signed
 * response. There is no server-to-server "charge" call; charge() here
 * builds the redirect payload instead of making an HTTP request.
 */
class JazzCashGateway implements PaymentGatewayInterface
{
    private string $merchantId;
    private string $password;
    private string $integritySalt;
    private string $postUrl = 'https://sandbox.jazzcash.com.pk/CustomerPortal/transactionmanagement/merchantform/';

    public function __construct()
    {
        $this->merchantId    = env('jazzcash.merchantId');
        $this->password      = env('jazzcash.password');
        $this->integritySalt = env('jazzcash.integritySalt');
    }

    public function charge(float $amount, string $currency, array $metadata = []): array
    {
        $txnRefNo = 'T' . date('YmdHis') . bin2hex(random_bytes(3));
        $amountInPaisa = (int) round($amount * 100); // JazzCash expects amount in paisa

        $params = [
            'pp_Version'          => '1.1',
            'pp_TxnType'          => 'MWALLET',
            'pp_Language'         => 'EN',
            'pp_MerchantID'       => $this->merchantId,
            'pp_Password'         => $this->password,
            'pp_TxnRefNo'         => $txnRefNo,
            'pp_Amount'           => (string) $amountInPaisa,
            'pp_TxnCurrency'      => 'PKR',
            'pp_TxnDateTime'      => date('YmdHis'),
            'pp_BillReference'    => $metadata['reference_id'] ?? 'billref',
            'pp_Description'      => $metadata['description'] ?? 'Job Portal Payment',
            'pp_TxnExpiryDateTime'=> date('YmdHis', strtotime('+1 hour')),
            'pp_ReturnURL'        => base_url('api/v1/webhooks/jazzcash'),
        ];

        $params['pp_SecureHash'] = $this->generateHash($params);

        // Redirect flow — the controller renders an auto-submitting form to
        // $this->postUrl with these $params as hidden fields.
        return [
            'status'            => 'pending',
            'redirect_url'      => $this->postUrl,
            'client_secret'     => null,
            'gateway_reference' => $txnRefNo,
            'form_fields'       => $params, // consumed by the controller to render the redirect form
        ];
    }

    public function verifyWebhook(string $rawPayload, array $headers): array
    {
        parse_str($rawPayload, $data);

        $receivedHash = $data['pp_SecureHash'] ?? '';
        unset($data['pp_SecureHash']);
        $expectedHash = $this->generateHash($data);

        return [
            'verified'               => hash_equals($expectedHash, $receivedHash),
            'gateway_transaction_id' => $data['pp_TxnRefNo'] ?? null,
            'status'                 => ($data['pp_ResponseCode'] ?? '') === '000' ? 'succeeded' : 'failed',
            'raw'                    => $data,
        ];
    }

    public function refund(string $gatewayTransactionId, float $amount): array
    {
        // JazzCash refunds are typically handled via their merchant
        // dashboard / a separate reconciliation API per merchant agreement
        // — not exposed uniformly enough to automate safely here. Flagged
        // for manual processing, consistent with refund_requests requiring
        // Support-staff approval regardless of gateway.
        return ['status' => 'manual_processing_required', 'raw' => []];
    }

    public function getStatus(string $gatewayTransactionId): array
    {
        return ['status' => 'unknown', 'raw' => ['note' => 'JazzCash status requires their Inquiry API — implement per merchant agreement.']];
    }

    private function generateHash(array $params): string
    {
        ksort($params);
        $filtered = array_filter($params, static fn ($v) => $v !== null && $v !== '');
        $string = $this->integritySalt . '&' . implode('&', $filtered);
        return hash_hmac('sha256', $string, $this->integritySalt);
    }
}
