<?php

namespace App\Http\Controllers;

use App\Models\Payment;
use App\Services\Settings\SettingsService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Razorpay\Api\Api;
use Razorpay\Api\Errors\SignatureVerificationError;

class RazorpayWebhookController extends Controller
{
    public function __construct(private readonly SettingsService $settings) {}

    public function __invoke(Request $request): JsonResponse
    {
        abort_unless($this->isWebhookConfigured(), 503, 'Razorpay webhook is not configured.');

        $rawPayload = $request->getContent();
        $signature = (string) $request->header('X-Razorpay-Signature', '');

        abort_if($signature === '', 400, 'Missing Razorpay webhook signature.');

        try {
            $this->razorpay()->utility->verifyWebhookSignature(
                $rawPayload,
                $signature,
                $this->webhookSecret()
            );
        } catch (SignatureVerificationError) {
            return response()->json(['message' => 'Invalid webhook signature.'], 422);
        }

        $payload = json_decode($rawPayload, true);

        abort_unless(is_array($payload), 400, 'Invalid webhook payload.');

        $paymentEntity = $payload['payload']['payment']['entity'] ?? null;

        if (! is_array($paymentEntity)) {
            return response()->json(['message' => 'Webhook ignored.']);
        }

        $orderId = $paymentEntity['order_id'] ?? null;
        $paymentId = $paymentEntity['id'] ?? null;
        $status = $paymentEntity['status'] ?? null;

        if (! is_string($orderId) || ! is_string($paymentId)) {
            return response()->json(['message' => 'Webhook ignored.']);
        }

        $payment = Payment::query()
            ->where('razorpay_order_id', $orderId)
            ->first();

        if (! $payment) {
            return response()->json(['message' => 'Payment not found.']);
        }

        $amountMatches = (int) ($paymentEntity['amount'] ?? 0) === $payment->amount_paise;
        $currencyMatches = strtoupper((string) ($paymentEntity['currency'] ?? '')) === $payment->currency;

        if ($status === 'captured' && $amountMatches && $currencyMatches) {
            DB::transaction(function () use ($payment, $paymentId, $signature, $payload, $paymentEntity): void {
                $payment->forceFill([
                    'razorpay_payment_id' => $paymentId,
                    'razorpay_signature' => $signature,
                    'status' => Payment::STATUS_CAPTURED,
                    'payment_payload' => $paymentEntity,
                    'webhook_payload' => $payload,
                    'verified_at' => $payment->verified_at ?? now(),
                    'unlocked_at' => $payment->unlocked_at ?? now(),
                ])->save();

                $payment->user()->update([
                    'access_unlocked_at' => $payment->user->access_unlocked_at ?? now(),
                ]);
            });

            return response()->json(['message' => 'Payment captured.']);
        }

        if ($status === 'failed') {
            $payment->forceFill([
                'razorpay_payment_id' => $paymentId,
                'status' => Payment::STATUS_FAILED,
                'payment_payload' => $paymentEntity,
                'webhook_payload' => $payload,
                'failed_at' => now(),
            ])->save();
        }

        return response()->json(['message' => 'Webhook processed.']);
    }

    private function razorpay(): Api
    {
        return new Api(
            $this->razorpayKey(),
            $this->razorpaySecret()
        );
    }

    private function isWebhookConfigured(): bool
    {
        return $this->settings->isEnabled('payment.razorpay_enabled')
            && filled($this->razorpayKey())
            && filled($this->razorpaySecret())
            && filled($this->webhookSecret());
    }

    private function razorpayKey(): string
    {
        return (string) $this->settings->get('payment.razorpay_key_id', config('services.razorpay.key'));
    }

    private function razorpaySecret(): string
    {
        return (string) $this->settings->get('payment.razorpay_key_secret', config('services.razorpay.secret'));
    }

    private function webhookSecret(): string
    {
        return (string) $this->settings->get('payment.razorpay_webhook_secret', config('services.razorpay.webhook_secret'));
    }
}
