<?php

namespace ADP\BaseVersion\Includes\Database\Repository;

use ADP\BaseVersion\Includes\Core\Rule\CartCondition\Interfaces\ListComparisonCondition;
use ADP\BaseVersion\Includes\Database\Models\Rule;
use ADP\BaseVersion\Includes\Helpers\Helpers;
use ADP\ProVersion\Includes\Core\Rule\CartCondition\Impl\ShippingState;
use ADP\BaseVersion\Includes\Cache\CacheHelper;
class RuleRepository implements RuleRepositoryInterface {

    /**
     * @return bool
     */
    public function hasActiveRulesWithBadges(): bool
    {
        global $wpdb;
        $table = $wpdb->prefix . Rule::TABLE_NAME;

        $sql = "SELECT COUNT(*) FROM $table WHERE `advertising` NOT LIKE \"a:0:{}\" AND NOT deleted AND enabled  LIMIT 1";
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared
        $count = $wpdb->get_var($sql);
        return $count>0;
    }

    /**
     * @return bool
     */
    public function hasActiveRulesDependOnShipping(): bool
    {
        global $wpdb;
        $table = $wpdb->prefix . Rule::TABLE_NAME;

        $sql = "SELECT COUNT(*) FROM $table WHERE `conditions` LIKE \"%shipping%\" AND NOT deleted AND enabled  LIMIT 1";
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared
        $count = $wpdb->get_var($sql);
        return $count>0;
    }

    /**
     * @return bool
     */
    public function hasActiveRulesWithLimits(): bool
    {
        global $wpdb;
        $table = $wpdb->prefix . Rule::TABLE_NAME;

        $sql = "SELECT COUNT(*) FROM $table WHERE `limits` NOT LIKE \"a:0:{}\" AND NOT deleted AND enabled  LIMIT 1";
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared
        $count = $wpdb->get_var($sql);
        return $count>0;
    }

    /**
     * @return bool
     */
    public function hasActiveRulesWithCompexCartDiscounts(): bool
    {
        global $wpdb;
        $table = $wpdb->prefix . Rule::TABLE_NAME;

        $sql = "SELECT COUNT(*) FROM $table WHERE (`cart_adjustments` LIKE \"%discount_repeatable%\" OR `cart_adjustments` LIKE \"%fee_repeatable%\") AND NOT deleted AND enabled LIMIT 1";
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared
        $count = $wpdb->get_var($sql);
        return $count>0;
    }


    /**
     * @return array
     */
    public function getRulesWithBulk(): array
    {
        global $wpdb;
        $table = $wpdb->prefix . Rule::TABLE_NAME;

        $sql = "SELECT * FROM $table WHERE bulk_adjustments LIKE '%ranges%' AND NOT deleted";
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared
        $rows = $wpdb->get_results($sql);

        $rows = array_map(function ($item) {
            $result = array(
                'id'                       => $item->id,
                'title'                    => $item->title,
                'rule_type'		           => $item->rule_type,
                'type'                     => $item->type,
                'exclusive'                => $item->exclusive,
                'priority'                 => $item->priority,
                'enabled'                  => $item->enabled,
                'options'                  => unserialize($item->options ?? ""),
                'additional'               => unserialize($item->additional ?? ""),
                'conditions'               => unserialize($item->conditions ?? ""),
                'filters'                  => unserialize($item->filters ?? ""),
                'limits'                   => unserialize($item->limits ?? ""),
                'product_adjustments'      => unserialize($item->product_adjustments ?? ""),
                'sortable_blocks_priority' => unserialize($item->sortable_blocks_priority ?? ""),
                'bulk_adjustments'         => unserialize($item->bulk_adjustments ?? ""),
                'role_discounts'           => unserialize($item->role_discounts ?? ""),
                'cart_adjustments'         => unserialize($item->cart_adjustments ?? ""),
                'get_products'             => unserialize($item->get_products ?? ""),
                'advertising'              => unserialize($item->advertising ?? ""),
                'condition_message'        => unserialize($item->condition_message ?? ""),
            );
            return self::decodeArrayTextFields($result);
        }, $rows);

        foreach ($rows as &$row) {
            $row = self::validateBulkAdjustments($row);
        }

        $rows = self::migrateTo_2_2_3($rows);

        $countryStates = WC()->countries->get_states();

        // fix collections in conditions
        if(class_exists('ShippingState')) {
            foreach ($rows as &$row) {
                foreach ($row['conditions'] as &$condition) {
                    $type    = $condition['type'];
                    if ($type === 'shipping_state' && isset($condition['options'][ShippingState::COMPARISON_LIST_KEY])) {
                        $comparison_value = $condition['options'][ShippingState::COMPARISON_LIST_KEY];

                        $newComparisonValue = array();
                        $changed            = false;

                        foreach ($comparison_value as $value) {
                            if (strpos($value, ':') === false) {
                                foreach ($countryStates as $country_code => $states) {
                                    if (isset($states[$value])) {
                                        $newComparisonValue[] = $country_code . ":" . $value;
                                        $changed              = true;
                                    }
                                }
                            }
                        }

                        if ($changed) {
                            $condition['options'][ShippingState::COMPARISON_LIST_KEY] = $newComparisonValue;
                        }
                    }
                }
            }
        }

        $lastCustomTaxonomy = Helpers::getCustomProductTaxonomies();
        $lastCustomTaxonomy = end($lastCustomTaxonomy);

        $rules = array();

        foreach ($rows as &$row) {
            foreach ($row['conditions'] as &$condition) {
                $type = $condition['type'];

                if ($type === 'custom_taxonomy' || $type === 'amount_custom_taxonomy') {
                    $condition['type'] = $condition['type'] . '_' . $lastCustomTaxonomy->name;
                }
            }

            $rules[] = Rule::fromArray($row);
        }

        return $rules;
    }

