<?php

namespace KupShop\OrderingBundle\Resources\upgrade;

use KupShop\I18nBundle\Translations\SettingsTranslation;
use KupShop\KupShopBundle\Context\LanguageContext;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\Contexts;
use KupShop\OrderingBundle\Util\Order\OrderInfo;

class OrderUpgrade extends \UpgradeNew
{
    public function check_OrdersCurrencyColumn()
    {
        return findModule('currencies') && $this->checkColumnType('orders', 'currency', 'VARCHAR(3)');
    }

    /** Set orders.currency to varchar(3) instead of enum */
    public function upgrade_OrdersCurrencyColumn()
    {
        sqlQuery('ALTER TABLE orders CHANGE currency currency VARCHAR(3) DEFAULT "CZK";');

        $this->upgradeOK();
    }

    public function check_IndexOnOrderStatus()
    {
        return $this->checkIndexOnColumnExists('orders', 'status');
    }

    /** Add index on Orders.status */
    public function upgrade_IndexOnOrderStatus()
    {
        sqlQuery('CREATE INDEX orders_status_index ON orders (status);');

        $this->upgradeOK();
    }

    public function check_IndexOnOrderFlags()
    {
        return $this->checkIndexOnColumnExists('orders', 'flags');
    }

    /** Add index on Orders.flags */
    public function upgrade_IndexOnOrderFlags()
    {
        sqlQuery('CREATE INDEX orders_flags_index ON orders (flags);');

        $this->upgradeOK();
    }

    public function check_TotalPriceWithoutVatColumn(): bool
    {
        return $this->checkColumnExists('orders', 'total_price_without_vat');
    }

    /** Add total_price_without_vat column into orders table */
    public function upgrade_TotalPriceWithoutVatColumn(): void
    {
        sqlQuery('ALTER TABLE orders ADD COLUMN total_price_without_vat DECIMAL(15, 4) DEFAULT 0 AFTER total_price;');

        sqlQuery('UPDATE orders o SET o.total_price_without_vat = (
                SELECT SUM(oi.total_price) FROM order_items oi WHERE oi.id_order = o.id 
            );');

        $this->upgradeOK();
    }

    public function check_DateDeliveredColumn(): bool
    {
        return $this->checkColumnExists('orders', 'date_delivered');
    }

    /** Add date_delivered column into orders table */
    public function upgrade_DateDeliveredColumn(): void
    {
        sqlQuery('ALTER TABLE orders ADD COLUMN date_delivered datetime null AFTER date_handle;');
        $this->upgradeOK();
    }

    public function check_orderUserOrderNo()
    {
        return $this->checkColumnExists('orders', 'user_order_no');
    }

    /** orders: ADD COLUMN user_order_no*/
    public function upgrade_orderUserOrderNo()
    {
        sqlQuery('ALTER TABLE `orders` ADD `user_order_no` varchar(20) NULL;');
        sqlQuery('CREATE INDEX orders_user_order_no_index ON orders (user_order_no);');
        sqlQuery('UPDATE `orders` SET user_order_no = JSON_VALUE(note_admin,"$.order_number") WHERE JSON_VALUE(note_admin,"$.order_number") IS NOT NULL');
        sqlQuery('UPDATE `orders` SET user_order_no = JSON_VALUE(note_admin,"$.custom_number") WHERE JSON_VALUE(note_admin,"$.custom_number") IS NOT NULL');
    }

    public function check_DateCreatedIndex(): bool
    {
        return $this->checkIndexNameExists('orders', 'date_created');
    }

    /** Add index on orders.date_created column */
    public function upgrade_DateCreatedIndex(): void
    {
        sqlQuery('CREATE INDEX date_created ON orders (date_created)');

        $this->upgradeOK();
    }

    public function check_TotalWeight(): bool
    {
        return $this->checkColumnExists('orders', 'total_weight') && $this->checkModule(\Modules::PRODUCTS, \Modules::SUB_WEIGHT);
    }

