<?php

namespace idoit\Module\Pro\SettingPage\CustomTranslation;

use idoit\Component\Browser\Retriever;
use idoit\Module\Packager\Component\Packager;
use idoit\Module\Pro\Model\Language;
use idoit\Module\System\SettingPage\SettingPage;
use isys_application;
use isys_auth as Auth;
use isys_component_filemanager;
use isys_component_list;
use isys_component_template_navbar;
use isys_core;
use isys_format_json as JSON;
use isys_helper_link as HelperLink;
use isys_module_pro as ModulePro;
use isys_module_system as ModuleSystem;
use isys_notify;

/**
 * Class CustomTranslation
 *
 * @package idoit\Module\System\SettingPage
 */
class CustomTranslation extends SettingPage
{
    public const NAVMODE_IMPORT = 1000;
    public const NAVMODE_EXPORT = 1001;
    public const NAVMODE_NEW_TRANSLATION = 1002;

    /**
     * @var Language
     */
    private $languageModel;

    /**
     * SettingPage constructor.
     *
     * @param \isys_component_template                  $template
     * @param \isys_component_database                  $database
     * @param \isys_component_template_language_manager $language
     */
    public function __construct(\isys_component_template $template, \isys_component_database $database, \isys_component_template_language_manager $language)
    {
        parent::__construct($template, $database, $language);

        $this->languageModel = Language::instance(isys_application::instance()->container->get('database_system'));
    }

    /**
     * @param $navMode
     *
     * @return mixed|void
     * @throws \isys_exception_auth
     * @throws \isys_exception_dao
     * @throws \isys_exception_database
     */
    public function renderPage($navMode)
    {
        $request = isys_application::instance()->container->get('request');

        $getId = strtolower($request->query->get('id') ?? '');
        $postId = $request->request->get('id');

        if (!empty($getId) && !in_array($navMode, [C__NAVMODE__EDIT, C__NAVMODE__SAVE, C__NAVMODE__CANCEL, self::NAVMODE_EXPORT])) {
            $navMode = C__NAVMODE__EDIT;
        }

        switch ($navMode) {
            case C__NAVMODE__NEW:
                $this->renderForm('');
                break;

            case C__NAVMODE__EDIT:
                if ($postId) {
                    $redirectUrl = HelperLink::create_url([
                        C__GET__MODULE_ID     => defined_or_default('C__MODULE__SYSTEM'),
                        C__GET__MODULE_SUB_ID => defined_or_default('C__MODULE__PRO'),
                        C__GET__SETTINGS_PAGE => 'custom-translations',
                        C__GET__TREE_NODE     => $_GET[C__GET__TREE_NODE],
                        C__GET__ID            => strtolower(is_array($postId) ? implode('', $postId) : $postId)
                    ], true);

                    isys_core::send_header('Location', $redirectUrl);
                    die;
                }

                if ($getId) {
                    $this->renderForm($getId);
                } else {
                    $this->renderList();
                }
                break;

            case C__NAVMODE__DELETE:
            case C__NAVMODE__PURGE:
            case C__NAVMODE__QUICK_PURGE:
                $this->deleteLanguages(array_map('strtolower', (array)$postId));
                $this->renderList();
                break;

            case self::NAVMODE_EXPORT:
                isys_component_filemanager::sendInline(
                    JSON::encode($this->exportLanguage($getId)),
                    'custom-translation-' . $getId . '.json',
                    'application/json'
                );
                die;

            case C__NAVMODE__CANCEL:
            default:
                $this->renderList();
                break;
        }
    }