    public function getRules($args = array()): array
    {
        global $wpdb;
        $table = $wpdb->prefix . Rule::TABLE_NAME;

        $sql = "SELECT * FROM $table WHERE 1 ";

        if (isset($args['types'])) {
            $types        = (array)$args['types'];
            $placeholders = array_fill(0, count($types), '%s');
            $placeholders = implode(', ', $placeholders);
            //phpcs:ignore WordPress.DB
            $sql          = $wpdb->prepare("$sql AND type IN($placeholders)", $types);
        }

        if (isset($args['rule_types'])) {
            $types        = (array)$args['rule_types'];
            $placeholders = array_fill(0, count($types), '%s');
            $placeholders = implode(', ', $placeholders);
            //phpcs:ignore WordPress.DB
            $sql          = $wpdb->prepare("$sql AND (rule_type IN($placeholders) OR rule_type is NULL)", $types);
        }

        $active_only = isset($args['active_only']) && $args['active_only'];
        if ($active_only) {
            $sql .= ' AND enabled = 1';
        }

        if (isset($args['active'])) {
            $sql .= sprintf(' AND enabled = %s', $args['active'] ? "1" : "0");
        }

        $include_deleted = isset($args['include_deleted']) && $args['include_deleted'];
        if ( ! $include_deleted) {
            $sql .= ' AND deleted = 0';
        }

        if(adp_context()->isBaseVersion()) {
            $args['exclusive'] = 0;
        }

        if (isset($args['exclusive'])) {
            $showExclusive = $args['exclusive'] ? 1 : 0;
            $sql           = "$sql AND exclusive = $showExclusive";
        }

        if (isset($args['id'])) {
            $ids          = (array)$args['id'];
            $placeholders = array_fill(0, count($ids), '%d');
            $placeholders = implode(', ', $placeholders);
            //phpcs:ignore WordPress.DB
            $sql          = $wpdb->prepare("$sql AND id IN($placeholders)", $ids);
        }

        if (isset($args['filter_types'])) {
            $types        = (array)$args['filter_types'];

            foreach ( $types as $type ) {
                //phpcs:ignore WordPress.DB
                $wpdb->prepare("$sql AND (filters LIKE '%s')", "%$type%");
            }
        }

        if (isset($args['q'])) {
            $q = $args['q'];

            if (preg_replace("/\s+/", "", strtolower($q)) === 'noname') {
                $sql .= " AND (title = '' OR summary LIKE '%no name%')";
            } else {
                //phpcs:ignore WordPress.DB
                $sql = $wpdb->prepare("$sql AND (summary LIKE %s)", "%$q%");
            }
        }

        $sql .= " ORDER BY rule_type DESC, exclusive DESC, priority";

        if (isset($args['limit'])) {
            $sql_limit = "";
            $limit     = $args['limit'];

            $count = null;
            $start = null;

            if (is_string($limit)) {
                $count = $limit;
            } elseif (is_array($limit)) {
                if (1 === count($limit)) {
                    $count = reset($limit);
                } elseif (2 === count($limit)) {
                    list($start, $count) = $limit;
                }
            }

            if ( ! is_null($count)) {
                $count = (integer)$count;
                if ( ! is_null($start)) {
                    $start     = (integer)$start;
                    $sql_limit = sprintf("LIMIT %d, %d", $start, $count);
                } else {
                    $sql_limit = sprintf("LIMIT %d", $count);
                }
            }

            $sql .= " " . $sql_limit;
        }

        $sql = apply_filters("adp_get_rule_sql", $sql, $args);

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared
        $rows = $wpdb->get_results($sql);

        $rows = array_map(function ($item) {
            $result = array(
                'id'                       => $item->id,
                'title'                    => $item->title,
                'rule_type'		           => $item->rule_type,
                'type'                     => $item->type,
                'exclusive'                => $item->exclusive,
                'priority'                 => $item->priority,
                'enabled'                  => $item->enabled,
                'options'                  => unserialize($item->options ?? ""),
                'additional'               => unserialize($item->additional ?? ""),
                'conditions'               => unserialize($item->conditions ?? ""),
                'filters'                  => unserialize($item->filters ?? ""),
                'limits'                   => unserialize($item->limits ?? ""),
                'product_adjustments'      => unserialize($item->product_adjustments ?? ""),
                'sortable_blocks_priority' => unserialize($item->sortable_blocks_priority ?? ""),
                'bulk_adjustments'         => unserialize($item->bulk_adjustments ?? ""),
                'role_discounts'           => unserialize($item->role_discounts ?? ""),
                'cart_adjustments'         => unserialize($item->cart_adjustments ?? ""),
                'get_products'             => unserialize($item->get_products ?? ""),
                'auto_add_products'        => unserialize($item->auto_add_products ?? ""),
                'advertising'              => unserialize($item->advertising ?? ""),
                'condition_message'        => unserialize($item->condition_message ?? ""),
            );
            $result = self::decodeArrayTextFields($result);

            return $result;
        }, $rows);

        if (isset($args['product'])) {
            $new_rows              = array();
            $filters_to_check      = array_column($rows, "filters");
            $sellerRulesExist      = false;
            $customFieldsRuleExist = false;
            array_map(function ($ruleFilters) use (&$sellerRulesExist, &$customFieldsRuleExist) {
                $rulesFiltersValues = array_values(array_column($ruleFilters, "type"));
                if ($sellerRulesExist === false && in_array("product_sellers", $rulesFiltersValues)) {
                    $sellerRulesExist = true;
                }
                if ($customFieldsRuleExist === false && in_array("product_custom_fields", $rulesFiltersValues)) {
                    $customFieldsRuleExist = true;
                }

                return $ruleFilters;
            }, $filters_to_check);
            if ($sellerRulesExist) {
                $productSellers = array_column(Helpers::getUsers(array()), 'id');
            }
            if ($customFieldsRuleExist) {
                $customFields = array_column(Helpers::getProductCustomFields($args['product']),
                    'id');
            }
            foreach ($rows as $row) {
                foreach ($row['filters'] as $filter) {
                    switch ($filter['type']) {
                        case 'products':
                            foreach ($filter['value'] as $value) {
                                if ((integer)$value == $args['product'] || (isset($args["product_childs"]) && in_array((integer)$value,
                                            $args["product_childs"]))) {
                                    $new_rows[] = $row;
                                    break 3;
                                }
                            }
                            break 2;
                        case 'product_sku':
                            foreach ($filter['value'] as $value) {
                                if (isset($args[$filter['type']]) && strcmp((string)$value,
                                        $args[$filter['type']]) === 0) {
                                    $new_rows[] = $row;
                                    break 3;
                                }
                            }
                            break 2;
                        case 'product_categories':
                        case 'product_attributes':
                        case 'product_tags':
                            foreach ($filter['value'] as $value) {
                                if (isset($args[$filter['type']]) && in_array((integer)$value,
                                        $args[$filter['type']])) {
                                    $new_rows[] = $row;
                                    break 3;
                                }
                            }
                            break 2;
                        case 'product_sellers':
                            foreach ($filter['value'] as $value) {
                                if ( ! empty($productSellers) && in_array((integer)$value, $productSellers)) {
                                    $new_rows[] = $row;
                                    break 3;
                                }
                            }
                            break 2;
                        case 'product_custom_fields':
                            foreach ($filter['value'] as $value) {
                                if ( ! empty($customFields) && in_array((string)$value, $customFields)) {
                                    $new_rows[] = $row;
                                    break 3;
                                }
                            }
                            break 2;
                        case 'product_category_slug':
                            foreach ($filter['value'] as $value) {
                                if (isset($args["product_category_slug"]) && in_array((string)$value,
                                        $args['product_category_slug'])) {
                                    $new_rows[] = $row;
                                    break 3;
                                }
                            }
                            break 2;
                        default:
                            break 1;
                    }
                }
            }
            $rows = $new_rows;
        }

        foreach ($rows as &$row) {
            $row = self::validateBulkAdjustments($row);
        }

        $rows = self::migrateTo_2_2_3($rows);

        $countryStates = WC()->countries->get_states();

        // fix collections in conditions
        if(class_exists('ShippingState')) {
            foreach ($rows as &$row) {
                foreach ($row['conditions'] as &$condition) {
                    $type    = $condition['type'];
                    if ($type === 'shipping_state' && isset($condition['options'][ShippingState::COMPARISON_LIST_KEY])) {
                        $comparison_value = $condition['options'][ShippingState::COMPARISON_LIST_KEY];

                        $newComparisonValue = array();
                        $changed            = false;

                        foreach ($comparison_value as $value) {
                            if (strpos($value, ':') === false) {
                                foreach ($countryStates as $country_code => $states) {
                                    if (isset($states[$value])) {
                                        $newComparisonValue[] = $country_code . ":" . $value;
                                        $changed              = true;
                                    }
                                }
                            }
                        }

                        if ($changed) {
                            $condition['options'][ShippingState::COMPARISON_LIST_KEY] = $newComparisonValue;
                        }
                    }
                }
            }
        }

        $lastCustomTaxonomy = Helpers::getCustomProductTaxonomies();
        $lastCustomTaxonomy = end($lastCustomTaxonomy);

        $rules = array();

        foreach ($rows as &$row) {
            foreach ($row['conditions'] as &$condition) {
                $type = $condition['type'];

                if ($type === 'custom_taxonomy' || $type === 'amount_custom_taxonomy') {
                    $condition['type'] = $condition['type'] . '_' . $lastCustomTaxonomy->name;
                }
            }

            $row = apply_filters("adp_raw_rule", $row);

            $rules[] = Rule::fromArray($row);
        }

        return $rules;
    }

