<?php

declare(strict_types=1);

namespace External\HannahBundle\Resources\script;

use Doctrine\DBAL\Exception\DeadlockException;
use Doctrine\DBAL\Exception\LockWaitTimeoutException;
use External\HannahBundle\SAP\MappingType;
use External\HannahBundle\SAP\Util\SAPUtil;
use External\HannahBundle\Util\Configuration;
use KupShop\AdminBundle\Util\Script\Script;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\System\PathFinder;
use League\Csv\Reader;

class OCImportSalesScript extends Script
{
    protected static $name = '[OC] Import sales';

    private ?array $salesCache = null;

    protected function run(array $arguments)
    {
        $retry = 0;

        do {
            $this->log('Running import; Try: '.$retry);

            try {
                $stopWhile = $this->withCSVFile(fn (string $file) => $this->import($file));
            } catch (LockWaitTimeoutException|DeadlockException $e) {
                $stopWhile = ++$retry > 30;
                $this->log('Import failed: "'.$e->getMessage().'"! Retrying...');
            }
        } while ($stopWhile === false);
    }

    private function import(string $file): void
    {
        $csv = Reader::createFromPath($file);

        $csv->setDelimiter(';');
        $csv->setHeaderOffset(0);

        foreach ($csv->getRecords() as $key => $item) {
            $this->log("[{$key}] {$item['code']}");

            if ($this->isSaleCreated($item['code'])) {
                continue;
            }

            $data = json_decode($item['data'] ?: '', true) ?: [];

            $item['id_delivery_type'] = $this->getDeliveryTypeId();
            $item['id_seller'] = $this->getSellerIdBySAPStore($data['sapStoreId'] ?? '');
            $item['id_user'] = null;
            if (!empty($data['sapCustomerId'])) {
                $item['id_user'] = $this->getSAPUtil()->getMapping(MappingType::USERS, $data['sapCustomerId']);
            }

            $items = array_filter(json_decode($item['items'] ?: '', true) ?: [], fn ($x) => !empty($x['id']));
            unset($item['id'], $item['id_order'], $item['items']);

            sqlGetConnection()->transactional(function () use ($item, $items) {
                sqlQueryBuilder()
                    ->insert('sales')
                    ->directValues($item)
                    ->execute();

                $saleId = (int) sqlInsertId();

                $qb = sqlQueryBuilder()
                    ->insert('sales_items');

                foreach ($items as $item) {
                    $item['id_sale'] = $saleId;
                    $item['id_product'] = null;
                    $item['id_variation'] = null;

                    if ($mapping = $this->getSAPUtil()->getItemMapping($item['product_code'])) {
                        $item['id_product'] = $mapping[0];
                        $item['id_variation'] = $mapping[1];
                    }

                    unset($item['id'], $item['product_code']);

                    $qb->multiDirectValues($item);
                }

                if ($qb->getQueryPart('values')) {
                    $qb->execute();
                }
            });
        }
    }

    private function isSaleCreated(string $code): bool
    {
        if ($this->salesCache === null) {
            $this->salesCache = sqlQueryBuilder()
                ->select('code, id')
                ->from('sales')
                ->execute()->fetchAllKeyValue();
        }

        return (bool) ($this->salesCache[$code] ?? false);
    }

    private function getSellerIdBySAPStore(string $storeId): ?int
    {
        static $sellersCache;

        if (!$sellersCache) {
            $sellersCache = sqlQueryBuilder()
                ->select('id_sap, s.id')
                ->from('sap_stores', 'ss')
                ->join('ss', 'sellers', 's', 's.id_store = ss.id_store')
                ->execute()->fetchAllKeyValue();
        }

        return $sellersCache[$storeId] ?? null;
    }

    private function getDeliveryTypeId(): int
    {
        return match ($this->getConfiguration()->getShopId()) {
            Configuration::SHOP_HANNAH => 114,
            Configuration::SHOP_RAFIKI => 95,
            Configuration::SHOP_KEEN => 99,
        };
    }

    private function withCSVFile(callable $fn): bool
    {
        $file = $this->getCSVPath();

        $fn($file);

        unlink($file);

        return true;
    }

    private function getCSVPath(): string
    {
        $tmp = PathFinder::getService()->tmpPath('tmp_sales_data.csv');
        if (file_exists($tmp)) {
            return $tmp;
        }

        $fp = fopen($tmp, 'w+');

        if (!$fp) {
            $this->log('Could not open file for writing.');

            return '';
        }

        $ch = curl_init('https://www.uschovna.cz/download/QVM6KPY763UWD49T-S44/UWU54DWZBI/');

        curl_setopt($ch, CURLOPT_FILE, $fp);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 600);
        curl_setopt($ch, CURLOPT_BUFFERSIZE, 4096);

        if (!curl_exec($ch)) {
            $this->log('Error: '.curl_error($ch));

            return '';
        }

        curl_close($ch);
        fclose($fp);

        return $tmp;
    }

    private function getConfiguration(): Configuration
    {
        static $configuration;

        return $configuration ??= ServiceContainer::getService(Configuration::class);
    }

    private function getSAPUtil(): SAPUtil
    {
        static $sapUtil;

        return $sapUtil ??= ServiceContainer::getService(SAPUtil::class);
    }
}

return OCImportSalesScript::class;
