<?php

namespace Mnv\Models;

use Mnv\Core\Config;
use Mnv\Core\Filesystem\Filesystem;
use Mnv\Core\Model;
use Mnv\Core\Test\Logger;
use Mnv\Http\Request;

/**
 * Class Languages
 * @package Mnv\Models
 */
class Languages extends Model
{

    /** @var string */
    protected string $table = 'languages';

    /** @var string  */
    protected string $primaryKey = 'languageId';

    /** @var string  */
    protected string $orderBy = 'sortOrder ASC';

    /** @var string  */
    protected string $columns = 'languageId, languageName, codename, url, status, isDefault, sortOrder';

    public $languageIds = [];

    protected $lang;

    private $defaultLanguage;

    protected $filesystem;
    /**
     * Таблицы которые не нужно копировать
     * @var array
     */
    private static array $tableArray = [
        'languages',
        'subscribe',
        'feedback',
        'users',
        'user_history',
        'users_confirmations',
        'users_remembered',
        'users_resets',
        'users_throttling',
        'users_banned_ips',
        'user_images',
        'user_fields',
        'user_field_data',
        'user_group',
        'user_group_privileges',
        'user_option',
        'files',
        'socials',
        'maps',
        'log',
        'notice',
        'type_content',
        'type_content_fields',
        'type_content_field_property',
        'telegram_notifications',
        'shop_payments',
        'shop_currency',
        'shop_cart',
        'shop_orders',
        'shop_order_product',
        'shop_order_option',
        'shop_order_total',
        'shop_order_shipment',
        'shop_transactions'

    ];

    /**
     * LanguagesAdmin constructor.
     */
    public function __construct(Request $request)
    {
        global $DEFAULT_LANG;

        $this->lang  = $DEFAULT_LANG;
        $this->filesystem = new Filesystem();

        $this->id           = $request->get('id');                  // getRequestVar('id'),
        $this->data         = $request->get('language', '');  // getRequestVar('country', '', true)
        $this->languageIds  = $request->get('ids', '');      // getRequestVar('ids', '', true);

    }

    public function isMultiLang(): bool
    {
        return (int)connect($this->table)->count('*', 'count')->getValue() == 0;
    }

    /**
     * Проверка на совпадение и получение codename
     *
     * @param string|null $codename
     */
    public function checkFileName(string $codename)
    {
        if (!empty($this->id)) {
            connect()->where($this->primaryKey, '<>', $this->id);
        }

        if ($codeName = connect($this->table)->select('codename')->where('codename', $codename)->getValue()) return $codeName;

        return null;
    }

    public function prepare(array $data, int $managerId): bool
    {
        $data['modifiedBy']    = $managerId;
        $data['modifiedOn']    = gmdate('Y-m-d H:i:s');

        if (empty($this->id)) {
            if ((isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1)) || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) {
                $protocol = 'https://';
            } else {
                $protocol = 'http://';
            }

            $data['url'] = !empty($data['isDefault']) ? $protocol . $_SERVER['HTTP_HOST'] : $protocol . $_SERVER['HTTP_HOST'] . '/' . $data['codename'];
            if (!empty($data['isDefault']) || $this->addLanguage($data)) {
                $data['addedBy'] = $managerId;
                $data['addedOn'] = gmdate('Y-m-d H:i:s');
                $data['sortOrder'] = $this->getMaxValue('sortOrder') + 1;

                unset($data['admin_language']);
                unset($data['charset']);

                if ($this->id = $this->insert($data)) {
                    Logger::init()->info("Создан новый язык сайта «" . $data['languageName'] . "»", $managerId)->save();
                    $this->buildLanguagesArray();
                    return true;
                }
            }
        } else {
            unset($data['url']);
            unset($data['codename']);
            unset($data['isDefault']);

            if ($this->update($data)) {
                Logger::init()->info("Внесены изменения в «" . $data['languageName'] . "» язык сайта", $managerId)->save();
                $this->buildLanguagesArray();

                return true;
            }
        }

