<?php

namespace App\Services;

use App\Models\Billing;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

/**
 * Integrasi gateway Duitku (POP V2 createInvoice API).
 *
 * Semua formula/quirk Duitku diisolasi di sini agar controller bersih.
 * Autentikasi via header:
 * - x-duitku-signature = sha256(merchantCode + timestamp + apiKey)
 * - x-duitku-timestamp = milliseconds
 * - x-duitku-merchantcode = merchantCode
 *
 * Callback (server-to-server) tetap pakai signature MD5 klasik:
 * - md5(merchantCode + amount + merchantOrderId + apiKey)
 */
class DuitkuService
{
    /**
     * Buat invoice pembayaran di Duitku & ambil payment URL.
     *
     * @return array{payment_url: ?string, reference: ?string, payment_method: ?string, status_code: ?string, status_message: ?string, raw: array}
     *
     * @throws \RuntimeException bila Duitku tidak dikonfigurasi atau gagal.
     */
    public function createPayment(Billing $billing): array
    {
        $this->ensureConfigured();

        $merchantCode = config('services.duitku.merchant_code');
        $apiKey = config('services.duitku.api_key');
        $amount = (int) $billing->total;
        $merchantOrderId = $billing->no_invoice;
        $timestamp = (string) round(microtime(true) * 1000);
        $signature = hash('sha256', $merchantCode.$timestamp.$apiKey);

        $payload = [
            'merchantCode' => $merchantCode,
            'paymentAmount' => $amount,
            'merchantOrderId' => (string) $merchantOrderId,
            'productDetails' => "Deposit credit invoice {$merchantOrderId} ({$billing->jumlah_credit} credit)",
            'email' => $billing->user->email,
            'customerVaName' => $billing->user->name,
            'callbackUrl' => $this->callbackUrl(),
            'returnUrl' => $this->returnUrl(),
            'expiryPeriod' => (int) config('services.duitku.expiry_period', 60),
            'itemDetails' => [
                [
                    'name' => "Deposit credit ({$billing->jumlah_credit} credit)",
                    'price' => $amount,
                    'quantity' => 1,
                ],
            ],
        ];

        $endpoint = $this->baseUrl().config('services.duitku.inquiry_path');

        $response = Http::asJson()
            ->withHeaders([
                'x-duitku-signature' => $signature,
                'x-duitku-timestamp' => $timestamp,
                'x-duitku-merchantcode' => $merchantCode,
            ])
            ->withOptions(['verify' => false])
            ->post($endpoint, $payload);

        if (! $response->successful()) {
            Log::error('Duitku createInvoice request failed', [
                'invoice' => $merchantOrderId,
                'status' => $response->status(),
                'body' => $response->body(),
            ]);
            throw new \RuntimeException('Permintaan pembayaran Duitku gagal (HTTP '.$response->status().'): '.$response->body());
        }

        $data = $response->json() ?? [];

        $paymentUrl = $data['paymentUrl'] ?? $data['payment_url'] ?? null;
        $reference = $data['reference'] ?? $data['merchantOrderId'] ?? null;
        $statusCode = (string) ($data['statusCode'] ?? $data['status_code'] ?? '');
        $statusMessage = $data['statusMessage'] ?? $data['status_message'] ?? null;

        if (empty($paymentUrl)) {
            Log::error('Duitku createInvoice returned no payment URL', [
                'invoice' => $merchantOrderId,
                'response' => $data,
            ]);
            throw new \RuntimeException('Duitku tidak mengembalikan URL pembayaran. '.$statusMessage);
        }

        return [
            'payment_url' => $paymentUrl,
            'reference' => $reference,
            'payment_method' => $data['paymentMethod'] ?? $data['payment_method'] ?? null,
            'status_code' => $statusCode,
            'status_message' => $statusMessage,
            'raw' => $data,
        ];
    }

    /**
     * Signature request POP V2: sha256(merchantCode + timestamp + apiKey).
     */
    public function requestSignature(string $timestamp): string
    {
        return hash('sha256',
            config('services.duitku.merchant_code').
            $timestamp.
            config('services.duitku.api_key')
        );
    }

    /**
     * Signature callback: md5(merchantCode + amount + merchantOrderId + apiKey).
     */
    public function callbackSignature(string $amount, string $merchantOrderId): string
    {
        return md5(
            config('services.duitku.merchant_code').
            $amount.
            $merchantOrderId.
            config('services.duitku.api_key')
        );
    }

    /**
     * Verifikasi signature callback (constant-time compare).
     *
     * @param  array<string, mixed>  $payload
     */
    public function validCallback(array $payload): bool
    {
        $merchantCode = (string) ($payload['merchantCode'] ?? '');
        $amount = (string) ($payload['amount'] ?? '');
        $merchantOrderId = (string) ($payload['merchantOrderId'] ?? '');
        $signature = (string) ($payload['signature'] ?? '');

        if ($merchantCode === '' || $amount === '' || $merchantOrderId === '' || $signature === '') {
            return false;
        }

        // merchantCode harus cocok dengan konfigurasi.
        if (! hash_equals((string) config('services.duitku.merchant_code'), $merchantCode)) {
            return false;
        }

        return hash_equals($this->callbackSignature($amount, $merchantOrderId), $signature);
    }

    /**
     * Apakah resultCode callback menandakan pembayaran sukses? ('00')
     *
     * @param  array<string, mixed>  $payload
     */
    public function isSuccessfulCallback(array $payload): bool
    {
        return (string) ($payload['resultCode'] ?? '') === '00';
    }

    /**
     * Apakah gateway Duitku aktif & terkonfigurasi?
     */
    public function isConfigured(): bool
    {
        return (bool) config('services.duitku.enabled')
            && filled(config('services.duitku.merchant_code'))
            && filled(config('services.duitku.api_key'));
    }

    /**
     * @throws \RuntimeException bila belum dikonfigurasi.
     */
    protected function ensureConfigured(): void
    {
        if (! $this->isConfigured()) {
            throw new \RuntimeException('Gateway Duitku belum dikonfigurasi.');
        }
    }

    protected function baseUrl(): string
    {
        return rtrim((string) config('services.duitku.base_url'), '/');
    }

    protected function callbackUrl(): string
    {
        return config('services.duitku.callback_url') ?: route('payments.duitku.callback');
    }

    protected function returnUrl(): string
    {
        return config('services.duitku.return_url') ?: route('payments.duitku.return');
    }
}
