<?php

/*
 * Copyright 2005 - 2025 Centreon (https://www.centreon.com/)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * For more information : contact@centreon.com
 *
 */

require_once __DIR__ . '/centreonACL.class.php';
require_once __DIR__ . '/centreonLog.class.php';
require_once __DIR__ . '/centreonAuth.class.php';

/**
 * Class
 *
 * @class CentreonUser
 */
class CentreonUser
{
    /** @var int|string|null */
    public $user_id;

    /** @var string|null */
    public $name;

    /** @var string|null */
    public $alias;

    /** @var string|null */
    public $passwd;

    /** @var string|null */
    public $email;

    /** @var string|null */
    public $lang;

    /** @var string */
    public $charset = 'UTF-8';

    /** @var int */
    public $version = 3;

    /** @var int|string|null */
    public $admin;

    /** @var */
    public $limit;

    /** @var */
    public $num;

    /** @var mixed|null */
    public $gmt;

    /** @var bool|null */
    public $is_admin = null;

    /** @var */
    public $groupList;

    /** @var */
    public $groupListStr;

    /** @var CentreonACL */
    public $access;

    /** @var CentreonUserLog */
    public $log;

    /** @var int|mixed */
    public $default_page;

    /** @var string|null */
    public $theme;

    // User LCA
    // Array with elements ID for loop test
    /** @var array|null */
    public $lcaTopo;

    // String with elements ID separated by commas for DB requests
    /** @var string|null */
    public $lcaTStr;

    /** @var string */
    public $authType;

    /** @var string|null */
    protected $token;

    /** @var bool */
    protected $restApi;

    /** @var bool */
    protected $restApiRt;

    /** @var bool */
    private $showDeprecatedPages;

    /** @var int */
    private $currentPage;

    private bool $showDeprecatedCustomViews;

    /**
     * CentreonUser constructor
     *
     * @param array $user
     *
     * @throws PDOException
     */
    public function __construct($user = [])
    {
        global $pearDB;
        $this->user_id = $user['contact_id'] ?? null;
        $this->name = isset($user['contact_name'])
            ? html_entity_decode($user['contact_name'], ENT_QUOTES, 'UTF-8') : null;
        $this->alias = isset($user['contact_alias'])
            ? html_entity_decode($user['contact_alias'], ENT_QUOTES, 'UTF-8') : null;
        $this->email = isset($user['contact_email'])
            ? html_entity_decode($user['contact_email'], ENT_QUOTES, 'UTF-8') : null;
        $this->lang = $user['contact_lang'] ?? null;
        $this->passwd = $user['contact_passwd'] ?? null;
        $this->token = $user['contact_autologin_key'] ?? null;
        $this->admin = $user['contact_admin'] ?? null;
        $this->default_page = $user['default_page'] ?? CentreonAuth::DEFAULT_PAGE;
        $this->gmt = $user['contact_location'] ?? null;
        $this->showDeprecatedPages = (bool) ($user['show_deprecated_pages'] ?? false);
        $this->showDeprecatedCustomViews = (bool) ($user['show_deprecated_custom_views'] ?? false);
        $this->theme = $user['contact_theme'] ?? 'light';
        // Initiate ACL
        $this->access = new CentreonACL($this->user_id, $this->admin);
        $this->lcaTopo = $this->access->topology;
        $this->lcaTStr = $this->access->topologyStr;
        // Initiate Log Class
        $this->log = new CentreonUserLog($this->user_id, $pearDB);

        /**
         * Init rest api auth
         */
        $this->restApi = isset($user['reach_api']) && $user['reach_api'] == 1;
        $this->restApiRt = isset($user['reach_api_rt']) && $user['reach_api_rt'] == 1;

        // Init authentication type, could by local, openid, web-sso, saml
        $this->authType = $user['auth_type'] ?? 'unknown';
    }

    /**
     * @param $div_name
     *
     * @return int|mixed
     */
    public function showDiv($div_name = null)
    {
        global $pearDB;

        if (! isset($div_name)) {
            return 0;
        }

        return $_SESSION['_Div_' . $div_name] ?? 1;
    }

    /**
     * @param CentreonDB $pearDB
     *
     * @throws PDOException
     * @return array
     */
    public function getAllTopology($pearDB)
    {
        $DBRESULT = $pearDB->query('SELECT topology_page FROM topology WHERE topology_page IS NOT NULL');
        while ($topo = $DBRESULT->fetch()) {
            if (isset($topo['topology_page'])) {
                $lcaTopo[$topo['topology_page']] = 1;
            }
        }
        unset($topo);
        $DBRESULT->closeCursor();

        return $lcaTopo;
    }

