<?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 _CENTREON_PATH_ . 'www/include/common/vault-functions.php';

use App\Kernel;
use Centreon\Domain\Log\Logger;
use Core\Common\Application\Repository\ReadVaultRepositoryInterface;
use Core\Common\Infrastructure\FeatureFlags;
use Core\Security\Vault\Application\Repository\ReadVaultConfigurationRepositoryInterface;
use Core\Security\Vault\Domain\Model\VaultConfiguration;

/**
 * Test broker file config existance
 * @param $name
 */
function testExistence($name = null)
{
    global $pearDB, $form;

    $id = null;

    if (isset($form)) {
        $id = $form->getSubmitValue('id');
    }

    $dbResult = $pearDB->query("SELECT config_name, config_id
                                FROM `cfg_centreonbroker`
                                WHERE `config_name` = '" . htmlentities($name, ENT_QUOTES, 'UTF-8') . "'");
    $ndomod = $dbResult->fetch();
    if ($dbResult->rowCount() >= 1 && $ndomod['config_id'] == $id) {
        return true;
    }

    return ! ($dbResult->rowCount() >= 1 && $ndomod['config_id'] != $id);
}

/**
 * Enable a Centreon Broker configuration
 *
 * @param int $id The Centreon Broker configuration in database
 */
function enableCentreonBrokerInDB($id)
{
    global $pearDB;

    if (! $id) {
        return;
    }

    $query = "UPDATE cfg_centreonbroker SET config_activate = '1' WHERE config_id = :config_id";
    $statement = $pearDB->prepare($query);
    $statement->bindValue(':config_id', (int) $id, PDO::PARAM_INT);
    $statement->execute();
}

/**
 * Disable a Centreon Broker configuration
 *
 * @param int $id The Centreon Broker configuration in database
 */
function disablCentreonBrokerInDB($id)
{
    global $pearDB;

    if (! $id) {
        return;
    }

    $query = "UPDATE cfg_centreonbroker SET config_activate = '0' WHERE config_id = :config_id";
    $statement = $pearDB->prepare($query);
    $statement->bindValue(':config_id', (int) $id, PDO::PARAM_INT);
    $statement->execute();
}

/**
 * Delete Centreon Broker configurations
 *
 * @param array $id The Centreon Broker configuration in database
 * @param mixed $ids
 */
function deleteCentreonBrokerInDB($ids = [])
{
    global $pearDB;

    $brokerIds = array_keys($ids);

    $kernel = Kernel::createForWeb();
    /** @var Logger $logger */
    $logger = $kernel->getContainer()->get(Logger::class);
    /** @var ReadVaultConfigurationRepositoryInterface $readVaultConfigurationRepository */
    $readVaultConfigurationRepository = $kernel->getContainer()->get(
        ReadVaultConfigurationRepositoryInterface::class
    );
    /** @var FeatureFlags $featureFlagManager */
    $featureFlagManager = $kernel->getContainer()->get(FeatureFlags::class);
    $vaultConfiguration = $readVaultConfigurationRepository->find();

    /** @var Core\Common\Application\Repository\WriteVaultRepositoryInterface $writeVaultRepository */
    $writeVaultRepository = $kernel->getContainer()->get(Core\Common\Application\Repository\WriteVaultRepositoryInterface::class);
    $writeVaultRepository->setCustomPath(Core\Common\Infrastructure\Repository\AbstractVaultRepository::BROKER_VAULT_PATH);
    if ($featureFlagManager->isEnabled('vault_broker') && $vaultConfiguration !== null) {
        deleteBrokerConfigsFromVault($writeVaultRepository, $brokerIds);
    }

    $statement = $pearDB->prepare('DELETE FROM cfg_centreonbroker WHERE config_id = :config_id');
    foreach ($brokerIds as $id) {
        $statement->bindValue(':config_id', $id, PDO::PARAM_INT);
        $statement->execute();
    }
}

/**
 * Get the information of a server
 *
 * @param int $id
 * @return array
 */
function getCentreonBrokerInformation($id)
{
    global $pearDB;
    $query
        = 'SELECT config_name, config_filename, ns_nagios_server, stats_activate,
            config_write_timestamp, config_write_thread_id, config_activate, event_queue_max_size,
            event_queues_total_size, cache_directory, command_file, daemon, pool_size, log_directory, log_filename,
            log_max_size, bbdo_version
        FROM cfg_centreonbroker
        WHERE config_id = ' . $id;
    try {
        $res = $pearDB->query($query);
    } catch (PDOException $e) {
        $brokerConf = [
            'name' => '',
            'filename' => '',
            'log_directory' => '/var/log/centreon-broker/',
            'write_timestamp' => '1',
            'write_thread_id' => '1',
            'activate_watchdog' => '1',
            'activate' => '1',
            'event_queue_max_size' => '',
            'pool_size' => null,
        ];
    }
    $row = $res->fetch();
    if (! isset($brokerConf)) {
        $brokerConf = [
            'id' => $id,
            'name' => $row['config_name'],
            'filename' => $row['config_filename'],
            'ns_nagios_server' => $row['ns_nagios_server'],
            'activate' => $row['config_activate'],
            'activate_watchdog' => $row['daemon'],
            'stats_activate' => $row['stats_activate'],
            'write_timestamp' => $row['config_write_timestamp'],
            'write_thread_id' => $row['config_write_thread_id'],
            'event_queue_max_size' => $row['event_queue_max_size'],
            'event_queues_total_size' => $row['event_queues_total_size'],
            'cache_directory' => $row['cache_directory'],
            'command_file' => $row['command_file'],
            'daemon' => $row['daemon'],
            'pool_size' => $row['pool_size'],
            'log_directory' => $row['log_directory'],
            'log_filename' => $row['log_filename'],
            'log_max_size' => $row['log_max_size'],
            'bbdo_version' => $row['bbdo_version'],
        ];
    }
    // Log
    $brokerLogConf = [];
    $query = 'SELECT log.`name`, relation.`id_level`
            FROM `cb_log` log
            LEFT JOIN `cfg_centreonbroker_log` relation
                ON relation.`id_log`  = log.`id`
            WHERE relation.`id_centreonbroker` = ' . $id;
    try {
        $res = $pearDB->query($query);
    } catch (PDOException $e) {
        return $brokerConf;
    }
    while ($row = $res->fetch()) {
        $brokerLogConf['log_' . $row['name']] = $row['id_level'];
    }
    $result = array_merge($brokerConf, $brokerLogConf);

    return $result;
}

/**
 * Duplicate a configuration
 *
 * @param array $ids List of id CentreonBroker configuration
 * @param array $nbr List of number a duplication
 * @param mixed $nbrDup
 */
function multipleCentreonBrokerInDB($ids, $nbrDup)
{
    global $pearDB;
    foreach ($ids as $id => $value) {
        $cbObj = new CentreonConfigCentreonBroker($pearDB);

        $row = getCfgBrokerData((int) $id);

        // Prepare values
        $values = [];
        $values['activate_watchdog']['activate_watchdog'] = '0';
        $values['activate']['activate'] = '0';
        $values['ns_nagios_server'] = $row['ns_nagios_server'];
        $values['event_queue_max_size'] = $row['event_queue_max_size'];
        $values['cache_directory'] = $row['cache_directory'];
        $values['activate_watchdog']['activate_watchdog'] = $row['daemon'];
        $values['output'] = [];
        $values['input'] = [];
        $brokerCfgInfoData = getCfgBrokerInfoData((int) $id);

        foreach ($brokerCfgInfoData as $rowOpt) {
            if ($rowOpt['config_key'] == 'filters') {
                continue;
            }
            if ($rowOpt['config_key'] == 'category') {
                $configKey = 'filters__' . $rowOpt['config_group_id'] . '__category';
                $values[$rowOpt['config_group']][$rowOpt['config_group_id']][$configKey][]
                    = $rowOpt['config_value'];
            } elseif ($rowOpt['fieldIndex'] !== null) {
                $configKey = $rowOpt['config_key'] . '_' . $rowOpt['fieldIndex'];
                $values[$rowOpt['config_group']][$rowOpt['config_group_id']][$configKey] = $rowOpt['config_value'];
            } else {
                $values[$rowOpt['config_group']][$rowOpt['config_group_id']][$rowOpt['config_key']]
                    = $rowOpt['config_value'];
            }

        }

        // Convert values radio button
        foreach ($values as $group => $groups) {
            if (is_array($groups)) {
                foreach ($groups as $gid => $infos) {
                    if (isset($infos['blockId'])) {
                        [$tagId, $typeId] = explode('_', $infos['blockId']);
                        $fieldtype = $cbObj->getFieldtypes($typeId);
                    } else {
                        $fieldtype = [];
                    }

                    if (is_array($infos)) {
                        foreach ($infos as $key => $value) {
                            if (isset($fieldtype[$key]) && $fieldtype[$key] == 'radio') {
                                $values[$group][$gid][$key] = [$key => $value];
                            }
                        }
                    }
                }
            }
        }

        // Copy the configuration
        $j = 1;
        $query = 'SELECT COUNT(*) as nb FROM cfg_centreonbroker WHERE config_name = :config_name';
        $statement = $pearDB->prepare($query);
        for ($i = 1; $i <= $nbrDup[$id]; $i++) {
            $nameNOk = true;

            // Find the name
            while ($nameNOk) {
                $newname = $row['config_name'] . '_' . $j;
                $newfilename = $j . '_' . $row['config_filename'];
                $statement->bindValue(':config_name', $newname, PDO::PARAM_STR);
                $statement->execute();
                $rowNb = $statement->fetch(PDO::FETCH_ASSOC);
                if ($rowNb['nb'] == 0) {
                    $nameNOk = false;
                }
                $j++;
            }
            $values['name'] = $newname;
            $values['filename'] = $newfilename;

            retrieveOriginalPasswordValuesFromVault($values);

            $cbObj->insertConfig($values);
        }
    }
}

/**
 * Rule to check if given value is positive and numeric
 *
 * @param $size
 * @return bool
 */
function isPositiveNumeric($size): bool
{
    if (! is_numeric($size)) {
        return false;
    }
    $isPositive = false;
    if ((int) $size === (int) abs($size)) {
        $isPositive = true;
    }

    return $isPositive;
}

/**
 * Getting Centreon CFG broker data
 *
 * @param int $configId
 * @return array
 */
function getCfgBrokerData(int $configId): array
{
    global $pearDB;

    $query = 'SELECT config_name, config_filename, config_activate, ns_nagios_server,
            event_queue_max_size, cache_directory, daemon '
             . 'FROM cfg_centreonbroker '
             . 'WHERE config_id = :config_id ';
    try {
        $statement = $pearDB->prepare($query);
        $statement->bindValue(':config_id', $configId, PDO::PARAM_INT);
        $statement->execute();
        $cfgBrokerData = $statement->fetch(PDO::FETCH_ASSOC);
    } catch (PDOException $exception) {
        throw new Exception('Cannot fetch Broker config data');
    }
    $statement->closeCursor();

    return $cfgBrokerData;
}

/**
 * Getting Centreon CFG broker Info data
 *
 * @param int $configId
 * @return array
 */
function getCfgBrokerInfoData(int $configId): array
{
    global $pearDB;

    $query = <<<'SQL'
        SELECT config_key, config_value, config_group, config_group_id, fieldIndex
        FROM cfg_centreonbroker_info
        WHERE config_id = :config_id
        SQL;
    try {
        $statement = $pearDB->prepare($query);
        $statement->bindValue(':config_id', $configId, PDO::PARAM_INT);
        $statement->execute();
        $cfgBrokerInfoData = $statement->fetchAll(PDO::FETCH_ASSOC);
    } catch (PDOException $exception) {
        throw new Exception('Cannot fetch Broker info config data');
    }
    $statement->closeCursor();

    return $cfgBrokerInfoData;
}

/**
 * Replace the vaultPath by the actual value in the values array.
 *
 * @param array{
 *  name:string,
 *  output:array<string,array>,
 *  input:array<string,array>
 * } $values
 */
function retrieveOriginalPasswordValuesFromVault(array &$values): void
{
    $kernel = Kernel::createForWeb();
    /** @var ReadVaultConfigurationRepositoryInterface $readVaultConfigurationRepository */
    $readVaultConfigurationRepository = $kernel->getContainer()->get(
        ReadVaultConfigurationRepositoryInterface::class
    );
    $vaultConfiguration = $readVaultConfigurationRepository->find();

    if ($vaultConfiguration !== null) {
        /** @var Logger $logger */
        $logger = $kernel->getContainer()->get(Logger::class);
        /** @var ReadVaultRepositoryInterface $readVaultRepository */
        $readVaultRepository = $kernel->getContainer()->get(ReadVaultRepositoryInterface::class);
        foreach (['input', 'output'] as $tag) {
            foreach ($values[$tag] as $key => $inputOutput) {
                foreach ($inputOutput as $name => $value) {
                    if (is_string($value) && str_starts_with($value, VaultConfiguration::VAULT_PATH_PATTERN)) {
                        [$groupName, $subName] = explode('__', $name);
                        [$subName, $subKey] = explode('_', $subName);
                        if ($subName === 'value') {
                            $vaultKey = implode(
                                '_',
                                [$inputOutput['name'], $groupName, $inputOutput["{$groupName}__name_{$subKey}"]]
                            );
                        } else {
                            $vaultKey = $inputOutput['name'] . '_' . $name;
                        }

                        $passwordValue = findBrokerConfigValueFromVault(
                            $readVaultRepository,
                            $logger,
                            $vaultKey,
                            $value,
                        );
                        $values[$tag][$key][$name] = $passwordValue;
                    }
                }
            }
        }
    }
}
