<?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 Core\ActionLog\Domain\Model\ActionLog;

if (! isset($centreon)) {
    exit();
}

function includeExcludeTimeperiods($tpId, $includeTab = [], $excludeTab = [])
{
    global $pearDB;

    // Insert inclusions
    if (isset($includeTab) && is_array($includeTab)) {
        $str = '';
        foreach ($includeTab as $tpIncludeId) {
            if ($str != '') {
                $str .= ', ';
            }
            $str .= "('" . $tpId . "', '" . $tpIncludeId . "')";
        }
        if (strlen($str)) {
            $query = 'INSERT INTO timeperiod_include_relations (timeperiod_id, timeperiod_include_id ) VALUES ' . $str;
            $pearDB->query($query);
        }
    }

    // Insert exclusions
    if (isset($excludeTab) && is_array($excludeTab)) {
        $str = '';
        foreach ($excludeTab as $tpExcludeId) {
            if ($str != '') {
                $str .= ', ';
            }
            $str .= "('" . $tpId . "', '" . $tpExcludeId . "')";
        }
        if (strlen($str)) {
            $query = 'INSERT INTO timeperiod_exclude_relations (timeperiod_id, timeperiod_exclude_id ) VALUES ' . $str;
            $pearDB->query($query);
        }
    }
}

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

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

    $query = 'SELECT tp_name, tp_id FROM timeperiod WHERE tp_name = :tp_name';
    $statement = $pearDB->prepare($query);
    $statement->bindValue(
        ':tp_name',
        htmlentities($centreon->checkIllegalChar($name), ENT_QUOTES, 'UTF-8'),
        PDO::PARAM_STR
    );
    $statement->execute();
    $tp = $statement->fetch(PDO::FETCH_ASSOC);
    // Modif case
    if ($statement->rowCount() >= 1 && $tp['tp_id'] == $id) {
        return true;
    }

    return ! ($statement->rowCount() >= 1 && $tp['tp_id'] != $id);  // Duplicate entry
}

function deleteTimeperiodInDB($timeperiods = [])
{
    global $pearDB, $centreon;
    foreach ($timeperiods as $key => $value) {
        $dbResult2 = $pearDB->query("SELECT tp_name FROM `timeperiod` WHERE `tp_id` = '" . $key . "' LIMIT 1");
        $row = $dbResult2->fetch();
        $dbResult = $pearDB->query("DELETE FROM timeperiod WHERE tp_id = '" . $key . "'");
        $centreon->CentreonLogAction->insertLog(
            object_type: ActionLog::OBJECT_TYPE_TIMEPERIOD,
            object_id: $key,
            object_name: $row['tp_name'],
            action_type: ActionLog::ACTION_TYPE_DELETE
        );
    }
}

function multipleTimeperiodInDB($timeperiods = [], $nbrDup = [])
{
    global $centreon;

    foreach ($timeperiods as $key => $value) {
        global $pearDB;

        $fields = [];
        $dbResult = $pearDB->query("SELECT * FROM timeperiod WHERE tp_id = '" . $key . "' LIMIT 1");

        $query = "SELECT days, timerange FROM timeperiod_exceptions WHERE timeperiod_id = '" . $key . "'";
        $res = $pearDB->query($query);
        while ($row = $res->fetch()) {
            foreach ($row as $keyz => $valz) {
                $fields[$keyz] = $valz;
            }
        }

        $row = $dbResult->fetch();
        $row['tp_id'] = null;
        for ($i = 1; $i <= $nbrDup[$key]; $i++) {
            $val = [];
            foreach ($row as $key2 => $value2) {
                if ($key2 == 'tp_name') {
                    $value2 .= '_' . $i;
                }
                if ($key2 == 'tp_name') {
                    $tp_name = $value2;
                }
                $val[] = $value2 ?: null;
                if ($key2 != 'tp_id') {
                    $fields[$key2] = $value2;
                }
                if (isset($tp_name)) {
                    $fields['tp_name'] = $tp_name;
                }
            }
            if (isset($tp_name) && testTPExistence($tp_name)) {
                $params = [
                    'values' => $val,
                    'timeperiod_id' => $key,
                ];
                $tpId = duplicateTimePeriod($params);
                $centreon->CentreonLogAction->insertLog(
                    object_type: ActionLog::OBJECT_TYPE_TIMEPERIOD,
                    object_id: $tpId,
                    object_name: $tp_name,
                    action_type: ActionLog::ACTION_TYPE_ADD,
                    fields: $fields
                );
            }
        }
    }
}

