<?php

declare(strict_types=1);

/**
 * Module handles the first entry backend page after new login by user.
 *
 * @module          initial_page
 * @author          LEPTON project 
 * @copyright       2010-2026 LEPTON Project 
 * @link            https://lepton-cms.org
 * @license         copyright, all rights reserved
 * @license_terms   please see info.php of this module
 *
 */
 
class initial_page extends LEPTON_abstract
{
    // Own instance for this class!
    public static $instance;

    private LEPTON_database $db;

    private string $table = "mod_initial_page";

    private array $backend_pages = [];

    private string $sActionUrl = ADMIN_URL."/admintools/tool.php?tool=initial_page&leptoken=";
    
    /**
     * @return void
     */
    public function initialize(): void
    {
        $this->db = LEPTON_database::getInstance();

        $MENU = LEPTON_core::getGlobal("MENU");

        $this->backend_pages = [
            "Start"             => "start/index.php",
            $MENU["ADDON"]      => "addons/index.php",
            $MENU["ADMINTOOLS"] => "admintools/index.php",
            $MENU["GROUPS"]     => "groups/index.php",
            $MENU["LANGUAGES"]  => "languages/index.php",
            $MENU["MEDIA"]      => "media/index.php",
            $MENU["MODULES"]    => "modules/index.php",
            $MENU["PAGES"]      => "pages/index.php",
            $MENU["PREFERENCES"]=> "preferences/index.php",
            $MENU["SETTINGS"]   => "settings/index.php",
            $MENU["TEMPLATES"]  => "templates/index.php",
            $MENU["USERS"]      => "users/index.php"
        ];

        $this->testInstallation();

        $this->table = TABLE_PREFIX.$this->table;

        $this->sActionUrl .= get_leptoken();
    }

    /**
     * @param int $aUser_id
     * @param string $aPath_ref
     * @return void
     */
    public function execute(int $aUser_id = 0, string $aPath_ref = ""): void
    {
        if (($aUser_id != 0) && ($aPath_ref != ""))
        {
            $this->internalTestUser($aUser_id, $aPath_ref);
        } else {
            $this->internalTestEntries();
        }
    }

    /**
     * @param int $aID
     * @param string $path_ref
     * @return void
     */
    private function internalTestUser(int $aID, string $path_ref): void
    {
        $info = $this->get_user_info( $aID );
        $path = ADMIN_URL."/".$info['init_page'];
        if (($path <> $path_ref) && ($info['init_page'] != "start/index.php") && ($info['init_page'] != ""))
        {
            if (strlen($info['page_param']) > 0)
            {
                $path .= str_replace("&amp;", "&", $info['page_param']);
            }

            $this->internalAddLeptoken( $path );

            if (true === $this->testPath($path))
            {
                header('Location: '.$path );
                die();
            }
        }
    }

    /**
     * @param int $aUserId
     * @return array|string[]
     */
    public function get_user_info(int &$aUserId=0 ): array
    {
        $aUser = [];
        $this->db->execute_query(
            "SELECT `init_page`, `page_param` from `".$this->table."` where `user_id`=".$aUserId,
            true,
            $aUser,
            false
        );

        if (empty($aUser))
        {
            if ($aUserId > 0)
            {
                $this->db->simple_query(
                    "INSERT INTO `".$this->table."` (`user_id`, `init_page`,`page_param`) 
                    VALUES ('".$aUserId."', 'start/index.php', '')"
                );
            }

            return ['init_page' => "start/index.php", 'page_param' => ''];

        }
        else
        {
            return $aUser;
        }
    }

    /**
     * @param string $aURL
     * @return void
     */
    private function internalAddLeptoken(string &$aURL ): void
    {
        $tempLeptoken = filter_input(INPUT_GET, "leptoken", FILTER_SANITIZE_SPECIAL_CHARS);
        if (!is_null($tempLeptoken))
        {
            $aURL .= !str_contains($aURL, "?") ? "?" : "&";

            $aURL .= "leptoken=".$tempLeptoken;
        }
    }

