<?php

declare(strict_types=1);

namespace Flutterwave\Service;

use Flutterwave\Contract\ConfigInterface;
use Flutterwave\EventHandlers\TransactionVerificationEventHandler;
use Flutterwave\Traits\ApiOperations\Post;
use Unirest\Exception;

class Transactions extends Service
{
    use Post;
    public const ENDPOINT = 'transactions';
    public const REFUND_PATH = '/:id'.'/refund';
    public const MULTI_REFUND_ENDPOINT = '/refunds';
    public const REFUND_DETAILS_PATH = 'refunds/:id';
    public const TRANSACTION_FEE_PATH = '/fee';
    public const RESEND_FAILED_HOOKS_PATH = '/:id/resend-hook';
    public const TRANSACTION_TIMELINE_PATH = '/:id/events';
    public const VALIDATE_TRANSACTION = 'validate-charge';
    private static string $name = 'transactions';
    private string $end_point;
    private array $payment_type = [
        'card','debit_ng_account','mobilemoney','bank_transfer', 'ach_payment',
    ];
    private TransactionVerificationEventHandler $eventHandler;

    public function __construct(?ConfigInterface $config = null)
    {
        parent::__construct($config);
        $this->baseUrl = $this->config::BASE_URL;
        $this->end_point = Transactions::ENDPOINT;
        $this->eventHandler = new TransactionVerificationEventHandler();
    }

    /**
     * @throws Exception
     */
    public function verify(string $transactionId): \stdClass
    {
        $this->checkTransactionId($transactionId);
        $this->logger->notice('Transaction Service::Verifying Transaction...'.$transactionId);
        TransactionVerificationEventHandler::startRecording();
        $response = $this->request(
            null,
            'GET',
            self::ENDPOINT."/{$transactionId}/verify",
        );
        TransactionVerificationEventHandler::setResponseTime();

        return $response;
    }

    /**
     * @throws Exception
     */
    public function verifyWithTxref(string $tx_ref): \stdClass
    {
        $this->logger->notice('Transaction Service::Verifying Transaction...'.$tx_ref);
        TransactionVerificationEventHandler::startRecording();
        $response = $this->request(
            null,
            'GET',
            self::ENDPOINT.'/verify_by_reference?tx_ref='.$tx_ref,
        );
        TransactionVerificationEventHandler::setResponseTime();
        return $response;
    }

    /**
     * @throws Exception
     */
    public function refund(string $trasanctionId): \stdClass
    {
        $this->checkTransactionId($trasanctionId);
        $this->logger->notice("Transaction Service::Refunding Transaction...{$trasanctionId}");
        TransactionVerificationEventHandler::startRecording();
        $response = $this->request(
            null,
            'GET',
            self::ENDPOINT."/{$trasanctionId}/refund",
        );
        TransactionVerificationEventHandler::setResponseTime();
        return $response;
    }

    /**
     * @throws Exception
     */
    public function getAllTransactions(): \stdClass
    {
        $this->logger->notice('Transaction Service::Retrieving all Transaction for Merchant');
        TransactionVerificationEventHandler::startRecording();
        $response = $this->request(
            null,
            'GET',
            self::ENDPOINT,
        );
        TransactionVerificationEventHandler::setResponseTime();
        return $response;
    }

    /**
     * @throws Exception
     */
    public function getRefundInfo(string $trasanctionId): \stdClass
    {
        $this->checkTransactionId($trasanctionId);
        $this->logger->notice("Transaction Service::Retrieving refund:Transactionid => {$trasanctionId}");
        TransactionVerificationEventHandler::startRecording();
        $response = $this->request(
            null,
            'GET',
            "refunds/{$trasanctionId}",
        );
        TransactionVerificationEventHandler::setResponseTime();
        return $response;
    }

    /**
     * @throws Exception
     */
    public function getTransactionFee(string $amount, string $currency = 'NGN', string $payment_type = 'card'): \stdClass
    {
        if (! $amount) {
            $msg = 'Please pass a valid amount';
            $this->logger->warning($msg);
            throw new \InvalidArgumentException($msg);
        }
        $data = [
            'amount' => $amount,
            'currency' => $currency,
        ];

        if (! isset($this->payment_type[$payment_type])) {
            $logData = json_encode($this->payment_type);
            $msg = "Please pass a valid Payment Type: options::{$logData}";
            $this->logger->warning($msg);
            throw new \InvalidArgumentException($msg);
        }

        $data['payment_type'] = $payment_type;

        $query = http_build_query($data);

        $logData = json_encode($data);
        $this->logger->notice("Transaction Service::Retrieving Transaction Fee: Util => {$logData}");
        TransactionVerificationEventHandler::startRecording();
        $response = $this->request(
            null,
            'GET',
            self::ENDPOINT."/fee?{$query}",
        );
        TransactionVerificationEventHandler::setResponseTime();
        return $response;
    }

    /**
     * @throws Exception
     */
    public function resendFailedHooks(string $transactionId): \stdClass
    {
        $this->checkTransactionId($transactionId);
        $this->logger->notice("Transaction Service::Resending Transaction Webhook: TransactionId => {$transactionId}");
        TransactionVerificationEventHandler::startRecording();
        $response = $this->request(
            null,
            'GET',
            self::ENDPOINT."/{$transactionId}/resend-hook",
        );
        TransactionVerificationEventHandler::setResponseTime();
        return $response;
    }

    /**
     * @throws Exception
     */
    public function retrieveTimeline(string $transactionId): \stdClass
    {
        $this->checkTransactionId($transactionId);
        $this->logger->notice("Transaction Service::Retrieving Transaction Timeline: TransactionId => {$transactionId}");
        TransactionVerificationEventHandler::startRecording();
        $response = $this->request(
            null,
            'GET',
            self::ENDPOINT."/{$transactionId}/timeline",
        );
        TransactionVerificationEventHandler::setResponseTime();
        return $response;
    }

    /**
     * @throws Exception
     */
    public function validate(string $otp, string $flw_ref): \stdClass
    {
        $logData = json_encode(
            [
                'flw_ref' => $flw_ref,
                'date' => date('mm-dd-YYYY h:i:s'),
            ]
        );

        $this->logger->notice('Transaction Service::Validating Transaction ...'.$logData);

        $data = [
            'otp' => $otp,
            'flw_ref' => $flw_ref,
//            "type" => "card" //default would be card
        ];

        return $this->request(
            $data,
            'POST',
            self::VALIDATE_TRANSACTION,
        );
    }

    public function getName(): string
    {
        return self::$name;
    }
}
