<?php

namespace App\Libraries\PaymentGateways;

use GuzzleHttp\Client;

class PayPalGateway implements PaymentGatewayInterface
{
    private Client $http;
    private string $clientId;
    private string $secret;
    private string $baseUri;

    public function __construct()
    {
        $this->clientId = env('paypal.clientId');
        $this->secret   = env('paypal.secret');
        $mode = env('paypal.mode') ?? 'sandbox';
        $this->baseUri = $mode === 'live' ? 'https://api-m.paypal.com' : 'https://api-m.sandbox.paypal.com';
        $this->http = new Client(['base_uri' => $this->baseUri]);
    }

    private function accessToken(): string
    {
        $response = $this->http->post('/v1/oauth2/token', [
            'auth'        => [$this->clientId, $this->secret],
            'form_params' => ['grant_type' => 'client_credentials'],
        ]);
        $body = json_decode((string) $response->getBody(), true);
        return $body['access_token'];
    }

    public function charge(float $amount, string $currency, array $metadata = []): array
    {
        $token = $this->accessToken();

        $response = $this->http->post('/v2/checkout/orders', [
            'headers' => ['Authorization' => "Bearer {$token}"],
            'json'    => [
                'intent'          => 'CAPTURE',
                'purchase_units'  => [[
                    'amount'      => ['currency_code' => $currency, 'value' => number_format($amount, 2, '.', '')],
                    'custom_id'   => $metadata['reference_id'] ?? null,
                ]],
            ],
        ]);

        $body = json_decode((string) $response->getBody(), true);
        $approveLink = null;
        foreach ($body['links'] ?? [] as $link) {
            if (($link['rel'] ?? '') === 'approve') {
                $approveLink = $link;
                break;
            }
        }

        return [
            'status'            => strtolower($body['status'] ?? 'pending'),
            'redirect_url'      => $approveLink['href'] ?? null,
            'client_secret'     => null,
            'gateway_reference' => $body['id'] ?? null,
        ];
    }

    public function verifyWebhook(string $rawPayload, array $headers): array
    {
        // PayPal webhook verification requires a call to their
        // /v1/notifications/verify-webhook-signature endpoint with the
        // transmission headers — implemented as a direct call rather than
        // local HMAC since PayPal doesn't support local signature checks.
        $token = $this->accessToken();
        $body = json_decode($rawPayload, true) ?? [];

        $response = $this->http->post('/v1/notifications/verify-webhook-signature', [
            'headers' => ['Authorization' => "Bearer {$token}"],
            'json'    => [
                'transmission_id'   => $headers['Paypal-Transmission-Id'] ?? '',
                'transmission_time' => $headers['Paypal-Transmission-Time'] ?? '',
                'cert_url'          => $headers['Paypal-Cert-Url'] ?? '',
                'auth_algo'         => $headers['Paypal-Auth-Algo'] ?? '',
                'transmission_sig'  => $headers['Paypal-Transmission-Sig'] ?? '',
                'webhook_id'        => env('paypal.webhookId'),
                'webhook_event'     => $body,
            ],
        ]);

        $result = json_decode((string) $response->getBody(), true);

        return [
            'verified'               => ($result['verification_status'] ?? '') === 'SUCCESS',
            'gateway_transaction_id' => $body['resource']['id'] ?? null,
            'status'                 => $body['resource']['status'] ?? null,
            'raw'                    => $body,
        ];
    }

    public function refund(string $gatewayTransactionId, float $amount): array
    {
        $token = $this->accessToken();
        $response = $this->http->post("/v2/payments/captures/{$gatewayTransactionId}/refund", [
            'headers' => ['Authorization' => "Bearer {$token}"],
            'json'    => ['amount' => ['value' => number_format($amount, 2, '.', ''), 'currency_code' => 'USD']],
        ]);
        $body = json_decode((string) $response->getBody(), true);
        return ['status' => strtolower($body['status'] ?? 'failed'), 'raw' => $body];
    }

    public function getStatus(string $gatewayTransactionId): array
    {
        $token = $this->accessToken();
        $response = $this->http->get("/v2/checkout/orders/{$gatewayTransactionId}", ['headers' => ['Authorization' => "Bearer {$token}"]]);
        $body = json_decode((string) $response->getBody(), true);
        return ['status' => strtolower($body['status'] ?? 'unknown'), 'raw' => $body];
    }
}
