<?php

namespace App\Modules\HalkbankOnlinePayment\Repositories;

use App\Modules\Makeable;
use App\Modules\OnlinePayment\Contracts\PaymentProviderContract;
use Exception;
use GuzzleHttp\Psr7\Response as GuzzleResponse;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class HalkbankOnlinePaymentRepository implements PaymentProviderContract
{
    use Makeable;

    public function __construct(
        protected string $username = '',
        protected string $password = '',
        protected int|float|string $amount = '',
        protected int|string $orderNumber = '',
        protected string $returnUrl = '',
        protected string $description = '',
    ) {
        $this->username = config()->string('module.halkbank-online-payment.username');
        $this->password = config()->string('module.halkbank-online-payment.password');
        $this->returnUrl = config()->string('module.halkbank-online-payment.returnUrl');
        $this->orderNumber = $this->generateOrderNumber();
    }

    /**
     * Send request to gatewat
     */
    public function sendRequest(): Response
    {
        try {
            $paymentResponse = Http::get('https://mpi.gov.tm/payment/rest/register.do', [
                'orderNumber' => $this->orderNumber,
                'amount' => $this->formatAmount($this->amount),
                'currency' => 934,
                'language' => 'ru',
                'userName' => $this->username,
                'password' => $this->password,
                'returnUrl' => $this->returnUrl,
                'pageView' => 'DESKTOP',
                'description' => $this->description,
            ]);
        } catch (Exception $e) {
            Config::set('logging.channels.halkbank_payment_error', [
                'driver' => 'single',
                'path' => storage_path('logs/halkbank_payment_error.log'),
                'level' => 'debug',
            ]);

            Log::channel('halkbank_payment_error')
                ->error('Payment error', [
                    'response' => [
                        'error' => $e->getMessage(),
                        'file_line' => $e->getFile().':'.$e->getLine(),
                    ],
                ]);

            return new Response(new GuzzleResponse(
                503,
                ['Content-Type' => 'application/json'],
                sprintf('{"errorCode":"1","errorMessage":"%s"}', $e->getMessage())
            ));
        }

        return $paymentResponse;
    }

    /**
     * Format amount to match requirements
     */
    public function formatAmount(int|float|string $amount): string
    {
        return number_format(floatval($amount), 2, '', '');
    }

    /**
     * Get username
     */
    public function username(): string
    {
        return $this->username;
    }

    /**
     * Get password
     */
    public function password(): string
    {
        return $this->password;
    }

    /**
     * Get amount
     */
    public function amount(): int|float|string
    {
        return $this->amount;
    }

    /**
     * Get order number
     */
    public function orderNumber(): int|string
    {
        return $this->orderNumber;
    }

    /**
     * Set return url
     */
    public function returnUrl(): string
    {
        return $this->returnUrl;
    }

    /**
     * Set description
     */
    public function description(): string
    {
        return $this->description;
    }

    /**
     * Set username
     */
    public function setUsername(string $username): self
    {
        $this->username = $username;

        return $this;
    }

    /**
     * Set password
     */
    public function setPassword(string $password): self
    {
        $this->password = $password;

        return $this;
    }

    /**
     * Set amoutn
     */
    public function setAmount(int|float|string $amount): self
    {
        $this->amount = $amount;

        return $this;
    }

    /**
     * Set order number
     */
    public function setOrderNumber(int|string $orderNumber): self
    {
        $this->orderNumber = $orderNumber;

        return $this;
    }

    /**
     * Set return url
     */
    public function setReturnUrl(string $returnUrl): self
    {
        $this->returnUrl = $returnUrl;

        return $this;
    }

    /**
     * Set description
     */
    public function setDescription(string $description): self
    {
        $this->description = $description;

        return $this;
    }

    /**
     * Generate order number for payment
     */
    public function generateOrderNumber(): string
    {
        return date('dmyHis');
    }
}
