<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Controllers\Web\PaymentController;
use App\Models\Order;
use App\Services\EasyKashService;
use App\Services\PaymentTransactionLogger;
use App\Support\PaymentFailure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class EasyKashCallbackController extends Controller
{
    public function handle(Request $request, PaymentController $paymentController, EasyKashService $easyKashService)
    {
        $rawBody = $request->getContent();
        $payload = array_merge($request->query(), $this->decodePayload($request, $rawBody));

        if (!$this->signatureValid($request, $rawBody, $payload, $easyKashService)) {
            Log::warning('easykash.callback.invalid_signature', ['ip' => $request->ip()]);

            return response()->json(['ok' => false, 'error' => 'invalid_signature'], 401);
        }

        if (config('app.debug')) {
            Log::info('easykash.callback.payload', ['payload' => $payload]);
        }

        $orderId = $this->resolveOrderId($payload);
        if ($orderId === null) {
            Log::notice('easykash.callback.missing_order_id', ['payload' => $payload]);

            return response()->json(['ok' => true, 'processed' => false, 'reason' => 'missing_order_reference']);
        }

        $order = Order::where('id', $orderId)->first();
        if (!$order) {
            Log::notice('easykash.callback.order_not_found', ['order_id' => $orderId]);

            return response()->json(['ok' => true, 'processed' => false, 'reason' => 'order_not_found']);
        }

        if ($easyKashService->isFailedPaymentPayload($payload)) {
            $reason = $this->extractFailureReason($payload);

            if (in_array($order->status, [Order::$pending, Order::$paying], true)) {
                PaymentFailure::markOrderFailed($order, $reason);
            }

            PaymentTransactionLogger::logForOrder($order, 'easykash_callback', 'failed', $reason, [
                'response_body' => json_encode($payload, JSON_UNESCAPED_UNICODE),
            ]);

            $paymentController->unlockMeetingReservationLock($order);

            return response()->json(['ok' => true, 'processed' => true, 'result' => 'marked_failed']);
        }

        if (!$easyKashService->isSuccessfulPaymentPayload($payload)) {
            return response()->json(['ok' => true, 'processed' => false, 'reason' => 'non_terminal_status']);
        }

        $done = $paymentController->finalizeSuccessfulGatewayPayment($order);

        PaymentTransactionLogger::logForOrder($order, 'easykash_callback', 'success', null, [
            'response_body' => json_encode($payload, JSON_UNESCAPED_UNICODE),
        ]);

        return response()->json([
            'ok' => true,
            'processed' => $done,
            'order_id' => $order->id,
            'status' => $order->fresh()->status,
        ]);
    }

    private function decodePayload(Request $request, string $rawBody): array
    {
        if ($request->isJson()) {
            return $request->json()->all() ?: [];
        }

        if ($rawBody !== '') {
            $decoded = json_decode($rawBody, true);
            if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
                return $decoded;
            }
        }

        return $request->request->all();
    }

    private function resolveOrderId(array $payload): ?int
    {
        $keys = [
            'customerReference',
            'CustomerReference',
            'merchant_order_id',
            'merchantOrderId',
            'order_id',
            'orderId',
            'OrderId',
            'external_reference',
            'externalReference',
            'reference',
            'entityExternalReference',
            'transaction_reference',
        ];

        foreach ($keys as $key) {
            if (!isset($payload[$key]) || $payload[$key] === '' || $payload[$key] === null) {
                continue;
            }
            $val = $payload[$key];
            if (is_numeric($val)) {
                return EasyKashService::resolveOrderIdFromCustomerReference((int) $val);
            }
        }

        if (!empty($payload['metadata']) && is_array($payload['metadata'])) {
            foreach (['order_id', 'orderId', 'transaction'] as $mk) {
                if (!empty($payload['metadata'][$mk]) && is_numeric($payload['metadata'][$mk])) {
                    return (int) $payload['metadata'][$mk];
                }
            }
        }

        return null;
    }

    private function signatureValid(Request $request, string $rawBody, array $payload, EasyKashService $easyKashService): bool
    {
        $secret = config('services.easykash.hmac_secret');

        if (!empty($payload['signatureHash']) || !empty($payload['signature_hash'])) {
            if ($secret === null || $secret === '') {
                Log::warning('easykash.callback.signature_configured_but_no_secret');

                return false;
            }

            return $easyKashService->verifyCallbackSignature($payload);
        }

        if ($secret === null || $secret === '') {
            return true;
        }

        $headers = config('services.easykash.signature_headers');
        if (!is_array($headers)) {
            $headers = ['X-Webhook-Signature'];
        }

        foreach ($headers as $headerName) {
            $received = $request->header($headerName);
            if ($received === null || $received === '') {
                continue;
            }

            $received = trim($received);
            if (strpos($received, 'sha256=') === 0) {
                $received = substr($received, 7);
            }

            $expectedHex = hash_hmac('sha256', $rawBody, $secret);
            if (hash_equals($expectedHex, $received)) {
                return true;
            }

            $decoded = json_decode($rawBody, true);
            if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
                $canonical = json_encode($decoded, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
                $expectedAlt = hash_hmac('sha256', $canonical, $secret);
                if (hash_equals($expectedAlt, $received)) {
                    return true;
                }
            }
        }

        return false;
    }

    private function extractFailureReason(array $payload): string
    {
        foreach (['message', 'error', 'failure_reason', 'reason', 'statusMessage'] as $key) {
            if (!empty($payload[$key]) && is_string($payload[$key])) {
                return $payload[$key];
            }
        }

        $status = $payload['status'] ?? $payload['payment_status'] ?? $payload['paymentStatus'] ?? null;

        return 'رفض الدفع من EasyKash' . ($status ? ' (حالة: ' . $status . ')' : '');
    }
}
