<?php
/**
 * Demo Oracle — periode et dimensions du rapport ASH detaille, et leur plafond.
 *
 * Meme role, et meme raison d'etre, que DemoOracleRealtimeFilters : la page et
 * son point de donnees passent tous deux par ici, si bien qu'une URL forgee
 * rend exactement ce que rend un clic normal.
 *
 * C'est indispensable ici : `_data_history_detail.php` recoit les bornes de
 * chaque tranche depuis le navigateur, en boucle. Plafonner la periode dans le
 * seul formulaire aurait laisse le point de donnees accepter n'importe quelle
 * amplitude, tranche apres tranche.
 *
 * Safe to include multiple times (guard sur class_exists).
 */
if (class_exists('DemoOracleAshDetailFilters')) return;

class DemoOracleAshDetailFilters
{
    /** Format accepte pour une borne : « AAAA-MM-JJ HH:MM ». */
    private const RE_DT = '/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/';

    /**
     * Toutes les dimensions du module complet, et celles que la demonstration
     * sert. Les autres restent listees, desactivees : le visiteur voit ce
     * qu'offre la version complete.
     *
     * Le choix retenu est celui du rapport temps reel — classe d'attente et
     * module — la troisieme dimension de celui-ci, l'instance, n'existant pas
     * dans ce rapport-ci.
     *
     * @return array<string, array{label: string, demo: bool}>
     */
    public static function dimensions(): array
    {
        $served = ['category', 'module'];
        $all = [
            'category'     => 'demo_oracle.ash_dim_category',
            'sql_id'       => 'demo_oracle.ash_dim_sql',
            'wait_event'   => 'demo_oracle.ash_dim_event',
            'module'       => 'demo_oracle.ash_dim_module',
            'service_name' => 'demo_oracle.ash_dim_service',
            'machine'      => 'demo_oracle.ash_dim_machine',
            'plsql_entry'  => 'demo_oracle.ash_dim_plsql',
            'object_name'  => 'demo_oracle.ash_dim_object',
        ];
        $out = [];
        foreach ($all as $key => $label) {
            $out[$key] = ['label' => $label, 'demo' => in_array($key, $served, true)];
        }
        return $out;
    }

    /**
     * Borne une periode a DEMO_ORACLE_ASH_MAX_HOURS.
     *
     * Le debut est conserve et la fin ramenee : c'est ce qui surprend le
     * moins. Quelqu'un qui demande « du 1er au 30 » cherche d'abord ce qui
     * s'est passe le 1er ; lui rendre les dernieres 24 h du 30 serait une
     * autre question que la sienne.
     *
     * @return array{0: string, 1: string, 2: bool}  [debut, fin, plafonne ?]
     */
    public static function clamp(string $dtBegin, string $dtEnd): array
    {
        $maxSecs = DEMO_ORACLE_ASH_MAX_HOURS * 3600;
        $b = strtotime($dtBegin);
        $e = strtotime($dtEnd);
        if ($b === false || $e === false || $e - $b <= $maxSecs) {
            return [$dtBegin, $dtEnd, false];
        }
        return [$dtBegin, date('Y-m-d H:i', $b + $maxSecs), true];
    }

    /**
     * Lit les bornes du formulaire (HTML) ou d'une tranche (JSON), les valide
     * et les plafonne.
     *
     * @param bool $chunk true pour une tranche AJAX (chunk_begin / chunk_end)
     * @return array{begin: string, end: string, clamped: bool, valid: bool}
     */
    public static function parsePeriod(bool $chunk = false): array
    {
        if ($chunk) {
            $b = str_replace('T', ' ', (string)($_GET['chunk_begin'] ?? ''));
            $e = str_replace('T', ' ', (string)($_GET['chunk_end']   ?? ''));
            if (!preg_match(self::RE_DT, $b) || !preg_match(self::RE_DT, $e) || $b >= $e) {
                return ['begin' => '', 'end' => '', 'clamped' => false, 'valid' => false];
            }
        } else {
            $defEnd   = date('Y-m-d H:00');
            $defBegin = date('Y-m-d H:00', strtotime('-1 hour'));
            $b = str_replace('T', ' ', (string)($_GET['dt_begin'] ?? $defBegin));
            $e = str_replace('T', ' ', (string)($_GET['dt_end']   ?? $defEnd));
            if (!preg_match(self::RE_DT, $b) || !preg_match(self::RE_DT, $e) || $b >= $e) {
                $b = $defBegin;
                $e = $defEnd;
            }
        }

        [$b, $e, $clamped] = self::clamp($b, $e);
        return ['begin' => $b, 'end' => $e, 'clamped' => $clamped, 'valid' => true];
    }

    /**
     * Taille d'intervalle, choisie sur la duree totale.
     *
     * Les seuils du module complet sont conserves, mais son dernier palier
     * — au-dela de sept jours — est hors d'atteinte ici : la periode est
     * plafonnee a 24 h.
     */
    public static function bucketSecs(string $dtBegin, string $dtEnd): int
    {
        $dur = max(1, strtotime($dtEnd) - strtotime($dtBegin));
        if ($dur <  2 * 3600) return 10;    // moins de 2 h  -> 10 s
        if ($dur < 12 * 3600) return 60;    // 2 a 12 h      -> 1 min
        return 600;                          // au-dela       -> 10 min
    }

    /** Dimension demandee, ramenee a une dimension servie si besoin. */
    public static function dimension(): string
    {
        $dim  = preg_replace('/[^a-z_]/', '', strtolower((string)($_GET['dim'] ?? '')));
        $dims = self::dimensions();
        return (isset($dims[$dim]) && $dims[$dim]['demo']) ? $dim : 'category';
    }
}