    /**
     * Check if user is admin or had ACL
     *
     * @param string $sid
     * @param CentreonDB $pearDB
     *
     * @throws PDOException
     */
    public function checkUserStatus($sid, $pearDB): void
    {
        $query1 = 'SELECT contact_admin, contact_id FROM session, contact '
            . 'WHERE session.session_id = :session_id'
            . " AND contact.contact_id = session.user_id AND contact.contact_register = '1'";
        $statement = $pearDB->prepare($query1);
        $statement->bindValue(':session_id', $sid);
        $statement->execute();
        $admin = $statement->fetch(PDO::FETCH_ASSOC);
        $statement->closeCursor();

        $query2 = 'SELECT count(*) FROM `acl_group_contacts_relations` '
            . 'WHERE contact_contact_id = :contact_id';
        $statement = $pearDB->prepare($query2);
        $statement->bindValue(':contact_id', (int) $admin['contact_id'], PDO::PARAM_INT);
        $statement->execute();
        $admin2 = $statement->fetch(PDO::FETCH_ASSOC);
        $statement->closeCursor();

        $this->is_admin = 0;
        if ($admin['contact_admin']) {
            unset($admin);
            $this->is_admin = 1;
        } elseif (! $admin2['count(*)']) {
            unset($admin2);
            $this->is_admin = 1;
        }
    }

    // Getters

    /**
     * @return int|mixed|string|null
     */
    public function get_id()
    {
        return $this->user_id;
    }

    /**
     * @return string|null
     */
    public function get_name()
    {
        return $this->name;
    }

    /**
     * @return string|null
     */
    public function get_email()
    {
        return $this->email;
    }

    /**
     * @return string|null
     */
    public function get_alias()
    {
        return $this->alias;
    }

    /**
     * @return int
     */
    public function get_version()
    {
        return $this->version;
    }

    /**
     * @return string
     */
    public function get_lang(): string
    {
        $lang = $this->lang;

        // Get locale from browser
        if ($lang === 'browser') {
            if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
                $lang = Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']);
            }

            // check that the variable value end with .UTF-8 or add it
            $lang = (str_contains($lang, '.UTF-8')) ?: $lang . '.UTF-8';
        }

