<?php

namespace KupShop\SKEETBundle\Tests;

use KupShop\GraphQLBundle\ApiAdmin\Types\Order\OrderItem as OrderItemType;
use KupShop\KupShopBundle\Context\PosContext;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\Contexts;
use KupShop\OrderingBundle\Entity\Order\OrderItem;
use KupShop\POSBundle\Util\PosOrderUtil;
use KupShop\POSBundle\Util\PosPaymentUtil;
use KupShop\SKEETBundle\Util\SKEETWorker;
use NineDigit\eKasa\Client\AccessTokenSource;
use NineDigit\eKasa\Client\ApiClient;
use NineDigit\eKasa\Client\ApiClientAuthenticationAccessTokenOptions;
use NineDigit\eKasa\Client\ApiClientAuthenticationOptions;
use NineDigit\eKasa\Client\ApiClientOptions;
use NineDigit\eKasa\Client\EKasaEnvironment;
use NineDigit\eKasa\Client\Models\Registrations\Receipts\ReceiptRegistrationResultReceiptDataDto;
use NineDigit\eKasa\Client\Models\Registrations\Receipts\RegisterReceiptResultDto;
use NineDigit\eKasa\Client\Models\Registrations\Receipts\RegisterReceiptResultResponseDto;
use Query\Operator;
use Symfony\Polyfill\Intl\Icu\Exception\NotImplementedException;

class SKEETTest extends \DatabaseTestCase
{
    private PosPaymentUtil $posPaymentUtil;
    private PosOrderUtil $posOrderUtil;

    protected function setUp(): void
    {
        parent::setUp();

        $this->removeModule(\Modules::EET);

        $dbcfg = \Settings::getDefault();
        $dbcfg->skeet = [
            'active' => 'Y',
            'subdomain' => 'jhgfdsadfgbnhmhgfdsdfgbgfds',
            'access_token' => 'fgbgfdsfgbdfgdbfngfdsfgdfbggbfd',
            'orp' => '12324484956598485485',
            'testing' => 'testing',
            'pos_invoice_payment_relation' => '1',
        ];

        $this->posPaymentUtil = ServiceContainer::getService(PosPaymentUtil::class);
        $this->posOrderUtil = ServiceContainer::getService(PosOrderUtil::class);
    }

    public function testCreateInstanceFromOptions()
    {
        $dbcfg = \Settings::getDefault();

        $url = EKasaEnvironment::exposePlayground($dbcfg->skeet['subdomain']);
        $accessTokenSource = AccessTokenSource::queryString($dbcfg->skeet['access_token']);
        $accessTokenOptions = new ApiClientAuthenticationAccessTokenOptions($dbcfg->skeet['access_token'], $accessTokenSource);
        $authentication = new ApiClientAuthenticationOptions(null, $accessTokenOptions);
        $clientOptions = new ApiClientOptions($url, $authentication);

        $throws = false;
        try {
            new ApiClient($clientOptions);
        } catch (\Exception $e) {
            $throws = true;
        }

        $this->assertFalse($throws);
    }

    public function testProcessPayment()
    {
        Contexts::get(PosContext::class)->activate(2);
        $this->set(SKEETWorker::class, new SKEETWorkerMock($this->mockSendFunction(...), $this->mockReceiveFunction(...)));

        // Zaplacení testovací objednávky
        $this->assertTableRowCount('sk_eet_payment', 0);

        $order = new \Order();
        $order->createFromDB(14011);
        $order->fetchItems();

        // Uložení objednávky - celá platba
        $response = $this->posOrderUtil->recalculateAndUpdateOrder(
            [
                new OrderItemType(new OrderItem([
                    'idProduct' => 4057,
                    'idVariation' => null,
                    'pieces' => 1,
                    'vat' => '23',
                    'priceWithoutVat' => 65.8537,
                    'discount' => null,
                    'idOrderItem' => 33923,
                ])),
            ],
            [],
            [],
            [],
            null,
            null,
            $order->id,
            true,
            'CASH',
            $order->total_price,
            true
        );

        // Potvrzení platby
        $this->posPaymentUtil->confirmPayment($order->id, $response->getOrderInfo()->getUuidPayment(), $response->getOrderInfo()->getRemainingPayment(), 'CASH');

        $this->assertTableRowCount('sk_eet_payment', 1);

        $data = sqlQueryBuilder()
            ->select('uid')
            ->from('sk_eet_payment')
            ->where('id_order = :order_id')
            ->setParameter('order_id', $order->id)
            ->execute()
            ->fetchAssociative();

        $this->assertEquals('987654321', $data['uid']);
    }

    public function testPaymentOfTheInvoice()
    {
        $this->set(SKEETWorker::class, new SKEETWorkerMock($this->mockSendFunction(...), $this->mockReceiveFunction(...)));
        $SKEETWorker = $this->get(SKEETWorker::class);

        // Nastavím v administraci na kterou pokladnu se má platba napárovat
        \Settings::getDefault()->skeet['pos_invoice_payment_relation'] = 2;

        $order = new \Order();
        $order->createFromDB(14011);

        // Nasimuluju "vygenerování" faktury
        $order->invoice_no = 'TEST_INVOICE_NO';

        // Simuluju zaplacení z akce
        $idPayment = $order->insertPayment('81', 'Úhrada faktury - HOTOVOST', null, true, \Payment::METHOD_EET_INVOICE_CASH);

        $this->assertTableRowCount('sk_eet_payment', 0);

        $SKEETWorker->setOrder($order);
        $SKEETWorker->processPaymentOfTheInvoice([
            'method' => \Payment::METHOD_EET_INVOICE_CASH,
            'price' => '81',
            'id' => $idPayment,
        ]);

        $this->assertTableRowCount('sk_eet_payment', 1);

        $row = sqlQueryBuilder()
            ->select('*')
            ->from('sk_eet_payment')
            ->andWhere(Operator::equals(['id_payment' => $idPayment]))
            ->execute()
            ->fetchAssociative();

        $this->assertEquals('987654321', $row['uid']);
    }

    public function mockSendFunction()
    {
        throw new NotImplementedException('Not implemented');
    }

    public function mockReceiveFunction()
    {
        $dataDto = new ReceiptRegistrationResultReceiptDataDto();
        $dataDto->id = '987654321';

        $responseDto = new RegisterReceiptResultResponseDto();
        $responseDto->data = $dataDto;

        $resultDto = new RegisterReceiptResultDto();
        $resultDto->response = $responseDto;
        $resultDto->isSuccessful = true;

        return $resultDto;
    }

    public function getDataSet()
    {
        return $this->getJsonDataSetFromFile();
    }
}
