<?php

namespace App\Services\Payment\Methods;

use App\Exceptions\PaymentProcessingException;
use App\Models\PaymentMethod;
use App\Services\Payment\Payable;
use App\Services\Payment\Traits\PaymentServiceHelper;
use Illuminate\Http\Request;
use Razorpay\Api\Api;

class RazorpayService extends AbstractPayment
{
    use PaymentServiceHelper;

    private $razorpay_api_client = null;

    private $webhook_secret = null;

    public function pay(Payable $payable, $rest = [])
    {
        $this->setUp($payable->getMethod());

        $response = $this->makePayment($payable);

        $payment = $this->createPayment($payable);

        return [
            'payment' => $payment,
            'response' => [
                'payment_url' => $response,
            ],
        ];
    }

    public function handleWebhook(Request $request)
    {
        // Razorpay sends raw body + signature
        $payload = $request->getContent();
        $signature = $request->header('X-Razorpay-Signature');

        $data = json_decode($payload, true);

        $this->setUp($this->getPaymentMethod('razorpay'));

        $this->razorpay_api_client->verifyWebhookSignature(
            $payload,
            $signature,
            $this->webhook_secret
        );

        $paymentLink = data_get($data, 'payload.payment_link.entity');

        if (! $paymentLink) {
            throw new PaymentProcessingException(__('Invalid Razorpay webhook payload.'));
        }

        $paymentLinkId = data_get($paymentLink, 'id');
        $status = data_get($paymentLink, 'status');

        if ($status !== 'paid') {
            throw new PaymentProcessingException(__('Payment not completed.'));
        }

        return $paymentLinkId;
    }

    public function handleSuccess(Request $request)
    {
        $paymentLinkId = $request->reference;

        if (! $paymentLinkId) {
            throw new PaymentProcessingException(__('Invalid payment reference!'), 1);
        }

        // Fetch Razorpay Payment Link info
        $paymentInfo = $this->paymentInfo($paymentLinkId);

        return match ($paymentInfo['status']) {
            'paid' => [
                'status' => self::SUCCESS,
                'payment' => $this->getPaymentByPid($paymentLinkId),
            ],
            'expired' => [
                'status' => self::FAILED,
                'payment' => $this->getPaymentByPid($paymentLinkId),
            ],
            'cancelled' => [
                'status' => self::CANCELLED,
                'payment' => $this->getPaymentByPid($paymentLinkId),
            ],
            default => throw new PaymentProcessingException(__('Payment not completed.'), 1),
        };
    }

    public function handleFailed(Request $request)
    {
        throw new PaymentProcessingException('Payment failed');
    }

    private function paymentInfo(string $paymentLinkId)
    {
        $this->setUp($this->getPaymentMethod('razorpay'));

        $response = $this->razorpay_api_client->paymentLink->fetch($paymentLinkId);

        if (! $response || ! isset($response['id'])) {
            throw new PaymentProcessingException(__('Payment not found!'));
        }

        return [
            'id' => $response['id'],
            'status' => $response['status'],  // paid, expired, cancelled
        ];
    }

    private function makePayment(Payable $payable)
    {
        /**
         * @var \App\Models\User $user
         */
        $user = auth('client')->user();

        $data = [
            'amount' => intval($payable->getConvertedAmount() * 100), // amount in paise
            'currency' => $payable->getCurrency(),
            'accept_partial' => false,
            'first_min_partial_amount' => 200,
            'description' => 'Payment for order '.$payable->getPid(),
            'customer' => [
                'name' => $user->fullName ?? '',
                'email' => $user->email,
                'contact' => $user->phone,
            ],
            'notify' => [
                'sms' => $user->hasVerifiedPhone(),
                'email' => $user->hasVerifiedEmail(),
            ],
            'reminder_enable' => true,
            'notes' => [
                'note_key' => 'Payment link for order '.$payable->getPid(),
            ],
            'callback_url' => $this->getReturnUrl($payable->getMethod(), pid: $payable->getPid()),
            'callback_method' => 'get',
        ];

        $response = $this->razorpay_api_client->paymentLink->create($data);
        
        if (isset($response['short_url'])) {

            $payable->setGatewayId($response['id']);

            return $response['short_url'];
        }

        throw new PaymentProcessingException('Payment failed');
    }

    private function setUp(PaymentMethod $paymentMethod)
    {
        $config = $paymentMethod->meta;

        if (! isset($config['api_key']) || ! isset($config['secret_key']) || ! isset($config['webhook_secret'])) {
            throw new PaymentProcessingException(__('Something want wrong!'));
        }

        $this->webhook_secret = $config['webhook_secret'];

        $this->razorpay_api_client = new Api($config['api_key'], $config['secret_key']);
    }
}