function updateTimeperiodInDB($tp_id = null)
{
    if (! $tp_id) {
        return;
    }
    updateTimeperiod($tp_id);
}

function updateTimeperiod($tp_id, $params = [])
{
    global $form, $pearDB, $centreon;

    if (! $tp_id) {
        return;
    }
    $ret = [];
    $ret = count($params) ? $params : $form->getSubmitValues();

    $ret['tp_name'] = $centreon->checkIllegalChar($ret['tp_name']);

    $rq = 'UPDATE timeperiod ';
    $rq .= "SET tp_name = '" . htmlentities($ret['tp_name'], ENT_QUOTES, 'UTF-8') . "', "
        . "tp_alias = '" . htmlentities($ret['tp_alias'], ENT_QUOTES, 'UTF-8') . "', "
        . "tp_sunday = '" . htmlentities($ret['tp_sunday'], ENT_QUOTES, 'UTF-8') . "', "
        . "tp_monday = '" . htmlentities($ret['tp_monday'], ENT_QUOTES, 'UTF-8') . "', "
        . "tp_tuesday = '" . htmlentities($ret['tp_tuesday'], ENT_QUOTES, 'UTF-8') . "', "
        . "tp_wednesday = '" . htmlentities($ret['tp_wednesday'], ENT_QUOTES, 'UTF-8') . "', "
        . "tp_thursday = '" . htmlentities($ret['tp_thursday'], ENT_QUOTES, 'UTF-8') . "', "
        . "tp_friday = '" . htmlentities($ret['tp_friday'], ENT_QUOTES, 'UTF-8') . "', "
        . "tp_saturday = '" . htmlentities($ret['tp_saturday'], ENT_QUOTES, 'UTF-8') . "' "
        . "WHERE tp_id = '" . $tp_id . "'";
    $pearDB->query($rq);

    $pearDB->query("DELETE FROM timeperiod_include_relations WHERE timeperiod_id = '" . $tp_id . "'");
    $pearDB->query("DELETE FROM timeperiod_exclude_relations WHERE timeperiod_id = '" . $tp_id . "'");

    if (! isset($ret['tp_include'])) {
        $ret['tp_include'] = [];
    }
    if (! isset($ret['tp_exclude'])) {
        $ret['tp_exclude'] = [];
    }

    includeExcludeTimeperiods($tp_id, $ret['tp_include'], $ret['tp_exclude']);

    if (isset($_POST['nbOfExceptions'])) {
        $my_tab = $_POST;
        $already_stored = [];
        $pearDB->query("DELETE FROM `timeperiod_exceptions` WHERE `timeperiod_id`='" . $tp_id . "'");
        for ($i = 0; $i <= $my_tab['nbOfExceptions']; $i++) {
            $exInput = 'exceptionInput_' . $i;
            $exValue = 'exceptionTimerange_' . $i;
            if (isset($my_tab[$exInput])
                && ! isset($already_stored[strtolower($my_tab[$exInput])])
                && $my_tab[$exInput]
            ) {
                $query = 'INSERT INTO timeperiod_exceptions (`timeperiod_id`, `days`, `timerange`) '
                    . "VALUES ('" . $tp_id . "', LOWER('" . $pearDB->escape($my_tab[$exInput]) . "'), '"
                    . $pearDB->escape($my_tab[$exValue]) . "')";
                $pearDB->query($query);
                $fields[$my_tab[$exInput]] = $my_tab[$exValue];
                $already_stored[strtolower($my_tab[$exInput])] = 1;
            }
        }
    }

    // Prepare value for changelog
    $fields = CentreonLogAction::prepareChanges($ret);
    $centreon->CentreonLogAction->insertLog(
        object_type: ActionLog::OBJECT_TYPE_TIMEPERIOD,
        object_id: $tp_id,
        object_name: $ret['tp_name'],
        action_type: ActionLog::ACTION_TYPE_CHANGE,
        fields: $fields
    );
}

