<?php

namespace App\Services;

use App\Models\Setting;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class PesapalService
{
    private function isEnabled(): bool
    {
        return $this->consumerKey() !== '' && $this->consumerSecret() !== '';
    }

    private function baseUrl(): string
    {
        $base = (string) (Setting::getValue('pesapal_base_url', null, config('services.pesapal.base_url', 'https://cybqa.pesapal.com/pesapalv3')) ?? '');
        return rtrim($base, '/');
    }

    private function consumerKey(): string
    {
        return (string) (Setting::getValue('pesapal_consumer_key', null, config('services.pesapal.consumer_key')) ?? '');
    }

    private function consumerSecret(): string
    {
        return (string) (Setting::getValue('pesapal_consumer_secret', null, config('services.pesapal.consumer_secret')) ?? '');
    }

    public function currency(): string
    {
        return strtoupper((string) (Setting::getValue('pesapal_currency', null, config('services.pesapal.currency', 'UGX')) ?? 'UGX'));
    }

    public function getAccessToken(): ?string
    {
        if (! $this->isEnabled()) {
            Log::warning('PesaPal not configured: consumer key/secret missing.');
            return null;
        }

        return Cache::remember('pesapal_access_token', now()->addMinutes(50), function () {
            $response = Http::timeout(20)->acceptJson()->post($this->baseUrl() . '/api/Auth/RequestToken', [
                'consumer_key' => $this->consumerKey(),
                'consumer_secret' => $this->consumerSecret(),
            ]);

            if (! $response->successful()) {
                Log::error('PesaPal token request failed', ['status' => $response->status(), 'body' => $response->body()]);
                return null;
            }

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

    public function registerIpnUrl(string $ipnUrl): ?string
    {
        $cached = Cache::get('pesapal_ipn_id');
        if (is_string($cached) && $cached !== '') {
            return $cached;
        }

        $token = $this->getAccessToken();
        if (! $token) {
            return null;
        }

        $response = Http::timeout(20)
            ->withToken($token)
            ->acceptJson()
            ->post($this->baseUrl() . '/api/URLSetup/RegisterIPN', [
                'url' => $ipnUrl,
                'ipn_notification_type' => 'GET',
            ]);

        if (! $response->successful()) {
            Log::error('PesaPal IPN registration failed', ['status' => $response->status(), 'body' => $response->body()]);
            return null;
        }

        $ipnId = $response->json('ipn_id');
        if (is_string($ipnId) && $ipnId !== '') {
            Cache::forever('pesapal_ipn_id', $ipnId);
            return $ipnId;
        }

        return null;
    }

    /**
     * @param array<string,mixed> $payload
     * @return array<string,mixed>|null
     */
    public function submitOrderRequest(array $payload): ?array
    {
        $token = $this->getAccessToken();
        if (! $token) {
            return null;
        }

        $response = Http::timeout(30)
            ->withToken($token)
            ->acceptJson()
            ->post($this->baseUrl() . '/api/Transactions/SubmitOrderRequest', $payload);

        if (! $response->successful()) {
            Log::error('PesaPal submit order failed', ['status' => $response->status(), 'body' => $response->body()]);
            return null;
        }

        return $response->json();
    }

    /**
     * @return array<string,mixed>|null
     */
    public function getTransactionStatus(string $orderTrackingId): ?array
    {
        $token = $this->getAccessToken();
        if (! $token) {
            return null;
        }

        $url = $this->baseUrl() . '/api/Transactions/GetTransactionStatus?orderTrackingId=' . urlencode($orderTrackingId);
        $response = Http::timeout(20)->withToken($token)->acceptJson()->get($url);

        if (! $response->successful()) {
            Log::error('PesaPal transaction status lookup failed', ['status' => $response->status(), 'body' => $response->body()]);
            return null;
        }

        return $response->json();
    }
}