    /** orders: ADD COLUMN total_weight  */
    public function upgrade_TotalWeight(): void
    {
        sqlQuery('ALTER TABLE orders ADD COLUMN total_weight decimal(15,6) null default null');

        sqlQuery('update orders o set total_weight=(select sum(coalesce(pv.weight, p.weight, 0) * oi.pieces)
                                from order_items oi left join products p on oi.id_product = p.id
                                left join products_variations pv on oi.id_variation = pv.id and oi.id_product = pv.id_product
                                where o.id=oi.id_order and oi.id_product is not null)');
    }

    public function check_OrderSource(): bool
    {
        return $this->checkColumnExists('orders', 'source');
    }

    /** Add orders.source column */
    public function upgrade_OrderSource(): void
    {
        $sources = array_map(fn ($x) => '"'.$x.'"', array_keys(OrderInfo::getOrderSources()));

        sqlQuery('ALTER TABLE orders ADD COLUMN source ENUM('.implode(',', $sources).') DEFAULT "'.OrderInfo::ORDER_SOURCE_SHOP.'" AFTER id');
        sqlQuery('CREATE INDEX orders_source_index ON orders (source);');

        $this->upgradeOK();
    }

    public function check_OrderSourceEnum(): bool
    {
        return $this->checkEnumOptions('orders', 'source', array_keys(OrderInfo::getOrderSources()));
    }

    /** Update orders.source enum */
    public function upgrade_OrderSourceEnum(): void
    {
        $this->updateEnumOptions('orders', 'source', array_keys(OrderInfo::getOrderSources()));

        $this->upgradeOK();
    }

    public function check_orderitem_price_buy()
    {
        return findModule(\Modules::PRODUCTS, \Modules::SUB_PRICE_BUY) && $this->checkColumnExists('order_items', 'price_buy');
    }

