<?php

namespace KupShop\HeurekaCartBundle\Tests;

use KupShop\HeurekaCartBundle\Util\HeurekaUtil;
use KupShop\OrderingBundle\Util\Order\OrderInfo;
use PHPUnit\Framework\ExpectationFailedException;
use Symfony\Bundle\FrameworkBundle\Client;

class HeurekaCartTest extends \DatabaseTestCase
{
    /** @var Client */
    private $client;

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

        $settings = [
            'stores' => [3 => 54301],
            'payment_online_id' => 9,
            'payment_bank_id' => 11,
        ];
        $settingsUtil = $this->get(HeurekaUtil::class);
        $settingsUtil->setHeurekaCartOptions($settings);

        $this->client = $this->createClient();

        $this->test_data['products'] = [
            'products' => [
                0 => ['id' => '9', 'count' => 10],
                1 => ['id' => '6_17', 'count' => 10],
            ],
        ];
        $this->test_data['order_products'] = [
            'products' => [
                0 => ['id' => '9', 'count' => 1, 'price' => 200, 'totalPrice' => 200],
                1 => ['id' => '6_17', 'count' => 10, 'price' => 49, 'totalPrice' => 490,
                    'gifts' => [0 => ['name' => 'TĚLOVÉ MLÉKO POMELLATO 100 ML ZDARMA!', 'shopGiftId' => '6_18']],
                ],
            ],
        ];
    }

    public function testProductsAvailability()
    {
        $query_data = $this->test_data['products'];
        $query = http_build_query($query_data);
        $this->client->request('GET', '/_heurekaCart/products/availability?'.$query);

        $statusCode = $this->client->getResponse()->getStatusCode();
        $this->assertEquals(200, $statusCode);

        $exp_res = [
            'products' => [
                0 => [
                    'id' => '9',
                    'count' => 10,
                    'name' => 'DeWALT DCD780C2 aku vrtačka',
                    'available' => true,
                    'delivery' => 0,
                    'price' => 5000,
                    'priceTotal' => 50000,
                    'related' => [
                        ['title' => 'Doprava zdarma'],
                    ],
                ],
                1 => [
                    'id' => '6_17',
                    'count' => 5,
                    'name' => 'Salomon XR MISSION W Velikost: 40',
                    'available' => true,
                    'delivery' => 0,
                    'price' => 3000,
                    'priceTotal' => 15000,
                ],
            ],
            'priceSum' => 65000,
        ];
        $exp_res = json_encode($exp_res);

        $data = $this->client->getResponse()->getContent();

        $this->assertJsonStringEqualsJsonString($exp_res, $data);
    }

    public function testPaymentDelivery()
    {
        $query_data = $this->test_data['products'];
        $query = http_build_query($query_data);
        $this->client->request('GET', '/_heurekaCart/payment/delivery?'.$query);

        $statusCode = $this->client->getResponse()->getStatusCode();
        $this->assertEquals(200, $statusCode);

        $exp_res = [
            'transport' => [
                0 => [
                    'id' => 1,
                    'type' => 2,
                    'name' => 'Česká pošta - Balík do ruky',
                    'price' => 50,
                    'description' => '',
                ],
                1 => [
                    'id' => 3,
                    'type' => 1,
                    'name' => 'Osobní odběr',
                    'price' => 0,
                    'description' => '',
                    'store' => [
                        'type' => 1,
                        'id' => 54301,
                    ],
                ],
                2 => [
                    'id' => 11,
                    'type' => 9,
                    'name' => 'Zásilkovna',
                    'price' => 40,
                    'description' => '',
                    'store' => [
                        'type' => 3,
                        'id' => 2,
                    ],
                ],
            ],
            'payment' => [
                0 => [
                    'id' => 2,
                    'type' => 1,
                    'name' => 'Dobírkou',
                    'price' => 20,
                ],
                1 => [
                    'id' => 3,
                    'type' => 2,
                    'name' => 'Hotově',
                    'price' => 0,
                ],
                2 => [
                    'id' => 9,
                    'type' => 3,
                    'name' => 'Bezpečná on-line platba',
                    'price' => 0,
                ],
                3 => [
                    'id' => 11,
                    'type' => 4,
                    'name' => 'Bankovní převod',
                    'price' => 0,
                ],
            ],
            'binding' => [
                0 => [
                    'id' => 2,
                    'transportId' => 1,
                    'paymentId' => 2,
                ],
                1 => [
                    'id' => 23,
                    'transportId' => 1,
                    'paymentId' => 9,
                ],
                2 => [
                    'id' => 16,
                    'transportId' => 11,
                    'paymentId' => 2,
                ],
                3 => [
                    'id' => 24,
                    'transportId' => 11,
                    'paymentId' => 9,
                ],
                4 => [
                    'id' => 1,
                    'transportId' => 3,
                    'paymentId' => 3,
                ],
                5 => [
                    'id' => 26,
                    'transportId' => 3,
                    'paymentId' => 9,
                ],
                6 => [
                    'id' => 28,
                    'transportId' => 3,
                    'paymentId' => 11,
                ],
            ],
        ];

        $data = $this->client->getResponse()->getContent();
        $data = json_decode($data, true);

        $this->assertEquals($exp_res['binding'], $data['binding']);
    }

    public function testProductsErrors()
    {
        $query_data = $this->test_data['products'];
        $query_data['products'][0]['id'] = '999';
        $query_data['products'][1]['id'] = '6_12';
        $query = http_build_query($query_data);

        $exp_res = [
            'id' => -1,
            'msg' => 'Neexistující produkt/varianta v objednávce (id=999).',
        ];
        $exp_res = json_encode($exp_res);

        // products/availability
        $this->client->request('GET', '/_heurekaCart/products/availability?'.$query);

        $statusCode = $this->client->getResponse()->getStatusCode();
        $this->assertEquals(404, $statusCode);

        $data = $this->client->getResponse()->getContent();

        $this->assertJsonStringEqualsJsonString($exp_res, $data);

        // payment/delivery
        $this->client->request('GET', '/_heurekaCart/payment/delivery?'.$query);

        $statusCode = $this->client->getResponse()->getStatusCode();
        $this->assertEquals(404, $statusCode);

        $data = $this->client->getResponse()->getContent();

        $this->assertJsonStringEqualsJsonString($exp_res, $data);
    }

    public function testOrderStatus()
    {
        $query_data = [
            'order_id' => 1,
        ];
        $query = http_build_query($query_data);
        $this->client->request('GET', '/_heurekaCart/order/status?'.$query);

        $statusCode = $this->client->getResponse()->getStatusCode();
        $this->assertEquals(200, $statusCode);

        $exp_res = [
            'order_id' => 1,
            'status' => 1,
        ];
        $exp_res = json_encode($exp_res);

        $data = $this->client->getResponse()->getContent();

        $this->assertJsonStringEqualsJsonString($exp_res, $data);
    }

    public function testOrdersErrors()
    {
        $query_data = [
            'order_id' => 2, // existuje, ale neni Heureka objednavka
        ];
        $query = http_build_query($query_data);
        $this->client->request('GET', '/_heurekaCart/order/status?'.$query);

        $statusCode = $this->client->getResponse()->getStatusCode();
        $this->assertEquals(404, $statusCode);

        $exp_res = [
            'id' => -1,
            'msg' => 'Objednávka 2 neexistuje.',
        ];
        $exp_res = json_encode($exp_res);

        $data = $this->client->getResponse()->getContent();

        $this->assertJsonStringEqualsJsonString($exp_res, $data);

        $query_data = [
            'order_id' => 5, // neexistuje
        ];
        $query = http_build_query($query_data);
        $this->client->request('GET', '/_heurekaCart/order/status?'.$query);

        $statusCode = $this->client->getResponse()->getStatusCode();
        $this->assertEquals(404, $statusCode);

        $exp_res = [
            'id' => -1,
            'msg' => 'Objednávka 5 neexistuje.',
        ];
        $exp_res = json_encode($exp_res);

        $data = $this->client->getResponse()->getContent();

        $this->assertJsonStringEqualsJsonString($exp_res, $data);
    }

    public function testOrderSend()
    {
        $query_products = $this->test_data['order_products'];

        $query_data = '{"customer":{"firstname":"Test","lastname":"Heureka","email":"test.kosik@heureka.cz","phone":"+420 728 000 000","street":"Libereck\u00e1 5894\/430","city":"Jablonec","postCode":"839 02","state":"Česká republika","company":"Heureka&Special","ic":19384157,"dic":"CZ2991468300"},';
        $query_data .= '"deliveryAddress":{"firstname":"Test","lastname":"Heureka","street":"Libereck\u00e1 5894\/430","city":"Jablonec","postCode":"839 02","state":"CZ","company":"Heureka"},';
        $query_data .= '"note":"","deliveryId":1,"paymentId":9,"heureka_id":1611213902,"eLicence":false,"deliveryPrice":100,"paymentPrice":30,"productsTotalPrice":690,"paymentOnlineType":{"title":"Platba","id":6}}';

        $query = array_merge($query_products, json_decode($query_data, true));
        $this->client->request('POST', '/_heurekaCart/order/send', $query);

        $statusCode = $this->client->getResponse()->getStatusCode();
        $this->assertEquals(200, $statusCode);

        \DeliveryBase::clearCache();

        $id = sqlQueryBuilder()->select('MAX(id)')->from('orders')->execute()->fetchColumn();
        $order = new \Order($id);
        $order->createFromDB($id);
        $exp_res = [
            'order_id' => intval($id),
            'internal_id' => $order->order_no,
            'variableSymbol' => intval($order->order_no),
        ];
        $exp_res = json_encode($exp_res);

        $data = $this->client->getResponse()->getContent();

        $this->assertJsonStringEqualsJsonString($exp_res, $data);

        $this->assertEquals('CZ', $order->invoice_country);
        $this->assertEquals('CZ', $order->delivery_country);

        $this->assertEquals(1611213902, $order->getData('heureka_id'));
        $this->assertArrayHasKey('H', $order->getFlags());

        // "deliveryPrice":100,"paymentPrice":30,"productsTotalPrice":690
        $this->assertEquals(820, $order->total_price->asFloat());

        // delivery_type => 23 ('transportId' => 1, 'paymentId' => 9)
        $this->assertEquals(23, $order->id_delivery);
        $this->assertEquals('Bezpečná on-line platba (Heureka) - Česká pošta - Balík do ruky', $order->delivery_type);
        $this->assertEquals(130, $order->getDeliveryPrice()['value_with_vat']->asFloat());

        $this->assertEquals(OrderInfo::ORDER_SOURCE_DROPSHIP, $order->source);

        $items = $order->fetchItems();
        $this->assertNotEmpty($items);
        $this->assertEquals(4, count($items)); // 2 products + gift + delivery
        $product = reset($items);
        $this->assertEquals(9, $product['id_product']);
        $this->assertNull($product['id_variation']);
        $this->assertEquals(200, $product['piece_price']['value_with_vat']->value(2)->asFloat());
        $product = next($items);
        $this->assertEquals(6, $product['id_product']);
        $this->assertEquals(17, $product['id_variation']);
        $this->assertEquals(49, $product['piece_price']['value_with_vat']->asFloat());
        $product = next($items); // gift
        $this->assertEquals(6, $product['id_product']);
        $this->assertEquals(18, $product['id_variation']);
        $this->assertTrue($product['piece_price']['value_with_vat']->isZero());
        $product = next($items); // delivery
        $this->assertNull($product['id_product']);
        $this->assertNull($product['id_variation']);
        $this->assertEquals(130, $product['piece_price']['value_with_vat']->asFloat());
    }

    public function testOrderSendZasilkovna()
    {
        $query_products = $this->test_data['order_products'];

        $query_data = '{"customer":{"firstname":"Test","lastname":"Heureka","email":"test.kosik@heureka.cz","phone":"+420 728 000 000","street":"Libereck\u00e1 5894\/430","city":"Jablonec","postCode":"839 02","state":"Česká republika","company":"Heureka&Special","ic":19384157,"dic":"CZ2991468300"},';
        $query_data .= '"deliveryAddress":{"firstname":"Test","lastname":"Heureka","street":"Libereck\u00e1 5894\/430","city":"Jablonec","postCode":"839 02","state":"CZ","company":"Heureka","depotId":"12"},';
        $query_data .= '"note":"","deliveryId":11,"paymentId":9,"heureka_id":1611213902,"eLicence":false,"deliveryPrice":100,"paymentPrice":30,"productsTotalPrice":690,"paymentOnlineType":{"title":"Platba","id":6}}';

        $query = array_merge($query_products, json_decode($query_data, true));
        $this->client->request('POST', '/_heurekaCart/order/send', $query);

        $statusCode = $this->client->getResponse()->getStatusCode();
        $this->assertEquals(200, $statusCode);

        \DeliveryBase::clearCache();

        $id = sqlQueryBuilder()->select('MAX(id)')->from('orders')->execute()->fetchColumn();
        $order = new \Order($id);
        $order->createFromDB($id);

        $delivery = $order->getDeliveryType()->getDelivery();
        $deliveryData = $delivery->getInfo();

        $this->assertEquals('37001', $deliveryData['zip']);
        $this->assertEquals('C37-111-012', $deliveryData['labelRouting']);
        $this->assertEquals('CZ', $deliveryData['country']);
        $this->assertEquals('České Budějovice', $deliveryData['city']);
        $this->assertEquals('Rudolfovská 1', $deliveryData['street']);
    }

    public function testOrderCancel()
    {
        $query_data = [
            'order_id' => 1,
            'reason' => 5,
        ];
        $this->client->request('PUT', '/_heurekaCart/order/cancel', $query_data);

        $statusCode = $this->client->getResponse()->getStatusCode();
        $this->assertEquals(200, $statusCode);

        $exp_res = [
            'status' => true,
        ];
        $exp_res = json_encode($exp_res);

        $data = $this->client->getResponse()->getContent();

        $this->assertJsonStringEqualsJsonString($exp_res, $data);

        $order = new \Order(1);
        $order->createFromDB(1);
        $this->assertEquals(1, $order->status_storno);

        try {
            $this->testOrderStatus();
        } catch (ExpectationFailedException $exception) {
            $exp_res = [
                'order_id' => 1,
                'status' => 4, // storno z pohledu obchodu
            ];
            $exp_res = json_encode($exp_res);

            $data = $this->client->getResponse()->getContent();

            $this->assertJsonStringEqualsJsonString($exp_res, $data);

            try {
                $this->testPaymentStatus();
            } catch (ExpectationFailedException $exception) {
                $this->assertEquals('Failed asserting that 405 matches expected 200.', $exception->getMessage());
                $exp_res = [
                    'id' => -1,
                    'msg' => 'Objednávka 1 stornována.',
                ];
                $exp_res = json_encode($exp_res);

                $data = $this->client->getResponse()->getContent();

                $this->assertJsonStringEqualsJsonString($exp_res, $data);
            }
        }
    }

    public function testPaymentStatus()
    {
        $query_data = [
            'order_id' => 1,
            'status' => 1,
            'date' => '2019-04-20',
        ];
        $this->client->request('PUT', '/_heurekaCart/payment/status', $query_data);

        $statusCode = $this->client->getResponse()->getStatusCode();
        $this->assertEquals(200, $statusCode);

        $exp_res = [
            'status' => true,
        ];
        $exp_res = json_encode($exp_res);

        $data = $this->client->getResponse()->getContent();

        $this->assertJsonStringEqualsJsonString($exp_res, $data);

        $order = new \Order(1);
        $order->createFromDB(1);
        $this->assertEquals(1, $order->status_payed);

        $paid = $order->getPayments();
        $this->assertEquals(1060, $paid);

        $payments = $order->getPaymentsArray();
        $this->assertNotEmpty($payments);

        $payment = [
            'id_order' => 1,
            'price' => 1060,
            'date' => new \DateTime('2019-04-20'),
            'note' => 'Zaplaceno (stav platby z Heureky)',
            'status' => 0,
            'payment_data' => null,
            'admin' => null,
            'method' => 8, // METHOD_ONLINE = 8 - Online payment
            'payment_data_array' => [],
        ];
        unset($payments[0]['id']);
        $this->assertEquals($payment, $payments[0]);
        $this->assertEquals(1, $order->status); // status changed from 0 to 1 (payment config, default order_status_finished = 1)

        try {
            $this->testOrderCancel();
        } catch (ExpectationFailedException $exception) {
            $this->assertEquals('Failed asserting that 405 matches expected 200.', $exception->getMessage());
            $exp_res = [
                'id' => -1,
                'msg' => 'Objednávku 1 nelze stronovat, protože k ní existuje platba, která doposud nebyla vrácena.',
            ];
            $exp_res = json_encode($exp_res);

            $data = $this->client->getResponse()->getContent();

            $this->assertJsonStringEqualsJsonString($exp_res, $data);
        }
    }

    public function testHeurekaAPI()
    {
        $heurekaUtil = $this->get(HeurekaUtil::class);
        $heurekaAPI = $heurekaUtil->getHeurekaAPIUtil();

        // testovaci url
        $this->assertEquals('https://api.heureka.cz/cart/validate/1/', $heurekaAPI->getRequestUrl());

        $exp_res = [
            'status' => true,
        ];

        $order = new \Order(1);
        $order->createFromDB(1);
        $order->package_id = '1234567890';
        $query_data = [
            'order_id' => 1,
            'status' => 1,
            'transport' => ['tracking_url' => $order->replacePlaceholders('{ODKAZ_SLEDOVANI_BALIKU}')],
        ];
        $response = $heurekaAPI->putOrderStatus($query_data);
        // TODO: Revert me, temporarily commented-out because Heureka changed response. Possibly rewrite/mock to avoid network request?
        // $this->assertEquals($exp_res, $response);
    }

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