function insertTimeperiodInDB($ret = [])
{
    return insertTimeperiod($ret);
}

function insertTimeperiod($ret = [], $exceptions = null)
{
    global $form, $pearDB, $centreon;

    if (! count($ret)) {
        $ret = $form->getSubmitValues();
    }

    $ret['tp_name'] = $centreon->checkIllegalChar($ret['tp_name']);

    $rq = 'INSERT INTO timeperiod ';
    $rq .= '(tp_name, tp_alias, tp_sunday, tp_monday, tp_tuesday, tp_wednesday, tp_thursday, tp_friday, tp_saturday) ';
    $rq .= 'VALUES (';
    isset($ret['tp_name']) && $ret['tp_name'] != null
        ? $rq .= "'" . htmlentities($ret['tp_name'], ENT_QUOTES, 'UTF-8') . "', "
        : $rq .= 'NULL, ';
    isset($ret['tp_alias']) && $ret['tp_alias'] != null
        ? $rq .= "'" . htmlentities($ret['tp_alias'], ENT_QUOTES, 'UTF-8') . "', "
        : $rq .= 'NULL, ';
    isset($ret['tp_sunday']) && $ret['tp_sunday'] != null
        ? $rq .= "'" . htmlentities($ret['tp_sunday'], ENT_QUOTES, 'UTF-8') . "', "
        : $rq .= 'NULL, ';
    isset($ret['tp_monday']) && $ret['tp_monday'] != null
        ? $rq .= "'" . htmlentities($ret['tp_monday'], ENT_QUOTES, 'UTF-8') . "', "
        : $rq .= 'NULL, ';
    isset($ret['tp_tuesday']) && $ret['tp_tuesday'] != null
        ? $rq .= "'" . htmlentities($ret['tp_tuesday'], ENT_QUOTES, 'UTF-8') . "', "
        : $rq .= 'NULL, ';
    isset($ret['tp_wednesday']) && $ret['tp_wednesday'] != null
        ? $rq .= "'" . htmlentities($ret['tp_wednesday'], ENT_QUOTES, 'UTF-8') . "', "
        : $rq .= 'NULL, ';
    isset($ret['tp_thursday']) && $ret['tp_thursday'] != null
        ? $rq .= "'" . htmlentities($ret['tp_thursday'], ENT_QUOTES, 'UTF-8') . "', "
        : $rq .= 'NULL, ';
    isset($ret['tp_friday']) && $ret['tp_friday'] != null
        ? $rq .= "'" . htmlentities($ret['tp_friday'], ENT_QUOTES, 'UTF-8') . "', "
        : $rq .= 'NULL, ';
    isset($ret['tp_saturday']) && $ret['tp_saturday'] != null
        ? $rq .= "'" . htmlentities($ret['tp_saturday'], ENT_QUOTES, 'UTF-8') . "'"
        : $rq .= 'NULL';
    $rq .= ')';
    $pearDB->query($rq);
    $dbResult = $pearDB->query('SELECT MAX(tp_id) FROM timeperiod');
    $tp_id = $dbResult->fetch();

    if (! isset($ret['tp_include'])) {
        $ret['tp_include'] = [];
    }
    if (! isset($ret['tp_exclude'])) {
        $ret['tp_exclude'] = [];
    }

    includeExcludeTimeperiods($tp_id['MAX(tp_id)'], $ret['tp_include'], $ret['tp_exclude']);

    // Insert exceptions
    if (isset($exceptions)) {
        $my_tab = $exceptions;
    } elseif (isset($_POST['nbOfExceptions'])) {
        $my_tab = $_POST;
    }
    if (isset($my_tab['nbOfExceptions'])) {
        $already_stored = [];
        $query = 'INSERT INTO timeperiod_exceptions (`timeperiod_id`, `days`, `timerange`) '
                 . 'VALUES (:timeperiod_id, :days, :timerange)';
        $statement = $pearDB->prepare($query);
        for ($i = 0; $i <= $my_tab['nbOfExceptions']; $i++) {
            $exInput = 'exceptionInput_' . $i;
            $exValue = 'exceptionTimerange_' . $i;
            if (
                isset($my_tab[$exInput]) && ! isset($already_stored[strtolower($my_tab[$exInput])])
                && $my_tab[$exInput]
            ) {
                $statement->bindValue(':timeperiod_id', (int) $tp_id['MAX(tp_id)'], PDO::PARAM_INT);
                $statement->bindValue(':days', strtolower($my_tab[$exInput]), PDO::PARAM_STR);
                $statement->bindValue(':timerange', $my_tab[$exValue], PDO::PARAM_STR);
                $statement->execute();
                $fields[$my_tab[$exInput]] = $my_tab[$exValue];
                $already_stored[strtolower($my_tab[$exInput])] = 1;
            }
        }
    }

    // Prepare value for changelog
    $fields = CentreonLogAction::prepareChanges($ret);
    $centreon->CentreonLogAction->insertLog(
        object_type: ActionLog::OBJECT_TYPE_TIMEPERIOD,
        object_id: $tp_id['MAX(tp_id)'],
        object_name: htmlentities($ret['tp_name'], ENT_QUOTES, 'UTF-8'),
        action_type: ActionLog::ACTION_TYPE_ADD,
        fields: $fields
    );

    return $tp_id['MAX(tp_id)'];
}

