<?php

/**
 * Copyright 2024-2025 Simply.IN Sp. z o.o.
 *
 * NOTICE OF LICENSE
 *
 * Licensed under the EUPL-1.2 or later.
 * You may not use this work except in compliance with the Licence.
 *
 * Copy of the Licence is available at:
 * https://joinup.ec.europa.eu/software/page/eupl
 * It is bundled with this package in the file LICENSE.txt
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the Licence is distributed on an as is basis,
 * without warranties or conditions of any kind, either express or implied.
 * Check the Licence for the specific language governing permissions
 * and limitations under the License.
 *
 * @author   Simply.IN Sp. z o.o.
 * @copyright 2024-2025 Simply.IN Sp. z o.o.
 * @license   https://joinup.ec.europa.eu/software/page/eupl
 */

if (!defined('_PS_VERSION_')) {
    exit;
}

trait SimplyInInstallSqlTrait
{
    public static function installSql()
    {
        $sql = [];
        $sql = '
            CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . self::$definition['table'] . '`
            (
                %fields%
            ) CHARACTER SET utf8 COLLATE utf8_general_ci;
        ';
        $fields_lang = [];
        $fields = [];
        $fields[] = self::$definition['primary'] . ' INT(11) PRIMARY KEY AUTO_INCREMENT';
        $fields_lang[] = self::$definition['primary'] . ' INT(11)';
        $fields_lang[] = 'id_lang INT(11)';
        foreach (self::$definition['fields'] as $key => $field) {
            $fields_query = '';
            switch ($field['type']) {
                case self::TYPE_STRING:
                case self::TYPE_HTML:
                    if (isset($field['lang'])) {
                        if (isset($field['size'])) {
                            $fields_lang[] = $key . ' VARCHAR(' . $field['size'] . ')';
                        } else {
                            $fields_lang[] = $key . ' LONGTEXT';
                        }
                    } else {
                        if (isset($field['size'])) {
                            $fields_query = $key . ' VARCHAR(' . $field['size'] . ')';
                        } else {
                            $fields_query = $key . ' LONGTEXT';
                        }
                    }

                    break;
                case self::TYPE_INT:
                case self::TYPE_BOOL:
                    if (isset($field['size'])) {
                        $fields_query = $key . ' INT(' . $field['size'] . ')';
                    } else {
                        $fields_query = $key . ' INT(11)';
                    }

                    break;
                case self::TYPE_DATE:
                    $fields_query = $key . ' DATETIME';

                    break;
                case self::TYPE_FLOAT:
                    $fields_query = $key . ' FLOAT';

                    break;
            }
            $fields[] = $fields_query;
        }
        $fields = implode(',' . PHP_EOL . str_repeat(' ', 16), array_filter($fields, static fn ($v): bool => $v !== ''));
        if (sizeof($fields_lang) > 2) {
            $sql_lang = '
                CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . self::$definition['table'] . '_lang`
                (
                    %fields%
                ) CHARACTER SET utf8 COLLATE utf8_general_ci;
            ';
            $fields_lang = implode(',' . PHP_EOL . str_repeat(' ', 16), array_filter($fields_lang, static fn ($v): bool => $v !== ''));
            $sql_lang = str_replace('%fields%', $fields_lang, $sql_lang);
            Db::getInstance()->execute($sql_lang);
        }
        $sql = str_replace('%fields%', $fields, $sql);

        $return = Db::getInstance()->execute($sql);
        if ($return) {
            foreach (self::$definition['fields'] as $key => $field) {
                if (isset($field['index']) && $field['index']) {
                    $sql = 'ALTER TABLE `' . _DB_PREFIX_ . self::$definition['table'] . '` ADD INDEX (`' . $key . '`)';
                    $return &= Db::getInstance()->execute($sql);
                }
            }
        }

        return $return;
    }

    public static function uninstallSql()
    {
        $sql = [];
        $sql[] = 'DROP TABLE IF EXISTS `' . _DB_PREFIX_ . self::$definition['table'] . '`';
        $sql[] = 'DROP TABLE IF EXISTS `' . _DB_PREFIX_ . self::$definition['table'] . '_lang`';
        foreach ($sql as $item) {
            if (!Db::getInstance()->execute($item)) {
                return false;
            }
        }

        return true;
    }

    /**
     * Adds, one column at a time, whatever the model's own field definition now has that the table
     * does not yet. SimplyInPayments had its own copy of exactly this loop before it moved here;
     * every model using this trait now shares the one implementation, so a model that gains a field
     * after its first release gets the same self-healing upgrade for free instead of hand-rolling
     * another copy of it.
     *
     * Safe to call on every write: a shop already on the current schema pays for one SHOW COLUMNS
     * and adds nothing.
     */
    public static function ensureSchema()
    {
        $table = _DB_PREFIX_ . self::$definition['table'];
        $columns = Db::getInstance()->executeS('SHOW COLUMNS FROM `' . bqSQL($table) . '`');
        if (!is_array($columns)) {
            return false;
        }

        $existing = [];
        foreach ($columns as $column) {
            if (isset($column['Field'])) {
                $existing[(string) $column['Field']] = true;
            }
        }

        $return = true;
        foreach (self::$definition['fields'] as $key => $field) {
            if (isset($existing[$key])) {
                continue;
            }
            switch ($field['type']) {
                case self::TYPE_STRING:
                case self::TYPE_HTML:
                    $sqlType = isset($field['size']) ? 'VARCHAR(' . (int) $field['size'] . ')' : 'LONGTEXT';

                    break;
                case self::TYPE_INT:
                case self::TYPE_BOOL:
                    $sqlType = isset($field['size']) ? 'INT(' . (int) $field['size'] . ')' : 'INT(11)';

                    break;
                case self::TYPE_DATE:
                    $sqlType = 'DATETIME';

                    break;
                case self::TYPE_FLOAT:
                    $sqlType = 'FLOAT';

                    break;
                default:
                    continue 2;
            }
            $sql = 'ALTER TABLE `' . bqSQL($table) . '` ADD COLUMN `' . bqSQL($key) . '` ' . $sqlType . ' NULL';
            $return = $return && Db::getInstance()->execute($sql);
        }

        return $return;
    }
}