    /**
     *  Does the target page exists, or does the target admin tool exists?
     *
     *  @param  string $sPath A path/link to the target backend page.
     *  @return bool
     *
     */
    private function testPath(string $sPath ): bool
    {
        // edit page?
        $matches = [];
        if (1 === preg_match("/modify.php\?page_id=([0-9]*)/", $sPath, $matches))
        {
            $iLookupPageID = intval($matches[1]);
            return (NULL != $this->db->get_one("SELECT `page_title` FROM `".TABLE_PREFIX."pages` WHERE `page_id` =".$iLookupPageID));

        } else {
            // Is it an admin tool?
            if (1 === preg_match("/admintools\/tool\.php\?tool=([A-Za-z_0-9]*)/", $sPath, $matches))
            {
                $sAdminToolName = $matches[1];
                return (NULL != $this->db->get_one("SELECT `name` FROM `".TABLE_PREFIX."addons` WHERE `directory` ='".$sAdminToolName."' AND `function`='tool' "));
            }
            else {
                return true;
            }
        }
    }

    /**
     *    Protected function to test the users and delete entries for
     *    not existing ones.
     *
     */
    protected function internalTestEntries(): void
    {
        $aResult= [];
        $this->db->execute_query(
            "SELECT `user_id` from `".TABLE_PREFIX."users` order by `user_id`",
            true,
            $aResult,
            true
        );
        if (!empty($aResult))
        {
            $ids = [];
            foreach ($aResult as $data)
            {
                $ids[] = $data['user_id'];
            }

            $this->db->simple_query( "DELETE from `".TABLE_PREFIX."mod_initial_page` where `user_id` not in (".implode (",",$ids).")" );
        }
    }

    /**
     * @param string $name
     * @param string $selected
     * @return string
     */
    public function get_backend_pages_select(string $name="init_page_select", string $selected = ""): string
    {
        $MENU = LEPTON_core::getGlobal("MENU");

        $values = [];

        // [1] First: add pages ...
        LEPTON_handle::register("page_tree");
        $all_pages = [];
        page_tree(0, $all_pages);

        $temp_storage = [];
        $this->internal_get_pagetree_menulevel( $all_pages, $temp_storage);

        foreach ($temp_storage as $key => $value)
        {
            $values[$MENU['PAGES']][$key] = $value;
        }

        // [2] Second: add tools
        $aTemp = [];
        $this->db->execute_query(
            "SELECT `name`,`directory` from `" . TABLE_PREFIX . "addons` where `function`='tool' order by `name`",
            true,
            $aTemp,
            true
        );

        foreach ($aTemp as $data)
        {
            $values[$MENU['ADMINTOOLS']][$data['name']] = "admintools/tool.php?tool=" . $data['directory'];
        }

        // [3] At last the backend-pages
        $values['Backend'] = &$this->backend_pages;
        $options = [
            'name' => $name,
            'class' => "init_page_select"
        ];

        return $this->internalBuildSelect($options, $values, $selected);
    }

    /**
     * Internal private function for the correct display of the page(-tree)
     *
     * @param array $all     Array within the pages. (Pass by reference)
     * @param array $storage A storage array for the result. (Pass by Reference)
     * @param int   $deep    Counter for the recursion deep, correspondence with the menu-level of the page(-s)
     * @return bool
     */
    private function internal_get_pagetree_menulevel(array &$all, array &$storage = [], int $deep = 0 ): bool
    {
        //    Menu-data is empty, nothing to do
        if (count($all) == 0)
		{
			return false;
		}

        //    Recursions are more than 50 ... break
        if ($deep > 50)
        {
            return false;
        }

        //    Build the 'select-(menu)title prefix
        $prefix = str_repeat("-", $deep);

        if ($deep > 0)
		{
			$prefix .= " ";
		}

        foreach ($all as $ref)
		{
            $storage[$prefix.$ref['page_title']] = "pages/modify.php?page_id=".$ref['page_id'];

            // Recursive call for the subpages
            $this->internal_get_pagetree_menulevel( $ref['subpages'], $storage, $deep+1 );
        }

        return true;
    }

    /**
     * @param array $options
     * @param array $values
     * @param string $selected
     * @return string
     */
    private function internalBuildSelect(array &$options, array &$values, string &$selected): string
    {
        $s = "<select ".$this->internalBuildArgs($options).">\n";
        foreach ($values as $theme => $sublist)
		{
            $s .= "<optgroup label='".$theme."'>";
            foreach ($sublist as $item => $val)
            {
                $sel = ($val == $selected) ? " selected='selected'" : "";
                $s .= "<option value='".$val."'".$sel.">".$item."</option>\n";
            }
            $s .= "</optgroup>";
        }
        $s.= "</select>\n";
        return $s;
    }

