<?php
/*
** Copyright (C) 2021-2026 initMAX s.r.o.
**
** This program is free software: you can redistribute it and/or modify it under the terms of
** the GNU Affero General Public License as published by the Free Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
** See the GNU Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public License along with this program.
** If not, see <https://www.gnu.org/licenses/>.
**/

namespace Modules\uxMAX\Actions;

use API, CController, CControllerResponseData, CWebUser;
use Modules\uxMAX\Includes\RequestGuard;
use Modules\uxMAX\Module;
use Modules\uxMAX\Services\Preferences;
use Modules\uxMAX\Services\DatabaseFont;

class Css extends CController {

    use RequestGuard;

    public Module $module;

    protected function init() {
        $this->disableUxmaxRequestGuard();
    }

    public function checkInput() {
        return true;
    }

    public function checkPermissions() {
        return true;
    }

    public function doAction() {
        $preferences = $this->module->preferences->get();
        $uri = $_SERVER['HTTP_REFERER'] ?? '';

        $this->setResponse((new CControllerResponseData([
            'css' => $this->getCssForAction($uri, $preferences)
        ])));
    }

    /**
     * Get custom styles matched passed$action.
     *
     * @param string $uri
     * @param array  $preferences
     */
    protected function getCssForAction(string $uri, array $preferences): string {
        $vars = [];
        $css = [];
        $css_imports = [];

        if ($preferences['state']['customfont']) {
            [$css_imports, $css] = $this->getCustomFontCss($preferences);
        }

        $debug = CWebUser::getDebugMode();
        parse_str(parse_url($uri, PHP_URL_QUERY), $query_args);
        $action = $query_args['action']??'';

        if ($action === '') {
            $action = basename(parse_url($uri, PHP_URL_PATH));
            $query_args['action'] = $action;
        }

        if ($debug) {
            $css[] = "/* uri: {$uri} */";
            $css[] = "/* action: {$action} */";
        }

        // Color tags are special - every logged-in user may override the
        // central rules through their own uxMAX preferences. When the user
        // override toggle is on, getEffectiveColorTags() returns the user's
        // rules; otherwise it falls back to the admin's central rules.
        // The state[colortags] master switch still gates the whole feature.
        $tags = $preferences['state']['colortags']
            ? $this->module->preferences->getEffectiveColorTags()
            : [];
        if ($debug) {
            $css[] = '/* tags css */';
        }

        // The tag text lives in `data-hintbox-contents` from 7.0 on; 6.0 - 6.4
        // nest a <div class="hint-box"> instead and carry NO attribute at all,
        // so an attribute selector matches nothing there and the whole feature
        // is a silent no-op. uxmax.colortags.js stamps `data-uxmax-tag` on
        // those frontends (and only on those), so one rule pair covers the
        // whole 6.0 - 7.4 range without a version test in the stylesheet.
        $operators = [
            Preferences::MATCH_BEGIN => '^',
            Preferences::MATCH_CONTAIN => '*',
            Preferences::MATCH_END => '$'
        ];

        foreach ($tags as $tag) {
            if (!array_key_exists($tag['match'], $operators)) {
                continue;
            }

            $operator = $operators[$tag['match']];

            foreach (['data-hintbox-contents', 'data-uxmax-tag'] as $attribute) {
                $css[] = sprintf('.tag[%1$s%2$s="%3$s"] { background-color: %4$s }',
                    $attribute, $operator, $tag['value'], $tag['color']
                );
            }
        }

        if ($preferences['state']['syntax'] || $preferences['state']['exprhighlight']) {
            if (Preferences::FONT_IMPORT_URL[$preferences['syntax']['font']] ?? false) {
                $css_imports[] = '@import url("'.Preferences::FONT_IMPORT_URL[$preferences['syntax']['font']].'");';
            }

            $font_family = Preferences::FONT[$preferences['syntax']['font']];
            $css[] = <<<CSS
            .ace_editor {
                font-family: {$font_family};
                font-size: {$preferences['syntax']['fontSize']};
            }
            CSS;
        }

        $vars[] = <<<CSS
        --uxmax-body-bgcolor: {$preferences['color']['bodybg']};
        --uxmax-sidebar-bgcolor: {$preferences['color']['asidebg']};
        CSS;

        if ($preferences['state']['modalwidth'] && $preferences['modalwidth']['value'] !== '') {
            $vars[] = '--uxmax-modal-width: '.$preferences['modalwidth']['value']
                .(substr($preferences['modalwidth']['value'], -2) === 'px' ? '' : 'px');
            $css[] = <<<'CSS'
            body .overlay-dialogue.modal-popup {
                min-width: var(--uxmax-modal-width) !important;
            }
            .overlay-dialogue.modal .overlay-dialogue-body { width: 100%; max-width: 100% }
            CSS;
        }

        // Directive @import must be at the top of the file.
        // See https://developer.mozilla.org/en-US/docs/Web/CSS/@import
        return implode("\r\n", array_merge($css_imports, [':root {'.implode("\r\n", $vars).'}'], $css));
    }

    /**
     * Add CSS styles for custom font.
     *
     * @param array $preferences  Preferences array.
     * @return array  Array of css and css @import rules.
     */
    protected function getCustomFontCss(array $preferences): array {
        $css = [];
        $css_imports = [];
        $font = array_filter($preferences['fonts'], fn($f) => $f['enabled']);
        $font = reset($font);

        if (!$font) {
            return [$css_imports, $css];
        }

        if ($font['type'] === Preferences::FONT_TYPE_CSS_URL && !($font['selfhosted']??0)) {
            $css_imports[] = "@import url('{$font['url']}');";
            $css[] = <<<CSS
            html body, input, textarea, button, [class^="btn"], z-select button
            { font-family: "{$font['font_family']}", sans-serif; }
            CSS;
            return [$css_imports, $css];
        }

        if (!($font['pngid'] ?? false)) {
            return [$css_imports, $css];
        }

        $png = API::Image()->get([
            'output' => [],
            'select_image' => true,
            'imageids' => $font['pngid']
        ]);

        if (!$png) {
            return [$css_imports, $css];
        }

        $database_font = new DatabaseFont;
        $css[] = $database_font->getDataBlockFromPng(base64_decode(reset($png)['image']), 0);
        $css[] = <<<CSS
            html body, input, textarea, button, [class^="btn"], z-select button
            { font-family: "{$font['font_family']}", sans-serif; }
            CSS;

        return [$css_imports, $css];
    }
}
