<?php
declare(strict_types=1);

// 온습도 임계 경보 판정 로직 회귀 테스트 (DB/네트워크 없이 순수 로직만).
//   - evaluate_metric_thresholds(): 고온/저온/고습/저습 판정 + 대표 상태
//   - metric_is_recovered():        히스테리시스 적용 정상복귀 판정
//   - metric_value_str():           표시용 숫자 포맷
// 임계값은 config.php 의 METRIC_* 상수를 그대로 사용하며, 어떤 운영 임계 설정에서도
// 의미가 유지되도록 상대값(임계±여유, 중간값)으로 검증한다.

$root = dirname(__DIR__);
require_once $root . '/php/sms_send.php';   // config.php + 판정 함수 포함

$failures = [];
function check(bool $cond, string $msg): void {
    global $failures;
    if (!$cond) { $failures[] = $msg; }
}
function eq($a, $b, string $msg): void {
    check($a === $b, $msg . ' (expected ' . var_export($b, true) . ', got ' . var_export($a, true) . ')');
}

// ── 함수 존재 ───────────────────────────────────────────────
check(function_exists('evaluate_metric_thresholds'), 'evaluate_metric_thresholds() should exist.');
check(function_exists('metric_is_recovered'), 'metric_is_recovered() should exist.');
check(function_exists('metric_value_str'), 'metric_value_str() should exist.');

$TH = (float)METRIC_TEMP_HIGH_C; $TL = (float)METRIC_TEMP_LOW_C;
$HH = (float)METRIC_RH_HIGH;     $HL = (float)METRIC_RH_LOW;
check($TL < $TH, 'temperature thresholds sane (low < high).');
check($HL < $HH, 'humidity thresholds sane (low < high).');

$tMid = ($TL + $TH) / 2.0;
$hMid = ($HL + $HH) / 2.0;

// ── evaluate_metric_thresholds ──────────────────────────────
eq(evaluate_metric_thresholds($tMid, $hMid)['breaches'], [], 'normal temp+humidity -> no breaches');
eq(evaluate_metric_thresholds($tMid, $hMid)['status'], 'normal', 'normal -> status normal');

eq(evaluate_metric_thresholds($TH + 5, $hMid)['breaches'], ['high_temp'], 'above high temp -> high_temp');
eq(evaluate_metric_thresholds($TL - 5, $hMid)['breaches'], ['low_temp'], 'below low temp -> low_temp');
eq(evaluate_metric_thresholds($tMid, $HH + 5)['breaches'], ['high_humidity'], 'above high rh -> high_humidity');
eq(evaluate_metric_thresholds($tMid, $HL - 5)['breaches'], ['low_humidity'], 'below low rh -> low_humidity');

// 경계값 포함(>= / <=)
eq(evaluate_metric_thresholds($TH, $hMid)['breaches'], ['high_temp'], 'temp == high threshold -> high_temp (inclusive)');
eq(evaluate_metric_thresholds($TL, $hMid)['breaches'], ['low_temp'], 'temp == low threshold -> low_temp (inclusive)');
eq(evaluate_metric_thresholds($tMid, $HH)['breaches'], ['high_humidity'], 'rh == high threshold -> high_humidity (inclusive)');
eq(evaluate_metric_thresholds($tMid, $HL)['breaches'], ['low_humidity'], 'rh == low threshold -> low_humidity (inclusive)');

// 동시 위반 + 대표 상태(첫 breach)
eq(evaluate_metric_thresholds($TH + 5, $HH + 5)['breaches'], ['high_temp', 'high_humidity'], 'high temp+humidity -> both breaches');
eq(evaluate_metric_thresholds($TH + 5, $HH + 5)['status'], 'high_temp', 'status = first breach');

// 결측(null) 처리
eq(evaluate_metric_thresholds(null, $HH + 5)['breaches'], ['high_humidity'], 'null temp + high rh -> high_humidity only');
eq(evaluate_metric_thresholds($TH + 5, null)['breaches'], ['high_temp'], 'high temp + null rh -> high_temp only');
eq(evaluate_metric_thresholds(null, null)['breaches'], [], 'all null -> no breaches');

// ── metric_is_recovered (히스테리시스) ──────────────────────
check(metric_is_recovered($tMid, $hMid) === true, 'mid values are recovered');
check(metric_is_recovered($TH + 5, $hMid) === false, 'above high temp not recovered');
check(metric_is_recovered($tMid, $HH + 5) === false, 'above high rh not recovered');
// 임계 바로 안쪽(히스테리시스 데드밴드)은 복구로 보지 않음
check(metric_is_recovered($TH - ((float)METRIC_TEMP_HYSTERESIS_C / 2.0), $hMid) === false, 'temp inside hysteresis deadband not recovered');
check(metric_is_recovered($tMid, $HH - ((float)METRIC_RH_HYSTERESIS / 2.0)) === false, 'rh inside hysteresis deadband not recovered');
// 결측은 해당 지표 정상 간주
check(metric_is_recovered(null, $hMid) === true, 'null temp recovered when rh normal');
check(metric_is_recovered($tMid, null) === true, 'null rh recovered when temp normal');

// ── metric_value_str ────────────────────────────────────────
eq(metric_value_str(30.0), '30', '30.0 -> 30');
eq(metric_value_str(25.5), '25.5', '25.5 -> 25.5');
eq(metric_value_str(-3.0), '-3', '-3.0 -> -3');
eq(metric_value_str(100.0), '100', '100.0 -> 100');
eq(metric_value_str(0.0), '0', '0.0 -> 0');

if ($failures) {
    fwrite(STDERR, "Threshold SMS logic test failures:\n");
    foreach ($failures as $f) {
        fwrite(STDERR, "- {$f}\n");
    }
    exit(1);
}

echo "Threshold SMS logic checks passed.\n";