function checkHours($hourString)
{
    if ($hourString == '') {
        return true;
    }
    if (strstr($hourString, ',')) {
        $tab1 = preg_split("/\,/", $hourString);
        for ($i = 0; isset($tab1[$i]); $i++) {
            if (preg_match('/([0-9]*):([0-9]*)-([0-9]*):([0-9]*)/', $tab1[$i], $str)) {
                if ($str[1] > 24 || $str[3] > 24) {
                    return false;
                }
                if ($str[2] > 59 || $str[4] > 59) {
                    return false;
                }
                if (($str[3] * 60 * 60 + $str[4] * 60) > 86400 || ($str[1] * 60 * 60 + $str[2] * 60) > 86400) {
                    return false;
                }
            } else {
                return false;
            }
        }

        return true;
    }
    if (preg_match('/([0-9]*):([0-9]*)-([0-9]*):([0-9]*)/', $hourString, $str)) {
        if ($str[1] > 24 || $str[3] > 24) {
            return false;
        }
        if ($str[2] > 59 || $str[4] > 59) {
            return false;
        }

        return ! (($str[3] * 60 * 60 + $str[4] * 60) > 86400 || ($str[1] * 60 * 60 + $str[2] * 60) > 86400);
    }

    return false;
}

/**
 * Get time period id by name
 *
 * @param string $name
 * @return int
 */
function getTimeperiodIdByName($name)
{
    global $pearDB;

    $id = 0;
    $res = $pearDB->query("SELECT tp_id FROM timeperiod WHERE tp_name = '" . $pearDB->escape($name) . "'");
    if ($res->rowCount()) {
        $row = $res->fetch();
        $id = $row['tp_id'];
    }

    return $id;
}

/**
 * Get chain of time periods via template relation
 *
 * @global \Pimple\Container $dependencyInjector
 * @param array $tpIds List of selected time period as IDs
 * @return array
 */
function getTimeperiodsFromTemplate(array $tpIds)
{
    global $dependencyInjector;

    $db = $dependencyInjector['centreon.db-manager'];

    $result = [];

    foreach ($tpIds as $tpId) {
        $db->getRepository(Centreon\Domain\Repository\TimePeriodRepository::class)
            ->getIncludeChainByParent($tpId, $result);
    }

    return $result;
}

/**
 * Validator prevent loops via template
 *
 * @global \HTML_QuickFormCustom $form Access to the form object
 * @param array $value List of selected time period as IDs
 * @return bool
 */