    public function getRulesCount($args = array())
    {
        //    	return self::get_test_rules();
        global $wpdb;
        $table = $wpdb->prefix . Rule::TABLE_NAME;

        $sql = "SELECT COUNT(*) FROM $table WHERE 1 ";

        if (isset($args['types'])) {
            $types        = (array)$args['types'];
            $placeholders = array_fill(0, count($types), '%s');
            $placeholders = implode(', ', $placeholders);
            //phpcs:ignore WordPress.DB
            $sql          = $wpdb->prepare("$sql AND type IN($placeholders)", $types);
        }

        $active_only = isset($args['active_only']) && $args['active_only'];
        if ($active_only) {
            $sql .= ' AND enabled = 1';
        }

        if (isset($args['active'])) {
            $sql .= sprintf(' AND enabled = %s', $args['active'] ? "1" : "0");
        }

        $include_deleted = isset($args['include_deleted']) && $args['include_deleted'];
        if ( ! $include_deleted) {
            $sql .= ' AND deleted = 0';
        }

        if (isset($args['exclusive'])) {
            $showExclusive = $args['exclusive'] ? 1 : 0;
            $sql           = "$sql AND exclusive = $showExclusive";
        }

        if (isset($args['id'])) {
            $ids          = (array)$args['id'];
            $placeholders = array_fill(0, count($ids), '%d');
            $placeholders = implode(', ', $placeholders);
            //phpcs:ignore WordPress.DB
            $sql          = $wpdb->prepare("$sql AND id IN($placeholders)", $ids);
        }

        if (isset($args['q'])) {
            $q = $args['q'];
            //phpcs:ignore WordPress.DB
            $sql = $wpdb->prepare("$sql AND (summary LIKE '%s')", "%$q%");
        }
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared
        return (integer)$wpdb->get_var($sql);
    }

