<?php

namespace App\Services;

use App\Exceptions\PaystackException;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class PaystackService
{
    private string $secretKey;
    private string $baseUrl;
    private string $webhookSecret;

    public function __construct()
    {
        $this->secretKey = config('services.paystack.secret_key');
        $this->baseUrl = config('services.paystack.base_url', 'https://api.paystack.co');
        $this->webhookSecret = config('services.paystack.webhook_secret', '');
    }

    /**
     * Initialize a Paystack transaction.
     *
     * @param  string  $email         Customer email
     * @param  int     $amountInKobo  Amount in kobo (NGN * 100)
     * @param  string  $reference     Unique transaction reference
     * @param  array   $metadata      Additional metadata
     * @param  string|null $callbackUrl  URL to redirect after payment
     * @return array{authorization_url: string, access_code: string, reference: string}
     *
     * @throws PaystackException
     */
    public function initializeTransaction(
        string $email,
        int $amountInKobo,
        string $reference,
        array $metadata = [],
        ?string $callbackUrl = null,
    ): array {
        $payload = [
            'email' => $email,
            'amount' => $amountInKobo,
            'reference' => $reference,
            'metadata' => $metadata,
            'currency' => 'NGN',
        ];

        if ($callbackUrl) {
            $payload['callback_url'] = $callbackUrl;
        }

        $response = Http::withToken($this->secretKey)
            ->timeout(30)
            ->post("{$this->baseUrl}/transaction/initialize", $payload);

        if ($response->failed() || !$response->json('status')) {
            Log::error('Paystack: Failed to initialize transaction', [
                'reference' => $reference,
                'status_code' => $response->status(),
                'body' => $response->json(),
            ]);

            throw new PaystackException(
                $response->json('message', 'Failed to initialize Paystack transaction'),
                $response->json() ?? [],
                $response->status(),
            );
        }

        $data = $response->json('data');

        return [
            'authorization_url' => $data['authorization_url'],
            'access_code' => $data['access_code'],
            'reference' => $data['reference'],
        ];
    }

    /**
     * Verify a Paystack transaction by reference.
     *
     * @param  string  $reference
     * @return array  Full transaction data from Paystack
     *
     * @throws PaystackException
     */
    public function verifyTransaction(string $reference): array
    {
        $response = Http::withToken($this->secretKey)
            ->timeout(30)
            ->get("{$this->baseUrl}/transaction/verify/{$reference}");

        if ($response->failed() || !$response->json('status')) {
            Log::error('Paystack: Failed to verify transaction', [
                'reference' => $reference,
                'status_code' => $response->status(),
                'body' => $response->json(),
            ]);

            throw new PaystackException(
                $response->json('message', 'Failed to verify Paystack transaction'),
                $response->json() ?? [],
                $response->status(),
            );
        }

        return $response->json('data');
    }

    /**
     * Validate Paystack webhook signature.
     *
     * @param  string  $payload    Raw request body
     * @param  string  $signature  X-Paystack-Signature header value
     * @return bool
     */
    public function validateWebhookSignature(string $payload, string $signature): bool
    {
        if (empty($this->webhookSecret)) {
            Log::warning('Paystack: Webhook secret not configured');
            return false;
        }

        $computed = hash_hmac('sha512', $payload, $this->webhookSecret);

        return hash_equals($computed, $signature);
    }
}
