<?php
declare(strict_types=1);

require_once dirname(__DIR__) . '/payments.php';

final class PayPalGateway implements PaymentGateway
{
    private ?string $accessToken = null;

    /** @param array<string,mixed> $settings */
    public function __construct(private array $settings)
    {
    }

    public function providerId(): string
    {
        return 'paypal';
    }

    private function baseUrl(): string
    {
        return (($this->settings['mode'] ?? 'test') === 'live')
            ? 'https://api-m.paypal.com'
            : 'https://api-m.sandbox.paypal.com';
    }

    private function token(): string
    {
        if ($this->accessToken) {
            return $this->accessToken;
        }
        $id = trim((string) ($this->settings['paypal_client_id'] ?? ''));
        $secret = trim((string) ($this->settings['paypal_client_secret'] ?? ''));
        if ($id === '' || $secret === '') {
            throw new RuntimeException('PayPal client ID/secret not configured.');
        }
        $resp = payment_http(
            'POST',
            $this->baseUrl() . '/v1/oauth2/token',
            [
                'Authorization: Basic ' . base64_encode($id . ':' . $secret),
                'Content-Type: application/x-www-form-urlencoded',
            ],
            'grant_type=client_credentials'
        );
        if (empty($resp['json']['access_token'])) {
            throw new RuntimeException('PayPal auth failed.');
        }
        $this->accessToken = (string) $resp['json']['access_token'];
        return $this->accessToken;
    }

    public function createCheckout(array $input): array
    {
        $currency = strtoupper((string) ($input['currency'] ?? 'USD'));
        $amount = number_format((float) $input['amount'], 2, '.', '');
        $payload = [
            'intent' => 'CAPTURE',
            'purchase_units' => [[
                'amount' => [
                    'currency_code' => $currency,
                    'value' => $amount,
                ],
                'description' => substr((string) $input['description'], 0, 120),
                'custom_id' => (string) (($input['metadata']['payment_id'] ?? '') ?: ($input['metadata']['reference_id'] ?? '')),
            ]],
            'application_context' => [
                'return_url' => $input['success_url'],
                'cancel_url' => $input['cancel_url'],
                'user_action' => 'PAY_NOW',
                'shipping_preference' => 'NO_SHIPPING',
                'brand_name' => 'BarberShop',
            ],
        ];

        $resp = payment_http(
            'POST',
            $this->baseUrl() . '/v2/checkout/orders',
            [
                'Authorization: Bearer ' . $this->token(),
                'Content-Type: application/json',
            ],
            json_encode($payload, JSON_UNESCAPED_SLASHES)
        );
        if ($resp['status'] >= 400 || empty($resp['json']['id'])) {
            $msg = $resp['json']['message'] ?? ($resp['json']['details'][0]['description'] ?? ('PayPal error HTTP ' . $resp['status']));
            throw new RuntimeException(is_string($msg) ? $msg : 'PayPal order create failed.');
        }
        $approve = null;
        foreach ($resp['json']['links'] ?? [] as $link) {
            if (($link['rel'] ?? '') === 'approve') {
                $approve = $link['href'] ?? null;
                break;
            }
        }
        return [
            'external_id' => (string) $resp['json']['id'],
            'checkout_url' => $approve,
            'status' => 'pending',
            'raw' => $resp['json'],
        ];
    }

    public function fetchStatus(string $externalId): array
    {
        $resp = payment_http(
            'GET',
            $this->baseUrl() . '/v2/checkout/orders/' . rawurlencode($externalId),
            [
                'Authorization: Bearer ' . $this->token(),
                'Content-Type: application/json',
            ]
        );
        $status = strtoupper((string) ($resp['json']['status'] ?? ''));
        if ($status === 'APPROVED') {
            $cap = payment_http(
                'POST',
                $this->baseUrl() . '/v2/checkout/orders/' . rawurlencode($externalId) . '/capture',
                [
                    'Authorization: Bearer ' . $this->token(),
                    'Content-Type: application/json',
                ],
                '{}'
            );
            $status = strtoupper((string) ($cap['json']['status'] ?? $status));
            return [
                'status' => $status === 'COMPLETED' ? 'paid' : 'pending',
                'external_id' => $externalId,
                'raw' => $cap['json'] ?? $resp['json'],
            ];
        }
        return [
            'status' => $status === 'COMPLETED' ? 'paid' : 'pending',
            'external_id' => $externalId,
            'raw' => $resp['json'] ?? [],
        ];
    }
}
