<?php

namespace App\Http\Controllers;

use App\Models\User;
use App\Models\Transaction;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;

class PaystackWebhookController extends Controller
{
    public function handle(Request $request)
    {
        $signature = $request->header('x-paystack-signature');
        $payload = $request->getContent();

        $expected = hash_hmac('sha512', $payload, config('services.paystack.secret_key'));

        if (! $signature || ! hash_equals($expected, $signature)) {
            Log::warning('Paystack webhook: invalid signature');
            return response()->json(['status' => 'invalid signature'], 401);
        }

        $event = $request->input('event');
        $data = $request->input('data');

        match ($event) {
            'charge.success' => $this->handleChargeSuccess($data),
            'dedicatedaccount.assign.success' => $this->handleAccountAssigned($data),
            default => Log::info("Paystack webhook: unhandled event {$event}"),
        };

        // Paystack expects a 200 quickly, regardless of internal processing outcome
        return response()->json(['status' => 'ok']);
    }

    private function handleChargeSuccess(array $data): void
    {
        // Only care about money received via the dedicated virtual account
        if (($data['channel'] ?? null) !== 'dedicated_nuban') {
            return;
        }

        $reference = $data['reference'] ?? null;
        $customerCode = $data['customer']['customer_code'] ?? null;
        $amountKobo = $data['amount'] ?? 0;

        if (! $reference || ! $customerCode) {
            Log::warning('Paystack webhook: missing reference/customer_code', $data);
            return;
        }

        // Idempotency guard — Paystack can send the same event more than once
        if (Transaction::where('paystack_reference', $reference)->exists()) {
            return;
        }

        $user = User::where('virtual_account_reference', $customerCode)->first();

        if (! $user) {
            Log::warning("Paystack webhook: no user for customer_code {$customerCode}");
            return;
        }

        DB::transaction(function () use ($user, $reference, $amountKobo, $data) {
            Transaction::create([
                'user_id' => $user->id,
                'paystack_reference' => $reference,
                'amount' => $amountKobo / 100,
                'type' => 'credit',
                'channel' => 'dedicated_nuban',
                'meta' => $data,
            ]);

            $user->increment('balance', $amountKobo / 100);
        });
    }

    private function handleAccountAssigned(array $data): void
    {
        $customerCode = $data['customer']['customer_code'] ?? null;
        $account = $data['dedicated_account'] ?? $data['account'] ?? null;

        if (! $customerCode || ! $account) {
            Log::warning('Paystack webhook: incomplete account assign payload', $data);
            return;
        }

        $user = User::where('virtual_account_reference', $customerCode)->first();

        if ($user) {
            $user->update([
                'virtual_account_number' => $account['account_number'] ?? null,
                'virtual_account_bank' => $account['bank']['name'] ?? null,
            ]);
        }
    }
}