    /**
     * @param array $aArgs
     * @return string
     */
    private function internalBuildArgs(array &$aArgs): string
    {
        $s = "";
        foreach($aArgs as $name=>$value)
        {
            $s .= " ".$name."='".$value."'";
        }
        return $s;
    }

    /**
     *  Update the user entries
     *
     *  @param  int     $iUID   A valid user ID.
     *  @param  string  $iValue A valid pageID.
     *  @param  string  $sParam A valid string for additional parameters.
     */
    public function update_user(int $iUID, string &$iValue, string $sParam = ""): void
    {
        $aFields = [
            "page_param" => $sParam,
            "init_page"  => $iValue
        ];

        $this->db->build_and_execute(
            "update",
            $this->table,
            $aFields,
            "user_id=" . $iUID
        );
    }

    /**
     * @param int $aUserId
     * @param string $aName
     * @param string $selected
     * @param array $options
     * @return string
     */
    public function get_single_user_select (
        int $aUserId,
        string $aName,
        string $selected="",
        array &$options=[
            'backend_pages' => true,
            'tools' => true,
            'pages' => true
            ]
        ): string
    {

        global $MENU;

        $values = [];

        if (array_key_exists('backend_pages', $options) && ($options['backend_pages'] === true))
        {
            $values['Backend'] = $this->backend_pages;
        }

        /**
         *    Add tools
         *
         */
        if (array_key_exists('tools', $options) && ($options['tools'] === true))
        {
            $temp = [];
            $this->db->execute_query(
                "SELECT `name`,`directory` from `" . TABLE_PREFIX . "addons` where `function`='tool' order by `name`",
                true,
                $temp,
                true
            );

            foreach ($temp as $data)
            {
                $values[$MENU['ADMINTOOLS']][$data['name']] = "admintools/tool.php?tool=".$data['directory'];
            }
        }

        /**
         *    Add pages
         *
         */
        if (array_key_exists('pages', $options) && ($options['pages'] === true))
        {
            LEPTON_handle::register("page_tree");

            $all_pages = [];
            page_tree(0, $all_pages);

            $temp_storage = [];
            $this->internal_get_pagetree_menulevel( $all_pages, $temp_storage);

            foreach ($temp_storage as $key => $value)
            {
                $values[$MENU['PAGES']][$key] = $value;
            }
        }

        $options = [
            'name' => $aName,
            'class' => "init_page_select"
        ];

        return $this->internalBuildSelect($options, $values, $selected);
    }

    /**
     * @return array
     */
    public function get_language(): array
    {
        return $this->language;
    }

    public function showInfo(): string
    {
        $TEXT = LEPTON_core::getGlobal("TEXT");
        $data = [
            'oINITIAL_PAGE' => $this,
            'image_url'     => LEPTON_URL."/modules/initial_page/img/initial_page_backend.png",
            'infos'         => [
                $TEXT['NAME']        => $this->module_name,
                $TEXT['DESCRIPTION'] => $this->module_description,
                $TEXT['AUTHOR']      => $this->module_author,
                $TEXT['VERSION']     => $this->module_version,
                $TEXT['MODULE_GUID'] => $this->module_guid,
                $TEXT['LICENSE']     => $this->module_license,
                $TEXT['MODULE_LICENSE_TERMS'] => $this->module_license_terms
            ]
        ];

        $oTWIG = lib_twig_box::getInstance();
        $oTWIG->registerModule("initial_page");
        
        echo $oTWIG->render(
            "@initial_page/info.lte",
            $data
        );        
        return "";
    }
    
    /**
     * Module is called but the db table is missing.
     *
     * @return void
     */
    private function testInstallation(): void
    {
        $allTables = LEPTON_database::getInstance()->list_tables(TABLE_PREFIX);
        if (!in_array($this->table, $allTables))
        {
            // DB table does not exist, so we try to run the installer
            require dirname(__DIR__)."/install.php";
        }
    }
}
