<?php

namespace App\Http\Controllers\Api\Wallet;

use App\Http\Controllers\Api\BaseController;
use App\Models\Payment;
use App\Models\Setting;
use App\Modules\Wallet\Interfaces\WalletServiceInterface;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class PaystackController extends BaseController
{
    public function __construct(
        protected WalletServiceInterface $walletService
    ) {}

    public function initialize(Request $request): JsonResponse
    {
        $minFunding = (float) Setting::getValue('min_funding', 100);
        $maxFunding = (float) Setting::getValue('max_funding', 500000);

        $validated = $request->validate([
            'amount' => ['required', 'numeric', "min:{$minFunding}", "max:{$maxFunding}"],
        ]);

        $user = $request->user();
        $amount = $validated['amount'];
        $reference = 'FND-' . strtoupper(Str::random(8)) . '-' . now()->format('YmdHis');

        $wallet = $this->walletService->getOrCreateWallet($user->id);

        Payment::create([
            'user_id' => $user->id,
            'wallet_id' => $wallet->id,
            'amount' => $amount,
            'fee' => 0,
            'total' => $amount,
            'currency' => 'NGN',
            'provider' => 'paystack',
            'reference' => $reference,
            'status' => 'pending',
        ]);

        try {
            $response = Http::withHeaders([
                'Authorization' => 'Bearer ' . config('services.paystack.secret_key'),
                'Content-Type' => 'application/json',
            ])->post(config('services.paystack.base_url') . '/transaction/initialize', [
                'email' => $user->email,
                'amount' => $amount * 100,
                'reference' => $reference,
                'callback_url' => route('wallet.paystack.callback'),
                'metadata' => [
                    'user_id' => $user->id,
                    'wallet_id' => $wallet->id,
                    'reference' => $reference,
                ],
            ]);

            $body = $response->json();

            if (!$response->successful() || empty($body['data']['authorization_url'])) {
                Log::error('Paystack initialization failed', ['response' => $body]);
                return $this->errorResponse('Payment initialization failed. Please try again.', 422);
            }

            return $this->successResponse([
                'authorization_url' => $body['data']['authorization_url'],
                'reference' => $reference,
                'amount' => $amount,
            ], 'Payment initialized');
        } catch (\Exception $e) {
            Log::error('Paystack initialization error', ['error' => $e->getMessage()]);
            return $this->errorResponse('Unable to connect to Paystack. Please try again.', 500);
        }
    }

    public function verify(Request $request): JsonResponse
    {
        $reference = $request->query('reference');

        if (!$reference) {
            return $this->errorResponse('Reference is required.', 422);
        }

        return $this->verifyPayment($reference);
    }

    public function webhook(Request $request): JsonResponse
    {
        $payload = $request->all();
        $event = $payload['event'] ?? '';

        Log::info('Paystack webhook received', ['event' => $event, 'data' => $payload]);

        if (!$this->verifyWebhookSignature($request)) {
            Log::warning('Paystack webhook: Invalid signature', [
                'ip' => $request->ip(),
                'headers' => $request->headers->all(),
            ]);
            return response()->json(['status' => 'error', 'message' => 'Invalid signature'], 400);
        }

        if ($event === 'charge.success') {
            $this->handleSuccessfulCharge($payload['data']);
        }

        return response()->json(['status' => 'success']);
    }

    protected function verifyWebhookSignature(Request $request): bool
    {
        $secret = config('services.paystack.webhook_secret');

        if (empty($secret)) {
            Log::warning('Paystack webhook_secret not configured — skipping signature verification');
            return true;
        }

        $hash = $request->header('X-Paystack-Signature');

        if (empty($hash)) {
            return false;
        }

        $body = $request->getContent();
        $computed = hash_hmac('sha512', $body, $secret);

        return hash_equals($computed, $hash);
    }

    protected function handleSuccessfulCharge(array $data): void
    {
        $reference = $data['reference'] ?? '';
        $paidAmount = ($data['paid_amount'] ?? $data['amount'] ?? 0) / 100;
        $fees = ($data['fees'] ?? 0) / 100;
        $metadata = $data['metadata'] ?? [];
        $userId = $metadata['user_id'] ?? null;

        if (!$userId || !$reference) {
            Log::warning('Paystack webhook: Missing required data', $data);
            return;
        }

        $this->creditWallet($userId, $paidAmount, $fees, $reference, $data);
    }

    protected function verifyPayment(string $reference): JsonResponse
    {
        try {
            $response = Http::withHeaders([
                'Authorization' => 'Bearer ' . config('services.paystack.secret_key'),
            ])->get(config('services.paystack.base_url') . '/transaction/verify/' . $reference);

            $body = $response->json();

            if (!$response->successful() || empty($body['data'])) {
                return $this->errorResponse('Payment verification failed.', 422);
            }

            $data = $body['data'];
            $status = $data['status'] ?? '';
            $amount = ($data['amount'] ?? 0) / 100;
            $paidAmount = ($data['paid_amount'] ?? $data['amount'] ?? 0) / 100;
            $fees = ($data['fees'] ?? 0) / 100;
            $metadata = $data['metadata'] ?? [];
            $userId = $metadata['user_id'] ?? null;

            if ($status === 'success' && $userId) {
                $this->creditWallet($userId, $paidAmount, $fees, $reference, $data);
            }

            return $this->successResponse([
                'status' => $status,
                'reference' => $reference,
                'amount' => $paidAmount,
            ], 'Payment ' . $status);
        } catch (\Exception $e) {
            Log::error('Paystack verification error', ['error' => $e->getMessage()]);
            return $this->errorResponse('Unable to verify payment.', 500);
        }
    }

    protected function creditWallet(string $userId, float $amount, float $fees, string $reference, array $data): void
    {
        DB::transaction(function () use ($userId, $amount, $fees, $reference, $data) {
            $payment = Payment::where('reference', $reference)->lockForUpdate()->first();

            if (!$payment || $payment->status === 'successful') {
                Log::info('Paystack: Payment already processed', ['reference' => $reference]);
                return;
            }

            $payment->update([
                'status' => 'successful',
                'fee' => $fees,
                'provider_reference' => $data['id'] ?? null,
                'provider_channel' => $data['channel'] ?? null,
                'provider_response' => $data,
                'paid_at' => now(),
            ]);

            $this->walletService->fundWallet($userId, (float) $payment->total, $reference, $data);
        });
    }
}