    /**
     * @return void
     * @throws \isys_exception_auth
     * @throws \isys_exception_database
     */
    private function renderList()
    {
        ModuleSystem::getAuth()
            ->check(Auth::VIEW, 'custom-translations');

        $allowedToCreate = ModuleSystem::getAuth()->is_allowed_to(Auth::CREATE, 'custom-translations');
        $allowedToEdit = ModuleSystem::getAuth()->is_allowed_to(Auth::EDIT, 'custom-translations');
        $allowedToDelete = ModuleSystem::getAuth()->is_allowed_to(Auth::DELETE, 'custom-translations');

        isys_component_template_navbar::getInstance()
            ->hide_all_buttons()
            ->set_js_onclick("$('navMode').setValue(" . C__NAVMODE__NEW . "); $('isys_form').submit();", C__NAVBAR_BUTTON__NEW)
            ->set_active($allowedToCreate, C__NAVBAR_BUTTON__NEW)
            ->set_visible(true, C__NAVBAR_BUTTON__NEW)
            ->set_js_onclick("$('navMode').setValue(" . C__NAVMODE__EDIT . "); $('isys_form').submit();", C__NAVBAR_BUTTON__EDIT)
            ->set_active($allowedToEdit, C__NAVBAR_BUTTON__EDIT)
            ->set_visible(true, C__NAVBAR_BUTTON__EDIT)
            ->set_active($allowedToDelete, C__NAVBAR_BUTTON__PURGE)
            ->set_visible(true, C__NAVBAR_BUTTON__PURGE)
            ->append_button('LC__LANGUAGE_ADD_TRANSLATION', 'new_translation', [
                'active'              => $allowedToEdit,
                'icon'                => 'axialis/flags-languages/document-language.svg',
                'navmode'             => self::NAVMODE_NEW_TRANSLATION
            ])
            ->append_button('LC__UNIVERSAL__EXPORT', 'export', [
                'active'              => $allowedToEdit,
                'icon'                => 'axialis/basic/symbol-download.svg',
                'navmode'             => C__NAVMODE__EXPORT
            ])
            ->append_button('LC__UNIVERSAL__IMPORT', 'import', [
                'active'              => ($allowedToCreate || $allowedToEdit),
                'icon'                => 'axialis/basic/symbol-upload.svg',
                'navmode'             => C__NAVMODE__IMPORT
            ]);

        $translationList = new isys_component_list(null, $this->languageModel->getAll());

        $rowHeaders = [
            'title'     => 'LC__LANGUAGE_LANGUAGE',
            'short'     => 'LC__LANGUAGE_LANGUAGE_ABBREVIATION',
            'icon'      => 'LC__LANGUAGE_FLAG',
            'available' => 'LC__LANGUAGE_AVAILABLE',
        ];

        $rowLink = HelperLink::create_url([
            C__GET__MODULE_ID     => defined_or_default('C__MODULE__SYSTEM'),
            C__GET__MODULE_SUB_ID => defined_or_default('C__MODULE__PRO'),
            C__GET__SETTINGS_PAGE => 'custom-translations',
            C__GET__TREE_NODE     => $_GET[C__GET__TREE_NODE],
            C__GET__ID            => '[{short}]'
        ]);

        $translationList->config($rowHeaders, $rowLink, '[{short}]');
        $translationList->set_row_modifier($this, 'modifyRow');

        $translationList->createTempTable();

        $this->tpl
            ->assign('content_title', $this->lang->get('LC__CUSTOM_TRANSLATIONS'))
            ->assign('translationList', $translationList->getTempTableHtml())
            ->smarty_tom_add_rule('tom.content.navbar.cRecStatus.p_bInvisible=1')
            ->include_template('contentbottomcontent', ModulePro::getPath() . 'templates/SettingPage/CustomTranslation/list.tpl');
    }

    /**
     * @param array $row
     *
     * @return void
     */
    public function modifyRow(array &$row)
    {
        global $g_dirs;

        $row['short'] = strtoupper($row['short']);
        $row['available'] = '<div class="display-flex align-items-center">' .
            ($row['available']
                ? '<img src="' . $g_dirs['images'] . 'axialis/basic/symbol-ok.svg" class="mr5" /><span class="text-green">LC__UNIVERSAL__YES</span>'
                : '<img src="' . $g_dirs['images'] . 'axialis/basic/symbol-cancel.svg" class="mr5" /><span class="text-red">LC__UNIVERSAL__NO</span>') .
            '</div>';

        if (empty($row['icon']) || !file_exists(BASE_DIR . 'images/' . $row['icon'])) {
            $row['icon'] = 'empty.gif';
        }

        $row['icon'] = '<img src="' . $g_dirs['images'] . $row['icon'] . '" />';
    }

    /**
     * @param string $languageAbbreviation
     *
     * @return void
     * @throws \isys_exception_database
     */
    private function renderForm(string $languageAbbreviation)
    {
        $auth = ModuleSystem::getAuth();
        $allowedToEdit = $auth->is_allowed_to(Auth::EDIT, 'custom-translations');

        // In 'create' mode we allow saving.
        if (empty($languageAbbreviation)) {
            $allowedToEdit = $allowedToEdit || $auth->is_allowed_to(Auth::CREATE, 'custom-translations');
        }

        isys_component_template_navbar::getInstance()
            ->hide_all_buttons()
            ->set_active(true, C__NAVBAR_BUTTON__CANCEL)
            ->set_js_onclick('', C__NAVBAR_BUTTON__CANCEL)
            ->set_js_onclick('', C__NAVBAR_BUTTON__SAVE)
            ->set_active($allowedToEdit, C__NAVBAR_BUTTON__SAVE);

        $isChangeable = $this->isChangeable($languageAbbreviation);
        $languageData = $this->languageModel->getByAbbreviation($languageAbbreviation);

        $rules = [
            'C__CUSTOM_TRANSLATION__NAME'           => [
                'p_strValue'  => $languageData['title']
            ],
            'C__CUSTOM_TRANSLATION__ABBREVIATION'   => [
                'p_strValue'  => strtoupper($languageData['short']),
                'p_bDisabled' => !$isChangeable || !empty($languageData['short']),
                'p_nMaxLen'   => 8
            ],
            'C__CUSTOM_TRANSLATION__AVAILABLE'      => [
                'p_arData'        => get_smarty_arr_YES_NO(),
                'p_bDbFieldNN'    => true,
                'p_strClass'      => 'input input-mini',
                'p_strSelectedID' => $languageData['available'],
                'p_bDisabled'     => !$isChangeable
            ],
            'custom-translation-table-filter'       => [
                'p_strPlaceholder'  => 'LC_UNIVERSAL__FILTER_LIST',
                'p_bInfoIconSpacer' => 0,
                'p_strClass'        => 'input input-mini',
                'p_bEditMode'       => true
            ],
            'custom-translation-table-current-page' => [
                'p_strValue'        => '1',
                'disableInputGroup' => true,
                'p_bInfoIconSpacer' => 0,
                'p_strStyle'        => 'width:50px;',
                'p_bEditMode'       => true
            ]
        ];

        if ($allowedToEdit) {
            $this->tpl->activate_editmode();
        }

        $this->tpl
            ->assign('content_title', $this->lang->get('LC__CUSTOM_TRANSLATIONS') . ' "' . $this->lang->get($languageData['title'] ?? '') . '"')
            ->assign('allowedToEdit', $allowedToEdit)
            ->assign('cssPath', ModulePro::getPath() . 'assets/css/custom-translation.css')
            ->assign('flagIcons', $this->getFlagIcons())
            ->assign('selectedFlagIcon', $languageData['icon'])
            ->assign('abbreviation', strtolower($languageAbbreviation))
            ->smarty_tom_add_rules('tom.content.bottom.content', $rules)
            ->include_template('contentbottomcontent', ModulePro::getPath() . 'templates/SettingPage/CustomTranslation/form.tpl');
    }

