<?php

namespace App\Http\Controllers\Webhook;

use App\Http\Controllers\Controller;
use App\Models\User;
use App\Models\WebhookEvent;
use App\Models\WalletFundingRequest;
use App\Services\SystemSettingService;
use App\Services\UserActivityService;
use App\Services\WalletService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class PaystackWebhookController extends Controller
{
    public function __invoke(
        Request $request,
        SystemSettingService $systemSettingService,
        WalletService $walletService,
        UserActivityService $userActivityService
    ): JsonResponse
    {
        $payload = $request->all();
        $this->assertSignature($request, $systemSettingService);

        $eventName = (string) ($payload['event'] ?? 'unknown');
        $paymentReference = (string) (data_get($payload, 'data.reference') ?? '');
        $eventReference = $paymentReference !== ''
            ? 'paystack:'.$eventName.':'.$paymentReference
            : 'paystack:'.$eventName.':'.hash('sha256', $request->getContent());

        $event = WebhookEvent::firstOrCreate(
            ['event_reference' => $eventReference],
            [
                'provider' => 'paystack',
                'payload_json' => $payload,
            ]
        );

        if ($event->processed_at !== null) {
            return response()->json(['ok' => true, 'duplicate' => true]);
        }

        $matched = false;
        $credited = false;

        $isSuccessful = strtolower((string) (data_get($payload, 'data.status') ?? '')) === 'success';
        $amount = round(((float) (data_get($payload, 'data.amount') ?? 0)) / 100, 2);

        if ($eventName === 'charge.success' && $paymentReference !== '' && $isSuccessful && $amount > 0) {
            $funding = WalletFundingRequest::query()
                ->with('user')
                ->where('provider', WalletFundingRequest::PROVIDER_PAYSTACK)
                ->where('reference', $paymentReference)
                ->first();

            $targetUser = $funding?->user;
            if (! $targetUser) {
                $metadataUserId = (int) (data_get($payload, 'data.metadata.user_id') ?? 0);
                if ($metadataUserId > 0) {
                    $targetUser = User::query()->find($metadataUserId);
                }
            }

            if ($targetUser) {
                $matched = true;

                $walletService->credit(
                    user: $targetUser,
                    amount: $amount,
                    reference: "wallet:paystack:{$paymentReference}",
                    narration: 'Paystack wallet funding',
                    meta: [
                        'provider' => 'paystack',
                        'funding_request_id' => $funding?->id,
                        'event' => $eventName,
                        'payment_reference' => $paymentReference,
                        'payload' => $payload,
                    ],
                    source: 'paystack'
                );
                $userActivityService->touch($targetUser);

                $credited = true;

                if ($funding) {
                    $funding->update([
                        'status' => WalletFundingRequest::STATUS_SUCCESS,
                        'paid_at' => now(),
                        'external_reference' => (string) (data_get($payload, 'data.id')
                            ?? data_get($payload, 'data.transaction_date')
                            ?? $funding->external_reference),
                        'payload_json' => $payload,
                    ]);
                }
            }
        }

        $event->update(['processed_at' => now()]);

        return response()->json([
            'ok' => true,
            'provider' => 'paystack',
            'matched' => $matched,
            'credited' => $credited,
        ]);
    }

    protected function assertSignature(Request $request, SystemSettingService $systemSettingService): void
    {
        $secret = (string) $systemSettingService->get('payments.paystack', 'secret_key', config('services.paystack.secret_key', ''));
        if ($secret === '') {
            $secret = (string) $systemSettingService->get(
                'webhooks.paystack',
                'secret',
                config('vtu.webhooks.paystack.secret', '')
            );
        }
        if ($secret === '') {
            if (app()->environment(['local', 'testing'])) {
                return;
            }

            abort(503, 'Paystack webhook secret is not configured.');
        }

        $provided = (string) $request->header('x-paystack-signature', '');
        $expected = hash_hmac('sha512', $request->getContent(), $secret);

        abort_unless($provided !== '' && hash_equals($expected, $provided), 401, 'Invalid Paystack signature.');
    }
}
