<?php declare(strict_types=1);

namespace VRPaymentPayment\Core\Api\Refund\Controller;

use Psr\Log\LoggerInterface;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\Log\Package;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\{
  HttpFoundation\Request,
  HttpFoundation\Response,
  Routing\Attribute\Route,
};
use VRPaymentPayment\Core\{
  Api\Refund\Service\RefundService,
  Api\Transaction\Service\TransactionService,
  Settings\Service\SettingsService
};

/**
 * Class RefundController
 *
 * @package VRPaymentPayment\Core\Api\Refund\Controller
 *
 */
#[Package('sales-channel')]
#[Route(defaults: ['_routeScope' => ['api']])]
class RefundController extends AbstractController
{
    /**
     * @var \VRPaymentPayment\Core\Api\Refund\Service\RefundService
     */
    protected $refundService;
    
    /**
     * @var \VRPaymentPayment\Core\Settings\Service\SettingsService
     */
    protected $settingsService;
    
    /**
     * @var \Psr\Log\LoggerInterface
     */
    protected $logger;

    /**
     * @var \VRPaymentPayment\Core\Api\Transaction\Service\TransactionService
     */
    protected $transactionService;
    
    /**
     * RefundController constructor.
     *
     * @param \VRPaymentPayment\Core\Api\Refund\Service\RefundService $refundService
     * @param \VRPaymentPayment\Core\Settings\Service\SettingsService $settingsService
     * @param \VRPaymentPayment\Core\Api\Transaction\Service\TransactionService $transactionService
     */
    public function __construct(RefundService $refundService, SettingsService $settingsService, TransactionService $transactionService)
    {
        $this->settingsService = $settingsService;
        $this->refundService = $refundService;
        $this->transactionService = $transactionService;
    }
    
    /**
     * @param \Psr\Log\LoggerInterface $logger
     * @internal
     * @required
     *
     */
    public function setLogger(LoggerInterface $logger): void
    {
        $this->logger = $logger;
    }
    
    /**
     * @param \Symfony\Component\HttpFoundation\Request $request
     * @param \Shopware\Core\Framework\Context $context
     * @return \Symfony\Component\HttpFoundation\Response
     * @throws \VRPayment\Sdk\ApiException
     * @throws \VRPayment\Sdk\Http\ConnectionException
     * @throws \VRPayment\Sdk\VersioningException
     */
    #[Route("/api/_action/vrpayment/refund/create-refund/",
      name: "api.action.vrpayment.refund.create-refund",
      methods: ['POST'])]
    public function createRefund(Request $request, Context $context): Response
    {
        $salesChannelId = $request->request->get('salesChannelId');
        $transactionId = $request->request->get('transactionId');
        $quantity = (int)$request->request->get('quantity');
        $lineItemId = $request->request->get('lineItemId');

        if ($quantity === null || $quantity <= 0) {
            return new Response('refundQuantityZero', Response::HTTP_BAD_REQUEST);
        }        
        
        $settings = $this->settingsService->getSettings($salesChannelId);
        $apiClient = $settings->getApiClient();
        
        $transaction = $apiClient->getTransactionService()->read($settings->getSpaceId(), $transactionId);

        $maxQuantity = $this->refundService->getMaxRefundableQuantity($transaction, $context, $lineItemId);

        if ($quantity > $maxQuantity) {
            return new Response('refundExceedsQuantity', Response::HTTP_BAD_REQUEST);
        }

        $refund = $this->refundService->create($transaction, $context, $lineItemId, $quantity);

        if ($refund === null) {
            return new Response('Refund was not created. Please check the refund amound or if the item was not refunded before', Response::HTTP_BAD_REQUEST);
        }
        
        return new Response(null, Response::HTTP_NO_CONTENT);
    }
    
    /**
     * @param \Symfony\Component\HttpFoundation\Request $request
     * @param \Shopware\Core\Framework\Context $context
     * @return \Symfony\Component\HttpFoundation\Response
     * @throws \VRPayment\Sdk\ApiException
     * @throws \VRPayment\Sdk\Http\ConnectionException
     * @throws \VRPayment\Sdk\VersioningException
     */
    #[Route("/api/_action/vrpayment/refund/create-refund-by-amount/",
      name: "api.action.vrpayment.refund.create.refund.by.amount",
      methods: ['POST'])]
    public function createRefundByAmount(Request $request, Context $context): Response
    {
        $salesChannelId = $request->request->get('salesChannelId');
        $transactionId = $request->request->get('transactionId');
        $refundableAmount = $request->request->get('refundableAmount');

        if ($refundableAmount === null || $refundableAmount <= 0.0) {
            return new Response('refundAmountZero', Response::HTTP_BAD_REQUEST);
        }
        
        $settings = $this->settingsService->getSettings($salesChannelId);
        $apiClient = $settings->getApiClient();
        
        $transaction = $apiClient->getTransactionService()->read($settings->getSpaceId(), $transactionId);
        
        $completed = (float) $transaction->getCompletedAmount();
        $refunded  = (float) $transaction->getRefundedAmount();
        $maxRefund = round($completed - $refunded, 2);

        if ($refundableAmount > $maxRefund) {
            return new Response('refundExceedsAmount', Response::HTTP_BAD_REQUEST);
        }
        
        $refund = $this->refundService->createRefundByAmount($transaction, $refundableAmount, $context);
        
        if ($refund === null) {
            return new Response('refundExceedsAmount', Response::HTTP_BAD_REQUEST);
        }

        return new Response(null, Response::HTTP_NO_CONTENT);
    }
    
    /**
     * @param \Symfony\Component\HttpFoundation\Request $request
     * @param \Shopware\Core\Framework\Context $context
     * @return \Symfony\Component\HttpFoundation\Response
     * @throws \VRPayment\Sdk\ApiException
     * @throws \VRPayment\Sdk\Http\ConnectionException
     * @throws \VRPayment\Sdk\VersioningException
     */
    #[Route("/api/_action/vrpayment/refund/create-partial-refund/",
      name: "api.action.vrpayment.refund.create.partial.refund",
      methods: ['POST'])]
    public function createPartialRefund(Request $request, Context $context): Response
    {
        $salesChannelId = $request->request->get('salesChannelId');
        $transactionId = $request->request->get('transactionId');
        $refundableAmount = $request->request->get('refundableAmount');
        $lineItemId = $request->request->get('lineItemId');
        
        $settings = $this->settingsService->getSettings($salesChannelId);
        $apiClient = $settings->getApiClient();
        
        $transaction = $apiClient->getTransactionService()->read($settings->getSpaceId(), $transactionId);
        $this->refundService->createPartialRefund($transaction, $context, $lineItemId, $refundableAmount);
        
        return new Response(null, Response::HTTP_NO_CONTENT);
    }
}