    /**
     * @return array
     */
    private function getFlagIcons(): array
    {
        $svgLanguageIcons = glob(BASE_DIR . 'images/axialis/flags-languages/*.svg');

        $svgIcons = array_map(function ($iconPath): array {
            return [
                'name' => ucwords(str_replace('-', ' ', substr(basename($iconPath, '.svg'), 5))), // Cut away the 'flag-' prefix
                'rawName' => basename($iconPath),
                'url'  => str_replace(BASE_DIR . 'images/', '', $iconPath)
            ];
        }, $svgLanguageIcons);

        $customLanguageIcons = glob(BASE_DIR . 'images/languages/*');
        $customIcons = array_map(function ($iconPath): array {
            return [
                'name' => trim(ucwords(str_replace(['_', '-'], ' ', basename($iconPath, '.' . pathinfo($iconPath)['extension'])))),
                'rawName' => basename($iconPath),
                'url'  => str_replace(BASE_DIR . 'images/', '', $iconPath)
            ];
        }, $customLanguageIcons);

        $iconCollection = array_merge($svgIcons, $customIcons);

        usort($iconCollection, function (array $a, array $b): int {
            return strcasecmp($a['name'], $b['name']);
        });

        return $iconCollection;
    }

    /**
     * @param array $languageAbbreviations
     *
     * @return void
     * @throws \isys_exception_auth
     * @throws \isys_exception_dao
     */
    private function deleteLanguages(array $languageAbbreviations)
    {
        ModuleSystem::getAuth()
            ->check(Auth::DELETE, 'custom-translations');

        foreach ($languageAbbreviations as $abbreviation) {
            $abbreviation = strtolower($abbreviation);

            if (!$this->isChangeable($abbreviation)) {
                isys_notify::warning($this->lang->get('LC__LANGUAGE_CORE_DELETION'));
                continue;
            }

            // Rename the custom translation file to avoid data loss.
            $fileName = BASE_DIR . 'src/lang/' . $abbreviation . '_custom.inc.php';
            $backupFileName = BASE_DIR . 'src/lang/' . $abbreviation . '_custom.' . date('YmdHis') . '.inc.php';

            if (file_exists($fileName)) {
                rename($fileName, $backupFileName);
            }

            $this->languageModel->delete($abbreviation);
        }
    }

    /**
     * @param string $abbreviation
     *
     * @return bool
     */
    private function isChangeable(string $abbreviation): bool
    {
        return !in_array(strtolower($abbreviation), Language::UNDELETABLE, true);
    }

    /**
     * @param string $abbreviation
     *
     * @return array
     * @throws \isys_exception_database
     */
    private function exportLanguage(string $abbreviation)
    {
        global $g_langcache;
        $language = $this->languageModel->getByAbbreviation($abbreviation);

        $g_langcache = [];
        $iconContent = null;
        $fileName = BASE_DIR . 'src/lang/' . $abbreviation . '_custom.inc.php';

        if ($fileName) {
            include $fileName;
        }

        if (!empty($language['icon']) || file_exists(BASE_DIR . 'images/' . $language['icon'])) {
            $iconContent = base64_encode(file_get_contents(BASE_DIR . 'images/' . $language['icon']));
        }

        return [
            'title'               => $language['title'],
            'short'               => $language['short'],
            'available'           => (bool)$language['available'],
            'const'               => $language['const'],
            'iconPath'            => empty($language['icon']) ? null : $language['icon'],
            'iconContent'         => $iconContent,
            'custom-translations' => $g_langcache
        ];
    }
}