    private static function validateBulkAdjustments($row)
    {
        if (empty($row['bulk_adjustments']['ranges'])) {
            return $row;
        }

        $ranges = $row['bulk_adjustments']['ranges'];
        $ranges = array_values(array_filter(array_map(function ($range) {
            return isset($range['to'], $range['from'], $range['value']) ? $range : false;
        }, $ranges)));


        usort($ranges, function ($a, $b) {
            if ($a["to"] === '' && $b["to"] === '') {
                return 0;
            } elseif ($a["to"] === '') {
                return 1;
            } elseif ($b["to"] === '') {
                return -1;
            }

            return (integer)$a["to"] - (integer)$b["to"];
        });

        $previousRange = null;
        foreach ($ranges as &$range) {
            $from = $range['from'];
            if ($from === '') {
                if (is_null($previousRange)) {
                    $from = 1;
                } else {
                    if ($previousRange['to'] !== '') {
                        $from = (integer)$previousRange['to'] + 1;
                    }
                }
            }
            $range['from'] = $from;
            $previousRange = $range;
        }

        $row['bulk_adjustments']['ranges'] = $ranges;

        return $row;
    }

    private static function migrateTo_2_2_3($rows)
    {
        // add selector "in_list/not_in_list" for amount conditions
        foreach ($rows as &$row) {
            foreach ($row['conditions'] as &$condition) {
                if ('amount_' === substr($condition['type'], 0, strlen('amount_')) &&
                !isset($condition['options'][ListComparisonCondition::COMPARISON_LIST_METHOD_KEY])) {
                    $condition['options'][ListComparisonCondition::COMPARISON_LIST_METHOD_KEY] = 'in_list';
                }
            }
        }

        return $rows;
    }

