<?php

declare(strict_types=1);

namespace External\PompoBundle\Util\Import;

use External\PompoBundle\DRS\Synchronizer\POSOrderSynchronizer;
use External\PompoBundle\DRS\Util\DRSApi;
use Query\Operator;

class PompoImport
{
    private DRSApi $drsApi;
    private POSOrderSynchronizer $posOrderSynchronizer;

    private ?\Closure $writeLineCallback = null;

    public function __construct(DRSApi $drsApi, POSOrderSynchronizer $posOrderSynchronizer)
    {
        $this->drsApi = $drsApi;
        $this->posOrderSynchronizer = $posOrderSynchronizer;
    }

    public function setWriteLineCallback(callable $writeLineCallback): void
    {
        $this->writeLineCallback = $writeLineCallback;
    }

    public function importDRSCoupons(): void
    {
        $couponsMap = [
            'Poukaz za body - NaturaMed' => 95,
            'Poukaz za body - Sleva 500 Kč' => 69,
            'Poukaz za body - TOBOGA' => 65,
            'Poukaz za body - Dinopark Ostrava' => 61,
            'Poukaz za body - Dinopark Praha' => 62,
            'Poukaz za body - Fruitisimo' => 116,
            'Poukaz za body - RAK' => 158,
            'Poukaz za body - Aqualand Moravia' => 59,
            'Poukaz za body - Chocotopia' => 160,
            'Poukaz za body - POEX' => 161,
            'Poukaz za body - Sleva 200 Kč' => 94,
            'Voucher - Narozeniny' => 159,
            'Poukaz za body - Sleva 250 Kč' => 68,
            'Poukaz za body - Sleva 100 Kč' => 67,
            'Poukaz za body - Sleva 50 Kč' => 93,
            'Poukaz za body - IQLANDIA' => 126,
            'Poukaz za body - Terezia' => 98,
            'Voucher - Narozeniny - Kopie' => 159,
            'Poukaz za body - Dinopark' => 60,
        ];

        $count = 0;
        foreach ($this->drsApi->getUsersCoupons() as $item) {
            if (empty($item['code'])) {
                continue;
            }

            $exists = sqlQueryBuilder()
                ->select('id')
                ->from('discounts_coupons')
                ->where(Operator::equals(['code' => $item['code']]))
                ->execute()->fetchOne();

            // kupon uz existuje
            if ($exists) {
                // zaktualizuju platnost
                sqlQueryBuilder()
                    ->update('discounts_coupons')
                    ->directValues(['used' => ($item['status'] == 2 || $item['status'] == 3) ? 'Y' : 'N'])
                    ->where(Operator::equals(['id' => $exists]))
                    ->execute();

                continue;
            }

            $userId = sqlQueryBuilder()
                ->select('id_user')
                ->from('drs_users')
                ->where(Operator::equals(['id_drs' => $item['customerId']]))
                ->execute()->fetchOne();

            // nemam usera
            if (!$userId) {
                continue;
            }

            // nemam ID generovanych kodu
            if (!($discountId = ($couponsMap[$item['name']] ?? null))) {
                continue;
            }

            // importuju kod
            $couponId = sqlGetConnection()->transactional(function () use ($discountId, $userId, $item) {
                sqlQueryBuilder()
                    ->insert('discounts_coupons')
                    ->directValues(
                        [
                            'id_discount' => $discountId,
                            'code' => $item['code'],
                            'date_from' => (new \DateTime($item['dateFrom']))->format('Y-m-d H:i:s'),
                            'date_to' => (new \DateTime($item['dateTo']))->format('Y-m-d H:i:s'),
                            'id_user' => $userId,
                            'used' => ($item['status'] == 2 || $item['status'] == 3) ? 'Y' : 'N',
                        ]
                    )->execute();

                return (int) sqlInsertId();
            });

            sqlQueryBuilder()
                ->insert('drs_user_coupons')
                ->directValues(
                    [
                        'id_drs' => $item['id'],
                        'id_coupon' => $couponId,
                    ]
                )->execute();

            $count++;
        }

        foreach ($couponsMap as $_ => $discountId) {
            $count = sqlQueryBuilder()
                ->select('COUNT(id)')
                ->from('discounts_coupons')
                ->where(Operator::equals(['id_discount' => $discountId]))
                ->execute()->fetchOne();

            sqlQueryBuilder()
                ->update('discounts')
                ->directValues(
                    [
                        'uses_max' => $count,
                    ]
                )
                ->where(Operator::equals(['id' => $discountId]))
                ->execute();
        }

        $this->writeLine('Imported coupons: '.$count);
    }

    public function importPOSOrders(): void
    {
        $dbcfg = \Settings::getDefault();
        $startTimestamp = $dbcfg->loadValue('drsPOSOrdersTimestampCustom');
        if (!$startTimestamp) {
            $startTimestamp = 38096494;
        }

        $timestampUpdater = function (int $timestamp) use ($dbcfg) {
            $dbcfg->saveValue('drsPOSOrdersTimestampCustom', $timestamp, false);
        };

        $forceEnd = false;
        do {
            try {
                $this->writeLine('Processing POS orders...');

                $this->posOrderSynchronizer->processWithCustomTimestamp(
                    $startTimestamp,
                    $timestampUpdater
                );

                $forceEnd = true;

                $this->writeLine('Done');
            } catch (\Throwable $e) {
                if (isDevelopment()) {
                    throw $e;
                }

                $this->writeLine('[ERROR] '.$e->getMessage());
                sleep(30);
            }
        } while ($forceEnd === false);
    }

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

        $forceEnd = false;
        do {
            $startDate = new \DateTime('2022-10-04');
            //            if ($timestamp = $dbcfg->loadValue('pompoOldOrdersTimestamp')) {
            //                $startDate = (new \DateTime())->setTimestamp($timestamp);
            //            }

            try {
                $this->writeLine('Processing orders...');
                foreach ($this->drsApi->getOrders($startDate) as $order) {
                    if ($order instanceof \DateTime) {
                        $dbcfg->saveValue('pompoOldOrdersTimestamp', $order->getTimestamp(), false);
                        sleep(5);
                        continue;
                    }

                    $this->posOrderSynchronizer->processOrder($order);
                }

                $forceEnd = true;
            } catch (\Exception $e) {
                if (isDevelopment()) {
                    throw $e;
                }

                $this->writeLine('[ERROR] '.$e->getMessage());
                sleep(30);
            }
        } while ($forceEnd === false);

        $this->writeLine('Import done');
    }

    private function writeLine(string $message): void
    {
        call_user_func($this->writeLineCallback, $message);
    }
}
