<?php

namespace Shop\Application\Payment;


use Shop\Application\Payment\CreateTransaction\CreateTransactionCommand;
use Shop\Application\Payment\CreateTransaction\TransactionResultCode;
use Shop\Application\Payment\Exceptions\TransactionNotFoundException;
use Shop\Domain\CustomerOrder\Contracts\CustomerOrderEntityInterface;
use Shop\Domain\PaymentTransaction\Contracts\PaymentTransactionEntityInterface;
use Shop\Infrastructure\Models\PaymentTransaction\PaymentTransactionQuery;
use Shop\Infrastructure\Repositories\PaymentTransaction\PaymentTransactionCriteria;
use Shop\Infrastructure\Repositories\PaymentTransaction\PaymentTransactionRepository;
use spaceonfire\CommandBus\CommandBus;

/**
 * Class PaymentService
 * @package Shop\Application\Payment
 */
class PaymentService
{
    protected $transactionRepository;
    protected $commandBus;

    /**
     * PaymentService constructor.
     * @param PaymentTransactionRepository $transactionRepository
     * @param CommandBus $commandBus
     */
    public function __construct(PaymentTransactionRepository $transactionRepository, CommandBus $commandBus)
    {
        $this->transactionRepository = $transactionRepository;
        $this->commandBus = $commandBus;
    }

    /**
     * @param string $code
     * @return PaymentTransactionEntityInterface
     * @throws \Repo\Concrete\Exceptions\Collection
     */
    public function getTransactionByOrderCode(string $code): PaymentTransactionEntityInterface
    {

        $trans = $this->transactionRepository->findByCriteria(
            PaymentTransactionCriteria::create()->setFilterByCode($code)
        );

        if (!$tran = $trans->current()) {
            throw new TransactionNotFoundException('payment transaction not found by code ' . $code);
        }

        return $tran;
    }

    /**
     * @param PaymentTransactionEntityInterface $trans
     */
    public function confirmedTransaction(PaymentTransactionEntityInterface $trans): void
    {
        $trans->setConfirmed('Y');
        $this->transactionRepository->save($trans);
    }

    /**
     * @param PaymentTransactionEntityInterface $trans
     */
    public function falseTransaction(PaymentTransactionEntityInterface $trans): void
    {
        $trans->setResult('error');
        $this->transactionRepository->save($trans);
    }

    /**
     * @param CustomerOrderEntityInterface $order
     * @return string
     */
    public function createTransaction(CustomerOrderEntityInterface $order): string
    {
        $result = new TransactionResultCode();
        $this->commandBus->handle(new CreateTransactionCommand($order, $result));
        return $result->getCode();
    }

    /**
     * @param string $code
     * @return PaymentTransactionEntityInterface
     */
    public function getConfirmedTransaction(string $code): PaymentTransactionEntityInterface
    {
        if (!$trans = PaymentTransactionQuery::create()
            ->filterByCode($code)
            ->filterByConfirmed('Y')
            ->findOne()) {
            throw new TransactionNotFoundException('not found by code ' . $code);
        }

        return $trans;
    }

}