    private static function decodeArrayTextFields($array)
    {
        foreach ($array as &$value) {
            if (is_array($value)) {
                $value = self::decodeArrayTextFields($value);
            } else {
                $value = trim(htmlspecialchars_decode($value));
            }
        }

        return $array;
    }

    public function deleteAllRules()
    {
        global $wpdb;
        CacheHelper::flushRulesCache();
        $table = $wpdb->prefix . Rule::TABLE_NAME;
        $sql   = "DELETE FROM $table";
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared
        $wpdb->query($sql);
    }

    public function markRulesAsDeleted($type)
    {
        global $wpdb;
        CacheHelper::flushRulesCache();
        $table = $wpdb->prefix . Rule::TABLE_NAME;

        $sql = "UPDATE $table SET deleted = 1 WHERE type ";
        if (is_array($type)) {
            $format = implode(', ', array_fill(0, count($type), '%s'));
            //phpcs:ignore WordPress.DB
            $sql    = $wpdb->prepare("$sql IN ($format)", $type);
        } else {
            //phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
            $sql = $wpdb->prepare("$sql = %s", $type);
        }
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared
        $wpdb->query($sql);
    }

    public function markRuleAsDeleted($rule_id)
    {
        global $wpdb;
        CacheHelper::flushRulesCache();
        $table = $wpdb->prefix . Rule::TABLE_NAME;

        $rules = $this->getRules(['id' => $rule_id]);

        if (isset($rules[0]) && $rules[0] instanceof Rule) {
            $rule_data = $rules[0]->getDataForDB();
            $rule_data['deleted'] = 1;
        } else {
            $rule_data = null;
        }

        $data  = array('deleted' => 1);
        $where = array('id' => $rule_id);
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery
        $wpdb->update($table, $data, $where);

        do_action("adp_rule_deleted", $rule_id, $rule_data);
    }

    public function storeRule($rule)
    {
        global $wpdb;

        CacheHelper::flushRulesCache();

        $table = $wpdb->prefix . Rule::TABLE_NAME;
        $data = $rule->getDataForDB();

        if ($id = $rule->id) {
            $where  = array('id' => $id);
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery
            $wpdb->update($table, $data, $where);
            do_action("adp_rule_updated", $id, $data);

            return $id;
        } else {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery
            $wpdb->insert($table, $data);
            do_action("adp_rule_added", $wpdb->insert_id, $data);

            return $wpdb->insert_id;
        }
    }

    public function changeRulePriority(int $ruleId, int $priority): int
    {
        global $wpdb;
        $table = $wpdb->prefix . Rule::TABLE_NAME;

        $result = 0;

        if ($ruleId) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery
            $result = $wpdb->update($table, array('priority' => $priority), array('id' => $ruleId));
        }

