<?php

namespace KupShop\DaktelaBundle\Tests;

use KupShop\DaktelaBundle\Utils\DaktelaUpdater;
use KupShop\SalesBundle\Util\SalesUtil;
use Query\Operator;

class DaktelaUpdaterTest extends \DatabaseTestCase
{
    private DaktelaUpdater $daktelaUpdater;

    private SalesUtil $salesUtil;

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

        $this->salesUtil = $this->get(SalesUtil::class);

        $dbcfg = \Settings::getDefault();
        $dbcfg->saveValue('daktela', []);
        \Settings::clearCache(true);
    }

    /** @dataProvider data_testSales */
    public function testSales(array $config, ?string $expectedTicketID, ?string $expectedException = null): void
    {
        $dbcfg = \Settings::getDefault();

        $dbcfg->updateValue('daktela', $config);

        $daktelaUpdater = $this->mockDaktelaUpdater(
            // createContact response
            [200, '{"result": {"name": "wpj__wpj--cz"}}'],
            // createTicket response
            [201, '{"result": {"name": "TicketID"}}']
        );

        if ($expectedException) {
            $this->expectException($expectedException);
        }

        $daktelaUpdater->processSales([1]);

        $sale = $this->salesUtil->getSale(1);

        $this->assertEquals($expectedTicketID, $sale->data['daktela_id'] ?? null);
    }

    public function data_testSales(): iterable
    {
        yield 'Vytvoreni tiketu probehne v poradku' => [
            [
                'url' => 'https:\/\/oveckarna.daktela.com\/api\/v6\/',
                'user' => 'API_US3R',
                'url_params' => [
                    'accessToken' => '123',
                ],
                'sales' => [
                    'active' => 'Y',
                ],
                'cs' => [
                    'sales' => [
                        'title' => 'Prodejka č.',
                        'category' => 'categories_123',
                    ],
                ],
            ],
            'TicketID',
        ];

        yield 'Tiken se nevytvori, protoze neni vyplnena category' => [
            [
                'url' => 'https:\/\/oveckarna.daktela.com\/api\/v6\/',
                'user' => 'API_US3R',
                'url_params' => [
                    'accessToken' => '123',
                ],
                'sales' => [
                    'active' => 'Y',
                ],
                'cs' => [
                    'sales' => [
                        'title' => 'Prodejka č.',
                        'category' => '',
                    ],
                ],
            ],
            null,
        ];

        yield 'Vytvoreni tiketu skonci chybou, protoze neni nastaven config' => [[], null, \RuntimeException::class];
    }

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

        $dbcfg->updateValue('daktela', [
            'url' => 'https:\/\/wpj.daktela.com\/api\/v6\/',
            'user' => 'API_US3R',
            'url_params' => [
                'accessToken' => '123',
            ],
            'orders' => [
                'active' => 'Y',
            ],
            'reclamations' => [
                'active' => 'Y',
            ],
            'returns' => [
                'active' => 'Y',
            ],

            'cs' => [
                'orders' => [
                    'title' => 'Objednávka č.',
                    'category' => 'categories_123',
                ],
                'reclamations' => [
                    'title' => 'Reklamace č.',
                    'category' => 'category_456',
                ],
                'returns' => [
                    'title' => 'Vratka č.',
                    'category' => 'category_789',
                ],
            ],
            'en' => [
                'orders' => [
                    'title' => 'Order č.',
                    'category' => 'categories_123en',
                ],
                'reclamations' => [
                    'title' => 'Reclamation č.',
                    'category' => 'category_456en',
                ],
                'returns' => [
                    'title' => 'Return č.',
                    'category' => 'category_789en',
                ],
            ],
            'hu' => [
                'orders' => [
                    'title' => 'Order č.',
                    'category' => 'categories_123hu',
                ],
                'reclamations' => [
                    'title' => 'Reclamation č.',
                    'category' => 'category_456hu',
                ],
                'returns' => [
                    'title' => 'Return č.',
                    'category' => 'category_789hu',
                ],
            ],
            'ro' => [
                'orders' => [
                    'title' => 'Order č.',
                    'category' => 'categories_123r',
                ],
                'reclamations' => [
                    'title' => 'Reclamation č.',
                    'category' => 'category_456r',
                ],
                'returns' => [
                    'title' => 'Return č.',
                    'category' => 'category_789r',
                ],
            ],
            'sk' => [
                'orders' => [
                    'title' => 'Order č.',
                    'category' => '',
                ],
                'reclamations' => [
                    'title' => 'Reclamation č.',
                    'category' => '',
                ],
                'returns' => [
                    'title' => 'Return č.',
                    'category' => '',
                ],
            ],
        ]);

        // order with existing contact
        $request = $this->makeRequest([200, '{"result": {"name": "wpj__wpj--cz"}}'], [201, '{"result": {"name": "TicketID"}}']);

        $this->set(DaktelaUpdater::class, $request);
        $this->daktelaUpdater = $this->get(DaktelaUpdater::class);

        $this->daktelaUpdater->processOrders([203579]);
        $qb = sqlQueryBuilder()
            ->select('note_admin')
            ->from('orders')
            ->andWhere(Operator::equals(['id' => '203579']))
            ->execute()
            ->fetchAssociative();
        $note_admin = json_decode($qb['note_admin'], true);
        $this->assertEquals('TicketID', $note_admin['daktela_id']);

        // order w/t existing contact
        $request = $this->makeRequest([404, ''], [201, '{"result": {"name": "wpj__centrum--cz"}}'], [201, '{"result": {"name": "TicketID"}}']);

        $this->set(DaktelaUpdater::class, $request);
        $this->daktelaUpdater = $this->get(DaktelaUpdater::class);

        $this->daktelaUpdater->processOrders([203094]);
        $qb = sqlQueryBuilder()
            ->select('note_admin')
            ->from('orders')
            ->andWhere(Operator::equals(['id' => '203094']))
            ->execute()
            ->fetch();
        $note_admin = json_decode($qb['note_admin'], true);
        $this->assertEquals('TicketID', $note_admin['daktela_id']);

        // reclamations w/t existing contact
        $request = $this->makeRequest([404, ''], [201, '{"result": {"name": "wpj__centrum--cz"}}'], [201, '{"result": {"name": "TicketID-Reclamation"}}']);

        $this->set(DaktelaUpdater::class, $request);
        $this->daktelaUpdater = $this->get(DaktelaUpdater::class);

        $this->daktelaUpdater->processReclamations([451]);
        $qb = sqlQueryBuilder()
            ->select('data')
            ->from('reclamations')
            ->andWhere(Operator::equals(['id' => '451']))
            ->execute()
            ->fetch();
        $data = json_decode($qb['data'], true);
        $this->assertEquals('TicketID-Reclamation', $data['daktela_id']);

        // returns w/t existing contact
        $request = $this->makeRequest([404, ''], [201, '{"result": {"name": "wpj__centrum--cz"}}'], [201, '{"result": {"name": "TicketID-Vratka"}}']);

        $this->set(DaktelaUpdater::class, $request);
        $this->daktelaUpdater = $this->get(DaktelaUpdater::class);

        $this->daktelaUpdater->processReturns([8202]);
        $qb = sqlQueryBuilder()
            ->select('data')
            ->from('returns')
            ->andWhere(Operator::equals(['id' => '8202']))
            ->execute()
            ->fetch();
        $data = json_decode($qb['data'], true);
        $this->assertEquals('TicketID-Vratka', $data['daktela_id']);

        $dbcfg->updateValue('daktela', [
            'company' => [
                'active' => 'Y',
            ],
            'contacts' => [
                'active' => 'Y',
                'update' => 'Y',
            ],
        ]);

        // order with existing contact
        $request = $this->makeRequest(
            [200, '{"result": {"name": "CZ12345678"}}'],
            [200, '{"result": {"name": "CZ12345678"}}'],
            [200, '{"result": {"name": "CZ12345678"}}'],
            [200, '{"result": {"name": "wpj__wpj--cz"}}'],
            [201, '{"result": {"name": "TicketID"}}']);

        $this->set(DaktelaUpdater::class, $request);
        $this->daktelaUpdater = $this->get(DaktelaUpdater::class);

        $this->daktelaUpdater->processOrders([203581]);
        $qb = sqlQueryBuilder()
            ->select('note_admin')
            ->from('orders')
            ->andWhere(Operator::equals(['id' => '203581']))
            ->execute()
            ->fetchAssociative();
        $note_admin = json_decode($qb['note_admin'], true);
        $this->assertEquals('TicketID', $note_admin['daktela_id']);
    }

    private function mockDaktelaUpdater(array ...$response): DaktelaUpdater
    {
        $daktelaUpdater = $this->makeRequest(...$response);

        $this->set(DaktelaUpdater::class, $daktelaUpdater);

        return $this->daktelaUpdater = $this->get(DaktelaUpdater::class);
    }

    private function makeRequest(...$response): DaktelaUpdater
    {
        $request = $this->getMockBuilder(DaktelaUpdater::class)
             ->setMethods(['makeRequest'])
             ->getMock();
        $request->setLogger($this->get('logger'));
        $request->method('makeRequest')->will($this->onConsecutiveCalls(...$response));

        return $request;
    }

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