        return $lang;
    }

    /**
     * @return mixed|string|null
     */
    public function get_passwd()
    {
        return $this->passwd;
    }

    /**
     * @return int|string|null
     */
    public function get_admin()
    {
        return $this->admin;
    }

    /**
     * @return bool|null
     */
    public function is_admin()
    {
        return $this->is_admin;
    }

    /**
     * @return bool
     */
    public function doesShowDeprecatedPages()
    {
        return $this->showDeprecatedPages;
    }

    public function doesShowDeprecatedCustomViews()
    {
        return $this->showDeprecatedCustomViews;
    }

    // Setters

    /**
     * @param $id
     *
     * @return void
     */
    public function set_id($id): void
    {
        $this->user_id = $id;
    }

    /**
     * @param string $name
     *
     * @return void
     */
    public function set_name($name): void
    {
        $this->name = $name;
    }

    /**
     * @param string $email
     *
     * @return void
     */
    public function set_email($email): void
    {
        $this->email = $email;
    }

    /**
     * @param string $lang
     *
     * @return void
     */
    public function set_lang($lang): void
    {
        $this->lang = $lang;
    }

    /**
     * @param string $alias
     *
     * @return void
     */
    public function set_alias($alias): void
    {
        $this->alias = $alias;
    }

    /**
     * @param string $version
     *
     * @return void
     */
    public function set_version($version): void
    {
        $this->version = $version;
    }

    public function setPasswd(string $passwd): void
    {
        $this->passwd = $passwd;
    }

    public function setShowDeprecatedPages(bool $showDeprecatedPages): void
    {
        $this->showDeprecatedPages = $showDeprecatedPages;
    }

    public function setShowDeprecatedCustomViews(bool $showDeprecatedCustomViews): void
    {
        $this->showDeprecatedCustomViews = $showDeprecatedCustomViews;
    }

    // Methods

    /**
     * @return mixed|null
     */
    public function getMyGMT()
    {
        return $this->gmt;
    }

    /**
     * @param CentreonDB $db
     *
     * @throws PDOException
     * @return array|mixed
     */
    public function getUserList($db)
    {
        static $userList;

        if (! isset($userList)) {
            $userList = [];
            $res = $db->query(
                "SELECT contact_id, contact_name
                FROM contact
                WHERE contact_register = '1'
                AND contact_activate = '1'
                ORDER BY contact_name"
            );
            while ($row = $res->fetchRow()) {
                $userList[$row['contact_id']] = $row['contact_name'];
            }
        }

        return $userList;
    }

    /**
     * Get Contact Name
     *
     * @param CentreonDB $db
     * @param int $userId
     *
     * @throws PDOException
     * @return string
     */
    public function getContactName($db, $userId)
    {
        static $userNames;

        if (! isset($userNames)) {
            $userNames = [];
            $res = $db->query('SELECT contact_name, contact_id FROM contact');
            while ($row = $res->fetch()) {
                $userNames[$row['contact_id']] = $row['contact_name'];
            }
        }

        return $userNames[$userId] ?? null;
    }

    /**
     * Get Contact Parameters
     *
     * @param CentreonDB $db
     * @param array $parameters
     *
     * @throws PDOException
     * @return array
     */
    public function getContactParameters($db, $parameters = [])
    {
        $values = [];

        $queryParameters = '';
        if (is_array($parameters) && count($parameters)) {
            $queryParameters = 'AND cp_key IN ("';
            $queryParameters .= implode('","', $parameters);
            $queryParameters .= '") ';
        }

        $query = 'SELECT cp_key, cp_value '
            . 'FROM contact_param '
            . 'WHERE cp_contact_id = ' . $this->user_id . ' '
            . $queryParameters;

        $res = $db->query($query);
        while ($row = $res->fetch()) {
            $values[$row['cp_key']] = $row['cp_value'];
        }

        return $values;
    }

    /**
     * Set Contact Parameters
     *
     * @param CentreonDB $db
     * @param array $parameters
     *
     * @throws PDOException
     * @return null|void
     */
    public function setContactParameters($db, $parameters = [])
    {
        if (! count($parameters)) {
            return null;
        }
        $queryValues = [];
        $keys = array_keys($parameters);
        $deleteQuery = 'DELETE FROM contact_param WHERE cp_contact_id = :cp_contact_id AND cp_key IN( ';
        $queryValues[':cp_contact_id'] = $this->user_id;
        $queryKey = '';
        foreach ($keys as $key) {
            $queryKey .= ' :cp_key' . $key . ',';
            $queryValues[':cp_key' . $key] = $key;
        }
        $queryKey = rtrim($queryKey, ',');
        $deleteQuery .= $queryKey . ' )';
        $stmt = $db->prepare($deleteQuery);
        $stmt->execute($queryValues);

        $insertQuery = 'INSERT INTO contact_param (cp_key, cp_value, cp_contact_id) VALUES '
            . '(:cp_key, :cp_value, :cp_contact_id)';
        $sth = $db->prepare($insertQuery);
        foreach ($parameters as $key => $value) {
            $sth->bindParam(':cp_key', $key, PDO::PARAM_STR);
            $sth->bindParam(':cp_value', $value, PDO::PARAM_STR);
            $sth->bindParam(':cp_contact_id', $this->user_id, PDO::PARAM_INT);
            $sth->execute();
        }
    }

    /**
     * Get current Page
     *
     * @return int
     */
    public function getCurrentPage()
    {
        return $this->currentPage;
    }

    /**
     * Set current page
     *
     * @param int $currentPage
     * @return void
     */
    public function setCurrentPage($currentPage): void
    {
        $this->currentPage = $currentPage;
    }

    /**
     * Get theme
     *
     * @return string
     */
    public function getTheme()
    {
        return $this->theme;
    }

    /**
     * Set theme
     *
     * @param string $theme
     * @return void
     */
    public function setTheme($theme): void
    {
        $this->theme = $theme;
    }

    /**
     * Get token
     *
     * @return string
     */
    public function getToken()
    {
        return $this->token;
    }

    /**
     * Set token
     *
     * @param string $token
     * @return void
     */
    public function setToken($token): void
    {
        $this->token = $token;
    }

    /**
     * If the user has access to Rest API Configuration
     *
     * @return bool
     */
    public function hasAccessRestApiConfiguration()
    {
        return $this->restApi;
    }

    /**
     * If the user has access to Rest API Realtime
     *
     * @return bool
     */
    public function hasAccessRestApiRealtime()
    {
        return $this->restApiRt;
    }
}
