<?php

namespace App\Services\Payment;

use App\Enums\PaymentStatusEnum;
use App\Enums\PaymentTypeEnum;
use App\Models\PaymentMethod;
use App\Models\User;
use App\Services\Payment\Interfaces\PaymentInterface;

class Payable implements PaymentInterface
{
    protected $amount;

    protected $currency;

    protected $charge;

    protected $payable;

    protected $method;

    protected $pid;

    protected $currencyRate;

    protected $gatewayId;

    protected $convertedAmount;

    protected PaymentTypeEnum $type;

    public function initialize(PaymentMethod $method, float $amount, float $charge, string $currency, PaymentTypeEnum $type = PaymentTypeEnum::DEPOSIT)
    {
        $this->amount = $amount;
        $this->currency = $currency;
        $this->method = $method;
        $this->type = $type;

        $pending_payment = $this->getPendingPayment();
        $this->pid = $pending_payment?->payment_identifier ?: $this->generatePid();

        $this->charge = $charge;

        $this->currencyRate = currencyRate($currency);

        $this->payable = $amount + $this->charge;

        $this->convertedAmount = $this->payable * $this->currencyRate;

        return $this;
    }

    public function getPendingPayment()
    {
        /**
         * @var User $user
         */
        $user = auth('client')->user();

        return $user->payments()->where('status', PaymentStatusEnum::PENDING)->first();
    }

    public function generatePid(): string
    {
        $this->pid = uniqid('pid_');

        return $this->pid;
    }

    /**
     * Pay the payable
     *
     * @return array [
     *               'payment' => \App\Models\Payment,
     *               'response' => [
     *               'payment_url' => string
     *               ]
     *               ]
     */
    public function pay(?array $rest = [])
    {
        $service = $this->getService($this->method->slug);

        if (! $service) {
            throw new \Exception('Payment method not found');
        }

        return $service->pay($this, $rest);
    }

    public function getAmount(): float
    {
        return $this->amount;
    }

    public function getConvertedAmount(): string
    {
        return (string) number_format($this->convertedAmount, 2, '.', '');
    }

    public function getCurrency(): string
    {
        return $this->currency;
    }

    public function getCharge(): float
    {
        return $this->charge;
    }

    public function getPayableAmount(): float
    {
        return $this->payable;
    }

    public function getMethod(): PaymentMethod
    {
        return $this->method;
    }

    public function getPid(): string
    {
        return $this->pid;
    }

    public function getType(): PaymentTypeEnum
    {
        return $this->type;
    }

    public function getGatewayId(): ?string
    {
        return $this->gatewayId;
    }

    public function setGatewayId(string $gatewayId): void
    {
        $this->gatewayId = $gatewayId;
    }

    public function getCurrencyRate(): float
    {
        return $this->currencyRate;
    }

    public function getService(?string $slug)
    {
        if (! $slug) {
            return null;
        }

        return match ($slug) {
            'amazon' => new \App\Services\Payment\Methods\AmazonService,
            'paypal' => new \App\Services\Payment\Methods\PayPalService,
            'stripe' => new \App\Services\Payment\Methods\StripeService,
            'flutterwave' => new \App\Services\Payment\Methods\FlutterwaveService,
            'mollie' => new \App\Services\Payment\Methods\MollieService,
            'paystack' => new \App\Services\Payment\Methods\PaystackService,
            'skrill' => new \App\Services\Payment\Methods\SkrillService,
            'braintree' => new \App\Services\Payment\Methods\BraintreeService,
            'toyyibpay' => new \App\Services\Payment\Methods\ToyyibpayService,
            'gocardless' => new \App\Services\Payment\Methods\GoCardlessService,
            'payu' => new \App\Services\Payment\Methods\PayUService,
            'square' => new \App\Services\Payment\Methods\SquareService,
            'vrpay' => new \App\Services\Payment\Methods\VRPayService,
            'sslcommerz' => new \App\Services\Payment\Methods\SSLCommerzService,
            'amarpay' => new \App\Services\Payment\Methods\AmarpayService,
            'cryptomus' => new \App\Services\Payment\Methods\CryptomusService,
            'razorpay' => new \App\Services\Payment\Methods\RazorpayService,
            default => new \App\Services\Payment\Methods\ManualPaymentService,
        };
    }
}
