<?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
 *
 */

use Adaptation\Log\LoggerPassword;
use Core\Common\Domain\Exception\RepositoryException;

require_once __DIR__ . '/../../../class/centreonContact.class.php';
require_once __DIR__ . '/../../../class/centreonAuth.class.php';

function testExistence($name = null)
{
    global $pearDB, $centreon;

    $query = "SELECT contact_name, contact_id FROM contact WHERE contact_name = '"
        . htmlentities($name, ENT_QUOTES, 'UTF-8') . "'";
    $dbResult = $pearDB->query($query);
    $contact = $dbResult->fetch();
    // Modif case
    if ($dbResult->rowCount() >= 1 && $contact['contact_id'] == $centreon->user->get_id()) {
        return true;
    }

    return ! ($dbResult->rowCount() >= 1 && $contact['contact_id'] != $centreon->user->get_id());
    // Duplicate entry

}

function testAliasExistence($alias = null)
{
    global $pearDB, $centreon;

    $query = 'SELECT contact_alias, contact_id FROM contact '
        . "WHERE contact_alias = '" . htmlentities($alias, ENT_QUOTES, 'UTF-8') . "'";
    $dbResult = $pearDB->query($query);
    $contact = $dbResult->fetch();

    // Modif case
    if ($dbResult->rowCount() >= 1 && $contact['contact_id'] == $centreon->user->get_id()) {
        return true;
    }

    return ! ($dbResult->rowCount() >= 1 && $contact['contact_id'] != $centreon->user->get_id());
    // Duplicate entry

}