        return $result;
    }

    public function markAsDisabledByPlugin($ruleId)
    {
        global $wpdb;
        CacheHelper::flushRulesCache();
        $tableRules = $wpdb->prefix . Rule::TABLE_NAME;
        //phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        $sql = $wpdb->prepare("SELECT {$tableRules}.additional FROM {$tableRules} WHERE id = %d", $ruleId);
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared
        $additional                       = $wpdb->get_var($sql);
        $additional                       = unserialize($additional);
        $additional['disabled_by_plugin'] = 1;

        $data  = array('enabled' => 0, 'additional' => serialize($additional));
        $where = array('id' => $ruleId);
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery
        $wpdb->update($tableRules, $data, $where);
    }

    public function deleteConditionsFromDbByTypes($types)
    {

        $rules = array_merge($this->getRules(), $this->getRules(array(
            'exclusive' => true,
        )));

        /**
         * @var Rule $rule
         */
        foreach ($rules as $rule) {
            if (isset($rule->conditions) && !empty($rule->conditions)) {
                $conditions = $rule->conditions;
            } else {
                continue;
            }
            foreach ($conditions as $keyCondition => $condition) {
                if (in_array($condition['type'], $types)) {
                    unset($conditions[$keyCondition]);
                }
            }
            $conditions = array_values($conditions);

            $data = array_merge($rule->getData(), array('id' => $rule->id, 'conditions' => $conditions));
            $ruleObj = Rule::fromArray($data);
            $this->storeRule($ruleObj);
        }
    }

    public function isConditionTypeActive($types)
    {
        $rules = array_merge($this->getRules(array(
            'active_only' => true,
        )), $this->getRules(array(
            'exclusive'   => true,
            'active_only' => true,
        )));

        foreach ($rules as $rule) {
            if (isset($rule->conditions)) {
                $conditions = $rule->conditions;
            } else {
                continue;
            }
            foreach ($conditions as $condition) {
                if (in_array($condition['type'], $types)) {
                    return true;
                }
            }

        }

        return false;
    }

    public function disableRule($ruleId)
    {
        global $wpdb;
        CacheHelper::flushRulesCache();
        $table = $wpdb->prefix . Rule::TABLE_NAME;

        $data  = array('enabled' => 0);
        $where = array('id' => $ruleId);
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery
        $wpdb->update($table, $data, $where);
    }

    public function enableRule($ruleId)
    {
        global $wpdb;
        CacheHelper::flushRulesCache();
        $table = $wpdb->prefix . Rule::TABLE_NAME;

        $data  = array('enabled' => 1);
        $where = array('id' => $ruleId);
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery
        $wpdb->update($table, $data, $where);
    }

    public function migrateSuitableCommonRulesToPersistence() : int
    {
        global $wpdb;
        $tableRules = $wpdb->prefix . Rule::TABLE_NAME;

        $sql = $wpdb->prepare(
            //phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
            "UPDATE {$tableRules}
            SET `rule_type` = 'persistent'
            WHERE
                  `deleted` = 0
              AND `exclusive` = 0
              AND `rule_type` <> %s
              AND `rule_type` <> %s
              AND `filters` LIKE %s
              AND `filters` LIKE %s
              AND `filters` NOT LIKE %s
              AND `cart_adjustments` = %s
              AND (`bulk_adjustments` = %s OR `bulk_adjustments` LIKE %s OR `bulk_adjustments` LIKE %s OR
                   `bulk_adjustments` = %s OR `bulk_adjustments` = %s OR
                   `bulk_adjustments` IS NULL)
        ",
            'persistent',
            'exclusive',
            'a:1:{%', // single filter
            '%s:3:"qty";s:1:"1";%', // qty equals 1
            '%s:4:"type";s:3:"any";%', // not any product
            'a:0:{}',
            'a:2:{s:4:"type";s:4:"bulk";s:13:"table_message";s:0:"";}', //no bulk
            '%s:4:"type";s:4:"bulk";%s:9:"qty_based";s:3:"all";%', //bulk with qty based on all matched products
            '%s:4:"type";s:4:"bulk";%s:9:"qty_based";s:3:"not";%', //bulk with qty based on all matched products if import from csv
            'a:1:{s:13:"table_message";s:0:"";}', //TODO: prevent rules to save bulk like this
            'a:0:{}' //for pre-4.0.0 imported rules with no bulk
        );
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared
        return (int)($wpdb->query($sql));
    }

    public function migrateSuitablePersistenceRulesToCommon() : int
    {
        global $wpdb;
        $tableRules = $wpdb->prefix . Rule::TABLE_NAME;

        $sql = $wpdb->prepare(
            //phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
            "UPDATE {$tableRules}
            SET `rule_type` = 'common'
            WHERE
                  `deleted` = 0
              AND `exclusive` = 0
              AND `rule_type` = %s
        ",
            'persistent'
        );
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared
        return (int)($wpdb->query($sql));
    }
}