    /** Add price_buy to order_items */
    public function upgrade_orderitem_price_buy()
    {
        sqlQuery('
            ALTER TABLE order_items ADD COLUMN price_buy DECIMAL(15,4) DEFAULT NULL;
        ');
    }

    public function check_orderedit_price_buy()
    {
        return findModule(\Modules::PRODUCTS, \Modules::SUB_PRICE_BUY) && findModule(\Modules::ORDER_EDIT) && $this->checkColumnExists('order_edit', 'price_buy');
    }

    /** Add price_buy to order_edit */
    public function upgrade_orderedit_price_buy()
    {
        sqlQuery('
            ALTER TABLE order_edit ADD COLUMN price_buy DECIMAL(15,4) DEFAULT NULL;
        ');
    }

    public function check_orders_reverse_order_no()
    {
        return $this->checkColumnExists('orders', 'order_no_reverse');
    }

    /** Add reversed order_no column for fast filtering */
    public function upgrade_orders_reverse_order_no()
    {
        sqlQuery('ALTER TABLE orders ADD COLUMN order_no_reverse VARCHAR(20) AS (REVERSE(order_no))PERSISTENT  after order_no;');
        sqlQuery('create unique index orders_order_no_reverse_uindex on orders (order_no_reverse);');
    }

    public function check_copyEmail()
    {
        return $this->checkColumnExists('orders', 'invoice_copy_email');
    }

    /** Add orders.invoice_copy_email column */
    public function upgrade_copyEmail()
    {
        sqlQuery('ALTER TABLE orders ADD COLUMN invoice_copy_email VARCHAR(100) NULL DEFAULT NULL');
        $this->upgradeOK();
    }

    public function check_dateUpdatedDefault()
    {
        return $this->checkColumnDefault('orders', 'date_updated', 'current_timestamp()');
    }

    /** Orders date_updated - change default to CURRENT_TIMESTAMP */
    public function upgrade_dateUpdatedDefault()
    {
        sqlQuery('UPDATE `orders` 
                    SET `date_updated` = COALESCE(date_handle, date_accept, date_created) 
                    WHERE `date_updated` IS NULL');
        sqlQuery('ALTER TABLE `orders` MODIFY COLUMN `date_updated` DATETIME NULL 
                    DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP');

        $this->upgradeOK();
    }

    public function check_OrdersIdDealerColumnDelete(): bool
    {
        return !$this->checkColumnExists('orders', 'id_dealer');
    }

    /** Drop column orders.id_dealer */
    public function upgrade_OrdersIdDealerColumnDelete(): void
    {
        try {
            sqlQuery('ALTER TABLE orders DROP FOREIGN KEY `orders_ibfk_2`');
        } catch (Throwable $e) {
        }

        sqlQuery('ALTER TABLE orders DROP COLUMN id_dealer;');

        $this->upgradeOK();
    }

    public function check_PaymentConfigOrderPaidDateHandleSetTrue(): bool
    {
        return $this->checkDataMigration(37);
    }

    /** Set settings payment_config.order_paid_date_handle to Y under invoices bundle */
    public function upgrade_PaymentConfigOrderPaidDateHandleSetTrue(): void
    {
        if (findModule(\Modules::INVOICES)) {
            $settings = \Settings::getDefault();
            $paymentConfig = $settings['payment_config'] ?? [];
            $paymentConfig['order_paid_date_handle'] = 'Y';
            $settings->saveValue('payment_config', $paymentConfig);
            if (findModule(\Modules::TRANSLATIONS)) {
                $languageContext = Contexts::get(LanguageContext::class);
                $settingsTranslations = ServiceContainer::getService(SettingsTranslation::class);
                foreach ($languageContext->getAll() as $lang) {
                    if ($lang->getId() == $languageContext->getDefaultId()) {
                        continue;
                    }
                    $settingsTranslations->setLanguageId($lang->getId());
                    $settings = $settingsTranslations->get();
                    if (!empty($settings['payment_config'])) {
                        $paymentConfig = $settings['payment_config'];
                        $paymentConfig['order_paid_date_handle'] = 'Y';
                        $settingsTranslations->update('payment_config', $paymentConfig);
                    }
                }
            }
        }
        $this->commitDataMigration(37);
        $this->upgradeOK();
    }

    public function check_OrderItemIdParentColumn(): bool
    {
        return $this->checkColumnExists('order_items', 'id_parent');
    }

    /** Add id_parent column into order_items table */
    public function upgrade_OrderItemIdParentColumn(): void
    {
        sqlQuery('ALTER TABLE order_items ADD COLUMN id_parent INT UNSIGNED DEFAULT NULL AFTER id_variation,
            ADD FOREIGN KEY FK_oi_id_parent (id_parent) REFERENCES order_items (id) ON DELETE SET NULL ON UPDATE CASCADE;');

        $this->upgradeOK();
    }

    public function check_OrderDropshipmentInvoiceIco(): bool
    {
        return $this->checkColumnType('invoice_ico', 'orders', 'VARCHAR(14)');
    }

    public function upgrade_OrderDropshipmentInvoiceIco(): void
    {
        sqlQuery("ALTER TABLE orders MODIFY COLUMN invoice_ico VARCHAR(14) DEFAULT '' NOT NULL;");
    }

    public function check_OrderEditIdParentColumn()
    {
        return findModule(\Modules::ORDER_EDIT) && $this->checkColumnExists('order_edit', 'id_parent');
    }

    /** Add id_parent column into order_edit table */
    public function upgrade_OrderEditIdParentColumn(): void
    {
        sqlQuery('ALTER TABLE order_edit ADD COLUMN id_parent INT UNSIGNED DEFAULT NULL AFTER id_variation,
            ADD FOREIGN KEY (id_parent) REFERENCES order_items (id) ON DELETE SET NULL ON UPDATE CASCADE;');

        $this->upgradeOK();
    }
}