function updateNotificationOptions($contact_id)
{
    global $form, $pearDB;

    $pearDB->query('DELETE FROM contact_param
        WHERE cp_contact_id = ' . $pearDB->escape($contact_id) . "
        AND cp_key LIKE 'monitoring%notification%'");
    $data = $form->getSubmitValues();
    foreach ($data as $k => $v) {
        if (preg_match('/^monitoring_(host|svc)_notification/', $k)) {
            $query = 'INSERT INTO contact_param (cp_key, cp_value, cp_contact_id) '
                . "VALUES ('" . $pearDB->escape($k) . "', '1', " . $pearDB->escape($contact_id) . ')';
            $pearDB->query($query);
        } elseif (preg_match('/^monitoring_sound/', $k)) {
            $query = 'INSERT INTO contact_param (cp_key, cp_value, cp_contact_id) '
                . "VALUES ('" . $pearDB->escape($k) . "', '" . $pearDB->escape($v) . "', "
                . $pearDB->escape($contact_id) . ')';
            $pearDB->query($query);
        }
    }
    unset($_SESSION['centreon_notification_preferences']);
}

/**
 * @param $contact_id
 *
 * @throws InvalidArgumentException
 * @throws PDOException
 * @throws RepositoryException
 * @return void
 */
function updateContactInDB($contact_id = null): void
{
    if (! $contact_id) {
        return;
    }
    updateContact($contact_id);
    updateNotificationOptions($contact_id);
}

/**
 * @param $contactId
 *
 * @throws PDOException
 * @throws RepositoryException
 * @return void
 */
function updateContact($contactId = null): void
{
    global $form, $pearDB, $centreon;

    if (! $contactId) {
        return;
    }

    $submitValues = $form->getSubmitValues();
    // remove illegal chars in data sent by the user
    $submitValues['contact_name'] = CentreonUtils::escapeSecure($submitValues['contact_name'], CentreonUtils::ESCAPE_ILLEGAL_CHARS);
    $submitValues['contact_alias'] = CentreonUtils::escapeSecure($submitValues['contact_alias'], CentreonUtils::ESCAPE_ILLEGAL_CHARS);
    $submitValues['contact_email'] = ! empty($submitValues['contact_email'])
        ? CentreonUtils::escapeSecure($submitValues['contact_email'], CentreonUtils::ESCAPE_ILLEGAL_CHARS) : '';
    $submitValues['contact_pager'] = ! empty($submitValues['contact_pager'])
        ? CentreonUtils::escapeSecure($submitValues['contact_pager'], CentreonUtils::ESCAPE_ILLEGAL_CHARS) : '';
    $submitValues['contact_autologin_key'] = ! empty($submitValues['contact_autologin_key'])
        ? CentreonUtils::escapeSecure($submitValues['contact_autologin_key'], CentreonUtils::ESCAPE_ILLEGAL_CHARS) : '';
    $submitValues['contact_lang'] = ! empty($submitValues['contact_lang'])
        ? CentreonUtils::escapeSecure($submitValues['contact_lang'], CentreonUtils::ESCAPE_ILLEGAL_CHARS) : '';

    $rq = 'UPDATE contact SET '
          . 'contact_name = :contactName, '
          . 'contact_alias = :contactAlias, '
          . 'contact_location = :contactLocation, '
          . 'contact_lang = :contactLang, '
          . 'contact_email = :contactEmail, '
          . 'contact_pager = :contactPager, '
          . 'default_page = :defaultPage, '
          . 'show_deprecated_pages = :showDeprecatedPages, '
          . 'contact_autologin_key = :contactAutologinKey, '
          . 'show_deprecated_custom_views = :showDeprecatedCustomViews';
    $rq .= ' WHERE contact_id = :contactId';

    $stmt = $pearDB->prepare($rq);
    $stmt->bindValue(':contactName', $submitValues['contact_name'], PDO::PARAM_STR);
    $stmt->bindValue(':contactAlias', $submitValues['contact_alias'], PDO::PARAM_STR);
    $stmt->bindValue(':contactLang', $submitValues['contact_lang'], PDO::PARAM_STR);
    $stmt->bindValue(
        ':contactEmail',
        ! empty($submitValues['contact_email']) ? $submitValues['contact_email'] : null,
        PDO::PARAM_STR
    );
    $stmt->bindValue(
        ':contactPager',
        ! empty($submitValues['contact_pager']) ? $submitValues['contact_pager'] : null,
        PDO::PARAM_STR
    );
    $stmt->bindValue(
        ':contactAutologinKey',
        ! empty($submitValues['contact_autologin_key']) ? $submitValues['contact_autologin_key'] : null,
        PDO::PARAM_STR
    );
    $stmt->bindValue(
        ':contactLocation',
        ! empty($submitValues['contact_location']) ? $submitValues['contact_location'] : null,
        PDO::PARAM_INT
    );
    $stmt->bindValue(':defaultPage', ! empty($submitValues['default_page']) ? $submitValues['default_page'] : null, PDO::PARAM_INT);
    $stmt->bindValue(':showDeprecatedPages', isset($submitValues['show_deprecated_pages']) ? 1 : 0, PDO::PARAM_STR);
    $stmt->bindValue(
        ':showDeprecatedCustomViews',
        isset($submitValues['show_deprecated_custom_views']) ? '1' : '0',
        PDO::PARAM_STR
    );
    $stmt->bindValue(':contactId', $contactId, PDO::PARAM_INT);
    $stmt->execute();

    if (isset($submitValues['contact_passwd']) && ! empty($submitValues['contact_passwd'])) {
        $hashedPassword = password_hash($submitValues['contact_passwd'], CentreonAuth::PASSWORD_HASH_ALGORITHM);

        try {
            $contact = new CentreonContact($pearDB);
            $contact->renewPasswordByContactId($contactId, $hashedPassword);

            $centreon->user->setPasswd($hashedPassword);

            LoggerPassword::create()->success(
                initiatorId: (int) $centreon->user->get_id(),
                targetId: (int) $centreon->user->get_id(),
            );
        } catch (PDOException $e) {
            LoggerPassword::create()->warning(
                reason: 'password update failed',
                initiatorId: (int) $centreon->user->get_id(),
                targetId: (int) $centreon->user->get_id(),
                exception: $e
            );

            throw new RepositoryException(
                message: 'Unable to update password for contact id ' . $contactId,
                previous: $e
            );
        }
    }

    // Update user object..
    $centreon->user->name = $submitValues['contact_name'];
    $centreon->user->alias = $submitValues['contact_alias'];
    $centreon->user->lang = $submitValues['contact_lang'];
    $centreon->user->email = $submitValues['contact_email'];
    $centreon->user->setToken($submitValues['contact_autologin_key'] ?? "''");
}

/**
 * @param array<string,mixed> $fields
 *
 * @return array<string,string>|true
 */
function validatePasswordModification(array $fields): array|true
{
    global $pearDB, $centreon;
    $newPassword = $fields['contact_passwd'];
    $confirmPassword = $fields['contact_passwd2'];
    $currentPassword = $fields['current_password'];
    $contactId = (int) $centreon->user->get_id();

    // If the user does not want to change his password, we do not need to check it
    if (empty($newPassword) && empty($confirmPassword) && empty($currentPassword)) {
        return true;
    }

    // If the user only provided a confirmation password, he must provide a new password and a current password
    if (empty($newPassword) && ! empty($confirmPassword) && empty($currentPassword)) {
        LoggerPassword::create()->warning(
            reason: 'new password or current password not provided',
            initiatorId: (int) $centreon->user->get_id(),
            targetId: (int) $centreon->user->get_id(),
        );

        return ['contact_passwd2' => _('Please fill in all password fields')];
    }

    // If the user only provided his current password, he must provide a new password
    if (empty($newPassword) && ! empty($currentPassword)) {
        LoggerPassword::create()->warning(
            reason: 'new password not provided',
            initiatorId: (int) $centreon->user->get_id(),
            targetId: (int) $centreon->user->get_id(),
        );

        return ['current_password' => _('Please fill in all password fields')];
    }

    // If the user wants to change his password, he must provide his current password
    if (! empty($newPassword) && empty($currentPassword)) {
        LoggerPassword::create()->warning(
            reason: 'current password not provided',
            initiatorId: (int) $centreon->user->get_id(),
            targetId: (int) $centreon->user->get_id(),
        );

        return ['current_password' => _('Please fill in all password fields')];
    }

    // If the user provided a current password, we check if it matches the one in the database
    if (! empty($currentPassword) && password_verify($currentPassword, $centreon->user->passwd) === false) {
        LoggerPassword::create()->warning(
            reason: 'current password wrong',
            initiatorId: (int) $centreon->user->get_id(),
            targetId: (int) $centreon->user->get_id(),
        );

        return ['current_password' => _('Authentication failed')];
    }

    try {
        $contact = new CentreonContact($pearDB);
        $contact->respectPasswordPolicyOrFail($newPassword, $contactId);

        return true;
    } catch (Exception $e) {
        LoggerPassword::create()->warning(
            reason: 'new password does not respect password policy',
            initiatorId: (int) $centreon->user->get_id(),
            targetId: (int) $centreon->user->get_id(),
            exception: $e,
        );

        return ['contact_passwd' => $e->getMessage()];
    }
}

/**
 * @param array<string,mixed> $fields
 * @return array<string,string>|bool
 */
function checkAutologinValue(array $fields)
{
    global $pearDB, $centreon;
    $errors = [];

    if (! empty($fields['contact_autologin_key'])) {
        $contactId = $centreon->user->get_id();
        $statement = $pearDB->prepare(
            'SELECT * FROM `contact_password` WHERE contact_id = :contactId ORDER BY creation_date DESC LIMIT 1'
        );
        $statement->bindValue(':contactId', $contactId, PDO::PARAM_INT);
        $statement->execute();

        if (
            ($result = $statement->fetch(PDO::FETCH_ASSOC))
            && password_verify($fields['contact_autologin_key'], $result['password'])
        ) {
            $errors['contact_autologin_key'] = _('Your autologin key must be different than your current password');
        } elseif (
            ! empty($fields['contact_passwd'])
            && $fields['contact_passwd'] === $fields['contact_autologin_key']
        ) {
            $errorMessage = _('Your new password and autologin key must be different');
            $errors['contact_passwd'] = $errorMessage;
            $errors['contact_autologin_key'] = $errorMessage;

            LoggerPassword::create()->warning(
                reason: 'new password and autologin key are the same',
                initiatorId: (int) $centreon->user->get_id(),
                targetId: (int) $centreon->user->get_id(),
            );
        }
    }

    return $errors !== [] ? $errors : true;
}
function updateNonLocalContactInDB($contact_id = null): void
{
    global $pearDB, $centreon, $form;

    if (! $contact_id) {
        return;
    }
    $ret = $form->getSubmitValues();
    $ret['contact_pager'] = ! empty($ret['contact_pager'])
        ? CentreonUtils::escapeSecure($ret['contact_pager'], CentreonUtils::ESCAPE_ILLEGAL_CHARS) : '';
    $ret['contact_lang'] = ! empty($ret['contact_lang'])
        ? CentreonUtils::escapeSecure($ret['contact_lang'], CentreonUtils::ESCAPE_ILLEGAL_CHARS) : '';

    $rq = 'UPDATE contact SET '
        . 'contact_location = :contactLocation, '
        . 'contact_lang = :contactLang, '
        . 'contact_pager = :contactPager, '
        . 'default_page = :defaultPage, '
        . 'show_deprecated_pages = :showDeprecatedPages, '
        . 'show_deprecated_custom_views = :showDeprecatedCustomViews';
    $rq .= ' WHERE contact_id = :contactId';

    $stmt = $pearDB->prepare($rq);
    $stmt->bindValue(':contactLang', $ret['contact_lang'], PDO::PARAM_STR);
    $stmt->bindValue(
        ':contactPager',
        ! empty($ret['contact_pager']) ? $ret['contact_pager'] : null,
        PDO::PARAM_STR
    );
    $stmt->bindValue(
        ':contactLocation',
        ! empty($ret['contact_location']) ? $ret['contact_location'] : null,
        PDO::PARAM_INT
    );

    $stmt->bindValue(':defaultPage', ! empty($ret['default_page']) ? $ret['default_page'] : null, PDO::PARAM_INT);
    $stmt->bindValue(':showDeprecatedPages', isset($ret['show_deprecated_pages']) ? 1 : 0, PDO::PARAM_STR);
    $stmt->bindValue(
        ':showDeprecatedCustomViews',
        isset($ret['show_deprecated_custom_views']) ? '1' : '0',
        PDO::PARAM_STR
    );
    $stmt->bindValue(':contactId', $contact_id, PDO::PARAM_INT);
    $stmt->execute();
    $stmt->closeCursor();

    // Update user object..
    $centreon->user->lang = $ret['contact_lang'];
}
