<?php

namespace App\Domain\Financial\Services;

use App\Domain\Financial\Enums\PaymentMethod;
use App\Domain\Financial\Enums\PaymentStatus;
use App\Domain\Financial\Events\PaymentReceived;
use App\Domain\Financial\Models\Invoice;
use App\Domain\Financial\Models\Payment;
use App\Domain\Shared\Models\SystemSetting;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class PaymobService
{
    private ?string $apiKey;
    private ?string $integrationId;
    private ?string $iframeId;
    private ?string $hmacSecret;

    public function __construct()
    {
        $this->apiKey = SystemSetting::get('paymob_api_key');
        $this->integrationId = SystemSetting::get('paymob_integration_id');
        $this->iframeId = SystemSetting::get('paymob_iframe_id');
        $this->hmacSecret = SystemSetting::get('paymob_hmac_secret');
    }

    public function isConfigured(): bool
    {
        return $this->apiKey && $this->integrationId && $this->hmacSecret;
    }

    public function createPaymentIntention(Invoice $invoice, User $payer): array
    {
        if (!$this->isConfigured()) {
            throw new \RuntimeException('Paymob is not configured');
        }

        // Step 1: Authentication
        $authToken = $this->authenticate();

        // Step 2: Create order
        $orderId = $this->createOrder($authToken, $invoice);

        // Step 3: Get payment key
        $paymentKey = $this->getPaymentKey($authToken, $orderId, $invoice, $payer);

        $iframeUrl = "https://accept.paymob.com/api/acceptance/iframes/{$this->iframeId}?payment_token={$paymentKey}";

        return [
            'payment_key' => $paymentKey,
            'iframe_url' => $iframeUrl,
            'order_id' => (string) $orderId,
        ];
    }

    public function verifyCallback(array $data): bool
    {
        if (!$this->hmacSecret) {
            return false;
        }

        $hmac = $data['hmac'] ?? '';
        unset($data['hmac']);

        $concatenated = implode('', [
            $data['amount_cents'] ?? '',
            $data['created_at'] ?? '',
            $data['currency'] ?? '',
            $data['error_occured'] ?? '',
            $data['has_parent_transaction'] ?? '',
            $data['id'] ?? '',
            $data['integration_id'] ?? '',
            $data['is_3d_secure'] ?? '',
            $data['is_auth'] ?? '',
            $data['is_capture'] ?? '',
            $data['is_refunded'] ?? '',
            $data['is_standalone_payment'] ?? '',
            $data['is_voided'] ?? '',
            $data['order'] ?? '',
            $data['owner'] ?? '',
            $data['pending'] ?? '',
            $data['source_data_pan'] ?? '',
            $data['source_data_sub_type'] ?? '',
            $data['source_data_type'] ?? '',
            $data['success'] ?? '',
        ]);

        $calculatedHmac = hash_hmac('sha512', $concatenated, $this->hmacSecret);

        return hash_equals($calculatedHmac, $hmac);
    }

    public function processSuccessfulPayment(array $callbackData): ?Payment
    {
        $transactionId = $callbackData['id'] ?? null;
        $orderId = $callbackData['order'] ?? null;
        $amountCents = (int) ($callbackData['amount_cents'] ?? 0);
        $success = filter_var($callbackData['success'] ?? false, FILTER_VALIDATE_BOOLEAN);

        if (!$success || !$orderId || $amountCents <= 0) {
            Log::warning('[Paymob] Callback with failure or missing data', $callbackData);
            return null;
        }

        // Find the pending payment by gateway order ID
        $payment = Payment::where('status', PaymentStatus::Pending)
            ->whereJsonContains('gateway_data->paymob_order_id', (string) $orderId)
            ->first();

        if (!$payment) {
            Log::warning('[Paymob] No pending payment found for order', ['order_id' => $orderId]);
            return null;
        }

        // Prevent double-processing
        if ($payment->status === PaymentStatus::Confirmed) {
            return $payment;
        }

        return DB::transaction(function () use ($payment, $transactionId, $callbackData) {
            $payment->update([
                'status' => PaymentStatus::Confirmed,
                'confirmed_at' => now(),
                'gateway_data' => array_merge($payment->gateway_data ?? [], [
                    'paymob_transaction_id' => $transactionId,
                    'callback_data' => $callbackData,
                ]),
            ]);

            // Update invoice
            $invoice = $payment->invoice;
            if ($invoice) {
                $invoice->paid_amount += $payment->amount;
                $invoice->balance_due = $invoice->total_amount - $invoice->paid_amount;

                if ($invoice->balance_due <= 0) {
                    $invoice->status = 'paid';
                    $invoice->balance_due = 0;
                } elseif ($invoice->paid_amount > 0) {
                    $invoice->status = 'partially_paid';
                }

                $invoice->save();
            }

            PaymentReceived::dispatch($payment, $payment->creator ?? User::find($payment->created_by));

            return $payment;
        });
    }

    private function authenticate(): string
    {
        $response = Http::post('https://accept.paymob.com/api/auth/tokens', [
            'api_key' => $this->apiKey,
        ]);

        if (!$response->successful()) {
            throw new \RuntimeException('Paymob authentication failed: ' . $response->body());
        }

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

    private function createOrder(string $authToken, Invoice $invoice): int
    {
        $response = Http::post('https://accept.paymob.com/api/ecommerce/orders', [
            'auth_token' => $authToken,
            'delivery_needed' => false,
            'amount_cents' => $invoice->balance_due,
            'currency' => 'EGP',
            'merchant_order_id' => $invoice->uuid,
            'items' => [],
        ]);

        if (!$response->successful()) {
            throw new \RuntimeException('Paymob order creation failed: ' . $response->body());
        }

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

    private function getPaymentKey(string $authToken, int $orderId, Invoice $invoice, User $payer): string
    {
        $response = Http::post('https://accept.paymob.com/api/acceptance/payment_keys', [
            'auth_token' => $authToken,
            'amount_cents' => $invoice->balance_due,
            'expiration' => 3600,
            'order_id' => $orderId,
            'billing_data' => [
                'first_name' => $payer->name_ar ?? $payer->name ?? 'Customer',
                'last_name' => 'N/A',
                'email' => $payer->email ?? 'no-email@example.com',
                'phone_number' => $payer->phone ?? '+201000000000',
                'apartment' => 'N/A',
                'floor' => 'N/A',
                'street' => 'N/A',
                'building' => 'N/A',
                'shipping_method' => 'N/A',
                'postal_code' => 'N/A',
                'city' => 'N/A',
                'country' => 'EG',
                'state' => 'N/A',
            ],
            'currency' => 'EGP',
            'integration_id' => (int) $this->integrationId,
        ]);

        if (!$response->successful()) {
            throw new \RuntimeException('Paymob payment key failed: ' . $response->body());
        }

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