        return false;
    }


    public function confirmDelete()
    {
        return !empty($this->id) && $this->data = connect($this->table)->where($this->primaryKey, $this->id)->get('array');
    }

    /**
     * @return bool
     */
    public function remove(): bool
    {
        if ($language = connect($this->table)->where($this->primaryKey, $this->id)->get('array')) {
            if (empty($language['isDefault'])) {
                $this->removeLanguage($language);
            }
            connect($this->table)->where($this->primaryKey, $this->id)->delete();
            $this->buildLanguagesArray();

            return true;
        }

        return false;
    }

    public function status(): bool
    {
        if (!empty($this->id) &&  $oldStatus = connect($this->table)->select('status')->where($this->primaryKey, $this->id)->getValue()) {
            $update['status'] = ($oldStatus == 'V') ? 'H' : 'V';
            connect($this->table)->where($this->primaryKey, $this->id)->update($update);
            $this->status = $update['status'];
            $this->buildLanguagesArray();

            return  true;
        }

        return false;
    }

    /**
     * Сортировка версии языка
     */
    public function reorder(): void
    {
        $i = 0;
        foreach ($this->languageIds as $languageId) {
            $i++;
            connect($this->table)->where($this->primaryKey, $languageId)->update(['sortOrder' => $i]);
            $this->buildLanguagesArray();
        }

    }

    /**
     * @param $language
     */
    public function removeLanguage($language): void
    {
        global $tbl, $databaseConfig;

        /** удаляем файлы */
        $this->filesystem->deleteDirectory(GLOBAL_ROOT . '/' . $language['codename']);
        $this->filesystem->delete(GLOBAL_ROOT . '/includes/languages/' . $language['codename'] . '.json');

        /** удаляем таблицы */
        foreach ($tbl as $tableKey => $void) {
            if (!in_array($tableKey, static::$tableArray)) {
                /** delete table */
                $tableName = $databaseConfig['prefix'] . $language['codename'] . '_' . $tableKey;
                connect()->query("DROP TABLE `$tableName`")->exec();
            }
        }
    }


    public function changeDefaultLanguage(): bool
    {
        if ($this->data = connect($this->table)->where($this->primaryKey, $this->id)->where('isDefault',0)->get('array')) {
            $this->defaultLanguage = connect($this->table)->where('isDefault',1)->get('array');
            $this->swapLanguages();

            return true;
        }

        return false;
    }

    public function swapLanguages(): bool
    {
        global $tbl, $databaseConfig;

        $dLanguage = array();
        $nLanguage = array();

        if ($this->data['isDefault']) {
            $dLanguage = $this->data;
            $nLanguage = $this->defaultLanguage;
        }
        if ($this->defaultLanguage['isDefault']) {
            $dLanguage = $this->defaultLanguage;
            $nLanguage = $this->data;
        }

        /* renaming SQL tables */
        $dLanguage['oldPrefix'] = $databaseConfig['prefix'];
        $dLanguage['newPrefix'] = $databaseConfig['prefix'].$dLanguage['codename'] . '_';
        $nLanguage['oldPrefix'] = $databaseConfig['prefix'].$nLanguage['codename'] . '_';
        $nLanguage['newPrefix'] = $databaseConfig['prefix'];
        $tmpPrefix              = $databaseConfig['prefix'].'tmp_';
        $nLanguage['oldURL'] = GLOBAL_URL . '/' . $nLanguage['codename'];
        $nLanguage['newURL'] = GLOBAL_URL;
        $dLanguage['oldURL'] = GLOBAL_URL;
        $dLanguage['newURL'] = GLOBAL_URL . '/' . $dLanguage['codename'];

        $oldLanguagePath = GLOBAL_ROOT . '/' . $dLanguage['codename'];
        $newLanguagePath = GLOBAL_ROOT . '/' . $nLanguage['codename'];

        foreach ($tbl as $tableKey => $void) {
            if (!in_array($tableKey, static::$tableArray)) {
                connect()->query('DROP TABLE IF EXISTS `' . $tmpPrefix. $tableKey. '`')->exec();
                connect()->query('RENAME TABLE `'.$dLanguage['oldPrefix'] . $tableKey.'` TO `'.$tmpPrefix.$tableKey.'`')->exec();
                connect()->query('RENAME TABLE `'.$nLanguage['oldPrefix'].$tableKey.'` TO `'.$nLanguage['newPrefix'].$tableKey.'`')->exec();
                connect()->query('RENAME TABLE `'.$tmpPrefix.$tableKey.'` TO `'.$dLanguage['newPrefix'].$tableKey.'`')->exec();
            }
        }

        /* updating languages */
        connect($this->table)->where($this->primaryKey, $dLanguage['languageId'])->update(['isDefault' => 0, 'url' => $dLanguage['newURL']]);
        connect($this->table)->where($this->primaryKey, $nLanguage['languageId'])->update(['isDefault' => 1, 'url' => $nLanguage['newURL']]);

        /* moving out dLanguage */
        $this->filesystem->ensureDirectoryExists($oldLanguagePath);
        $this->filesystem->ensureDirectoryExists($oldLanguagePath . '/uploads');
        $this->filesystem->ensureDirectoryExists($oldLanguagePath . '/includes');

        $this->filesystem->move(GLOBAL_ROOT . '/includes/serializations.inc.php', $oldLanguagePath . '/includes/serializations.inc.php');
        $this->filesystem->move(GLOBAL_ROOT . '/includes/.htaccess', $oldLanguagePath . '/includes/.htaccess');

        /* moving nLanguage */
        $this->filesystem->moveDirectory($newLanguagePath, GLOBAL_ROOT);

        /* leaving redirect in the language directory */
        $this->filesystem->ensureDirectoryExists($newLanguagePath);
        $htaccess  = "Options -Indexes\r\n";
        $htaccess .= "RewriteEngine On\r\n";
        $htaccess .= "RewriteRule ^(.*)$ " . GLOBAL_URL . "/\$1 [L,R=301]\r\n";
        $this->filesystem->put($newLanguagePath . '/.htaccess', $htaccess);

        /* getting languages */
        $dLanguage = connect($this->table)->where($this->primaryKey, $dLanguage['languageId'])->get('array');
        $nLanguage = connect($this->table)->where($this->primaryKey, $nLanguage['languageId'])->get('array');

        /* building serializations and .htaccess */
        foreach ($tbl as $tableKey => $void) {
            if (!in_array($tableKey, static::$tableArray)) {
                $tbl[$tableKey] = $databaseConfig['prefix'] . $dLanguage['codename'] . '_' . $tableKey;
            }
        }

        saveSerializations($dLanguage);
        writeHtaccess($dLanguage);

        foreach ($tbl as $tableKey => $void) {
            if (!in_array($tableKey, static::$tableArray)) {
                $tbl[$tableKey] = $databaseConfig['prefix'] . $tableKey;
            }
        }
        saveSerializations($nLanguage);
        writeHtaccess($nLanguage);
        $this->buildLanguagesArray();

        return true;
    }


    /**
     * Работа с базой данных и папками
     *
     * @param $language
     * @return bool
     */
    private function addLanguage($language): bool
    {
        global $tbl, $databaseConfig;

        if (!empty($language['isDefault']) || $this->lang == $language['codename']) {
            return false;
        }

        /** SQL copy table */

        foreach ($tbl as $tableKey => $void) {
            if (!in_array($tableKey, static::$tableArray)) {
                $tableName = $databaseConfig['prefix'].$tableKey;
                $newTableName = $databaseConfig['prefix'] . $language['codename'] . '_' . $tableKey;
                /* copy table */
                connect()->query("CREATE TABLE `$newTableName` LIKE `$tableName` ")->exec();
            }
        }

        /** SQL update table */
        foreach ($tbl as $tableKey => $void) {
            if (!in_array($tableKey, static::$tableArray)) {
                $tableName = $databaseConfig['prefix'].$tableKey;
                $newTableName = $databaseConfig['prefix'] . $language['codename'] . '_' . $tableKey;

                /** копировать данные таблиц */
                if ($tableKey != 'settings') {
                    connect()->query("INSERT INTO `$newTableName` SELECT * FROM " . $tableName)->exec();
                }
            }
        }

        /** SQL settings table insert new data */
        $langSettingsArr = connect()->table('settings')->getAll('array');
        foreach ($langSettingsArr as $item) {
            $langSettings[$item['codename']] = $item['value'];
        }

        if (!empty($language['charset'])) {
            $langSettings['charset'] = $language['charset'];
        }

        if (!empty($language['admin_language'])) {
            $langSettings['admin_language'] = $language['admin_language'];
        }

        $langSettings['website_language'] = $language['codename'];
        $langSettings['website_down'] = 0;

        $newTable = $databaseConfig['prefix'] . $language['codename'] . '_settings';
        foreach ($langSettings as $codename => $value) {
            connect()->query("INSERT INTO " . $newTable . " VALUES('" . $codename . "','" . $value . "')")->exec();
        }
        /** end settings table insert new data */

        /** file system */
        $newLanguageRoot = GLOBAL_ROOT.'/'.$language['codename'];
        $this->filesystem->ensureDirectoryExists($newLanguageRoot);
//        if (!$this->filesystem->isDirectory($newLanguageRoot) && !$this->filesystem->makeDirectory($newLanguageRoot)) {
//            throw new \RuntimeException(sprintf('Directory "%s" was not created', $newLanguageRoot));
//        }
        /** main htaccess */
        $this->filesystem->put($newLanguageRoot.'/.htaccess', "Options -Indexes\r\n");

        /** includes */
        $this->filesystem->ensureDirectoryExists($newLanguageRoot . '/includes');
        $this->filesystem->put($newLanguageRoot.'/includes/.htaccess', "Deny from all");
        $this->filesystem->copy(GLOBAL_ROOT.'/includes/serializations.inc.php', $newLanguageRoot.'/includes/serializations.inc.php');

        /** копирование содержимого папки uploads */
        $this->filesystem->ensureDirectoryExists($newLanguageRoot . '/uploads');
        /** копирование языковой версии сайта */
        $this->copyTranslations(Config::getValue('website_language'), $language['codename']);

        $this->copyTheme($language['codename']);

        return true;
    }

    /**
     * Дублирование темы (c шаблонами)
     *
     * @param $newLang
     */
    private function copyTheme($newLang): void
    {
        if (empty($newLang) || Config::getValue('website_language') === $newLang) {
            return;
        }

        $themeDir = GLOBAL_ROOT . '/themes/';
        $themeDefaultDir = $themeDir . Config::getValue('theme');

        if ($this->filesystem->isDirectory($themeDefaultDir)) {
            $themeName = explode( "-", Config::getValue('theme'));
            $themeNewDir = $themeDir . $themeName[0] . '-' . $newLang;
            if ($this->filesystem->exists($themeDefaultDir) && !$this->filesystem->exists($themeNewDir)) {
                $this->filesystem->copyDirectory($themeDefaultDir, $themeNewDir);
            }
        }
    }

    /**
     * Дублирование переводов
     * @param $label_src
     * @param $label_dest
     */
    private function copyTranslations($label_src, $label_dest): void
    {
        if (empty($label_src) || empty($label_dest) || $label_src == $label_dest) {
            return;
        }
        $lang_dir = GLOBAL_ROOT . '/includes/languages/';
        if ($this->filesystem->isDirectory($lang_dir)) {
            $src = $lang_dir . $label_src . '.json';
            $dest = $lang_dir . $label_dest . '.json';
            if ($this->filesystem->exists($src) && !$this->filesystem->exists($dest)) {
                $this->filesystem->copy($src, $dest);
            }
        }
    }


    protected function buildLanguagesArray(): bool
    {
        global $LANGUAGES;

        $LANGUAGES = connect($this->table)->select('languageName, codename, url, isDefault, status')->where('status', 'V')->orderBy('sortOrder')->indexKey('codename')->getAllIndexes('array');

        $langExport = "<?php\r\n";
        $langExport .= '$LANGUAGES = '. var_export($LANGUAGES, true).";\r\n";
        $langExport .= "return \$LANGUAGES;\r\n";
        $langExport .= "?>";

        $this->filesystem->put(GLOBAL_ROOT.'/includes/global-languages.inc.php', $langExport);

        foreach ($LANGUAGES as $codename => $void) {
            $LANGUAGES[$codename]['languageTransName'] = lang('languageList:'.$codename);
        }
        return true;
    }


}