function testTemplateLoop($value)
{
    // skip check if template field is empty
    if (! $value) {
        return true;
    }

    global $form;

    $data = $form->getSubmitValues();

    // skip check if timeperiod is new
    if (! $data['tp_id']) {
        return true;
    }
    if (in_array($data['tp_id'], $value)) {
        // try to skip heavy check of templates

        return false;
    }

    return ! (in_array($data['tp_id'], getTimeperiodsFromTemplate($value)));
    // get list of all timeperiods related via templates
}

/**
 * All in one function to duplicate time periods
 *
 * @param array $params
 * @return int
 */
function duplicateTimePeriod(array $params): int
{
    global $pearDB;

    $isAlreadyInTransaction = $pearDB->inTransaction();
    if (! $isAlreadyInTransaction) {
        $pearDB->beginTransaction();
    }
    try {
        $params['tp_id'] = createTimePeriod($params);
        createTimePeriodsExceptions($params);
        createTimePeriodsIncludeRelations($params);
        createTimePeriodsExcludeRelations($params);
        if (! $isAlreadyInTransaction) {
            $pearDB->commit();
        }
    } catch (Exception $e) {
        if (! $isAlreadyInTransaction) {
            $pearDB->rollBack();
        }
    }

    return $params['tp_id'];
}

/**
 * Creates time period and returns id.
 *
 * @param array $params
 * @return int
 */
function createTimePeriod(array $params): int
{
    global $pearDB;

    $queryBindValues = [];
    foreach ($params['values'] as $index => $value) {
        $queryBindValues[':value_' . $index] = $value;
    }
    $bindValues = implode(', ', array_keys($queryBindValues));
    $statement = $pearDB->prepare("INSERT INTO timeperiod VALUES ({$bindValues})");
    foreach ($queryBindValues as $bindKey => $bindValue) {
        if (array_key_first($queryBindValues) === $bindKey) {
            $statement->bindValue($bindKey, (int) $bindValue, PDO::PARAM_INT);
        } else {
            $statement->bindValue($bindKey, $bindValue, PDO::PARAM_STR);
        }
    }
    $statement->execute();

    return (int) $pearDB->lastInsertId();
}

/**
 * Creates time periods exclude relations
 *
 * @param array $params
 */
function createTimePeriodsExcludeRelations(array $params): void
{
    global $pearDB;

    $query = 'INSERT INTO timeperiod_exclude_relations (timeperiod_id, timeperiod_exclude_id) '
             . 'SELECT :tp_id, timeperiod_exclude_id FROM timeperiod_exclude_relations '
             . 'WHERE timeperiod_id = :timeperiod_id';
    $statement = $pearDB->prepare($query);
    $statement->bindValue(':tp_id', $params['tp_id'], PDO::PARAM_INT);
    $statement->bindValue(':timeperiod_id', (int) $params['timeperiod_id'], PDO::PARAM_INT);
    $statement->execute();
}

/**
 * Creates time periods include relations
 *
 * @param array $params
 */
function createTimePeriodsIncludeRelations(array $params): void
{
    global $pearDB;

    $query = 'INSERT INTO timeperiod_include_relations (timeperiod_id, timeperiod_include_id) '
             . 'SELECT :tp_id, timeperiod_include_id FROM timeperiod_include_relations '
             . 'WHERE timeperiod_id = :timeperiod_id';
    $statement = $pearDB->prepare($query);
    $statement->bindValue(':tp_id', $params['tp_id'], PDO::PARAM_INT);
    $statement->bindValue(':timeperiod_id', (int) $params['timeperiod_id'], PDO::PARAM_INT);
    $statement->execute();
}

/**
 * Creates time periods exceptions
 *
 * @param array $params
 */
function createTimePeriodsExceptions(array $params): void
{
    global $pearDB;

    $query = 'INSERT INTO timeperiod_exceptions (timeperiod_id, days, timerange) '
             . 'SELECT :tp_id, days, timerange FROM timeperiod_exceptions '
             . 'WHERE timeperiod_id = :timeperiod_id';
    $statement = $pearDB->prepare($query);
    $statement->bindValue(':tp_id', $params['tp_id'], PDO::PARAM_INT);
    $statement->bindValue(':timeperiod_id', (int) $params['timeperiod_id'], PDO::PARAM_INT);
    $statement->execute();
}
