<?php

namespace App\Http\Controllers;

use App\Http\Requests\VerifyRazorpayPaymentRequest;
use App\Models\Payment;
use App\Services\Analytics\EngagementLogger;
use App\Services\Settings\SettingsService;
use Illuminate\Contracts\View\View;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Razorpay\Api\Api;
use Razorpay\Api\Errors\SignatureVerificationError;
use Throwable;

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

    public function checkout(Request $request): View
    {
        return view('payment.checkout', [
            'user' => $request->user(),
            'amountPaise' => $this->unlockAmountPaise(),
            'currency' => $this->currency(),
            'razorpayKey' => $this->razorpayKey(),
        ]);
    }

    public function createOrder(Request $request): JsonResponse
    {
        abort_unless($this->isRazorpayConfigured(), 503, 'Razorpay is not configured.');
        abort_if($this->unlockAmountPaise() <= 0, 503, 'Unlock amount is not configured.');

        $user = $request->user();

        abort_if($user->hasUnlockedAccess(), 409, 'Access is already unlocked.');

        try {
            $order = $this->razorpay()->order->create([
                'amount' => $this->unlockAmountPaise(),
                'currency' => $this->currency(),
                'receipt' => 'unlock_'.$user->id.'_'.Str::random(16),
                'notes' => [
                    'user_id' => (string) $user->id,
                    'email' => $user->email,
                    'purpose' => 'remote_job_unlock',
                ],
            ]);

            $payload = $order->toArray();

            $payment = DB::transaction(fn (): Payment => Payment::query()->create([
                'user_id' => $user->id,
                'provider' => 'razorpay',
                'razorpay_order_id' => $payload['id'],
                'amount_paise' => $this->unlockAmountPaise(),
                'currency' => $this->currency(),
                'status' => Payment::STATUS_CREATED,
                'order_payload' => $payload,
            ]));

            return response()->json([
                'payment_id' => $payment->id,
                'order_id' => $payment->razorpay_order_id,
                'amount' => $payment->amount_paise,
                'currency' => $payment->currency,
                'key' => $this->razorpayKey(),
                'name' => $this->settings->get('general.application_name', config('app.name')),
                'description' => 'Remote job matching unlock',
                'prefill' => [
                    'name' => $user->name,
                    'email' => $user->email,
                ],
            ], 201);
        } catch (Throwable $exception) {
            report($exception);

            return response()->json([
                'message' => 'Unable to create a payment order right now.',
            ], 503);
        }
    }

    public function verify(VerifyRazorpayPaymentRequest $request, EngagementLogger $engagementLogger): JsonResponse
    {
        abort_unless($this->isRazorpayConfigured(), 503, 'Razorpay is not configured.');

        $validated = $request->validated();
        $user = $request->user();

        $payment = Payment::query()
            ->where('user_id', $user->id)
            ->where('razorpay_order_id', $validated['razorpay_order_id'])
            ->firstOrFail();

        try {
            $this->razorpay()->utility->verifyPaymentSignature($validated);

            DB::transaction(function () use ($payment, $user, $validated): void {
                $payment->forceFill([
                    'razorpay_payment_id' => $validated['razorpay_payment_id'],
                    'razorpay_signature' => $validated['razorpay_signature'],
                    'status' => Payment::STATUS_CAPTURED,
                    'verified_at' => now(),
                    'unlocked_at' => now(),
                ])->save();

                $user->forceFill([
                    'access_unlocked_at' => now(),
                ])->save();
            });

            $engagementLogger->record(
                $user,
                'payment_verified',
                'Verified paid access payment.',
                [
                    'payment_id' => $payment->id,
                    'amount_paise' => $payment->amount_paise,
                    'currency' => $payment->currency,
                ],
                $payment,
            );

            return response()->json([
                'message' => 'Payment verified.',
                'redirect_url' => $this->settings->get('payment.payment_success_redirect_url') ?: route('resume.show'),
            ]);
        } catch (SignatureVerificationError $exception) {
            report($exception);

            $payment->forceFill([
                'razorpay_payment_id' => $validated['razorpay_payment_id'],
                'razorpay_signature' => $validated['razorpay_signature'],
                'status' => Payment::STATUS_FAILED,
                'failed_at' => now(),
            ])->save();

            return response()->json([
                'message' => 'Payment verification failed.',
            ], 422);
        }
    }

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

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

    private function unlockAmountPaise(): int
    {
        $unlockPrice = $this->settings->get('payment.unlock_price');

        if (is_numeric($unlockPrice) && (float) $unlockPrice > 0) {
            return (int) round(((float) $unlockPrice) * 100);
        }

        return (int) config('services.razorpay.unlock_amount_paise', 0);
    }

    private function currency(): string
    {
        return strtoupper((string) $this->settings->get('payment.default_currency', config('services.razorpay.currency', 'INR')));
    }

    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'));
    }
}
