<?php

app_require('routes/moduleWeatherAPIRoute.php');

use routes\moduleWeatherAPIRoute;

function weather_timeline_range_invoke_private(moduleWeatherAPIRoute $route, string $method, array $args = []): mixed
{
    $reflection = new ReflectionClass($route);
    $target = $reflection->getMethod($method);

    return $target->invokeArgs($route, $args);
}

beforeEach(function (): void {
    $_SERVER['REQUEST_URI'] = '/departments/weather';
});

it('builds a timeline range from start of yesterday to end of today', function (): void {
    $route = new moduleWeatherAPIRoute();
    $range = weather_timeline_range_invoke_private($route, 'getDepartmentWeatherTimelineRange');

    $expectedStart = new DateTime(date('Y-m-d 00:00:00'));
    $expectedStart->sub(new DateInterval('P1D'));

    $expectedEndExclusive = new DateTime(date('Y-m-d 00:00:00'));
    $expectedEndExclusive->add(new DateInterval('P1D'));

    expect($range['start'] instanceof DateTime)->toBeTrue();
    expect($range['endExclusive'] instanceof DateTime)->toBeTrue();
    expect($range['start']->format('Y-m-d H:i:s'))->toBe($expectedStart->format('Y-m-d H:i:s'));
    expect($range['endExclusive']->format('Y-m-d H:i:s'))->toBe($expectedEndExclusive->format('Y-m-d H:i:s'));

    $hourCount = (int)(($range['endExclusive']->getTimestamp() - $range['start']->getTimestamp()) / 3600);
    expect($hourCount)->toBe(48);
});

it('builds a timeline range relative to explicit date_from and date_to override', function (): void {
    $route = new moduleWeatherAPIRoute();
    $range = weather_timeline_range_invoke_private($route, 'getDepartmentWeatherTimelineRange', ['2026-03-08', '2026-03-10']);

    expect($range['start']->format('Y-m-d H:i:s'))->toBe('2026-03-08 00:00:00');
    expect($range['endExclusive']->format('Y-m-d H:i:s'))->toBe('2026-03-11 00:00:00');

    $hourCount = (int)(($range['endExclusive']->getTimestamp() - $range['start']->getTimestamp()) / 3600);
    expect($hourCount)->toBe(72);
});

it('resolves forecast day count for a given timeline range with sane limits', function (): void {
    $route = new moduleWeatherAPIRoute();

    $start = new DateTime(date('Y-m-d 00:00:00'));
    $end = new DateTime(date('Y-m-d 00:00:00'));
    $end->add(new DateInterval('P3D'));

    $days = weather_timeline_range_invoke_private($route, 'resolveForecastDaysForTimelineRange', [$start, $end]);

    expect($days)->toBe(3);

    $farEnd = new DateTime(date('Y-m-d 00:00:00'));
    $farEnd->add(new DateInterval('P40D'));
    $clamped = weather_timeline_range_invoke_private($route, 'resolveForecastDaysForTimelineRange', [$start, $farEnd]);
    expect($clamped)->toBe(14);

    $pastStart = new DateTime(date('Y-m-d 00:00:00'));
    $pastStart->sub(new DateInterval('P10D'));
    $pastEnd = new DateTime(date('Y-m-d 00:00:00'));
    $pastEnd->sub(new DateInterval('P5D'));
    $pastDays = weather_timeline_range_invoke_private($route, 'resolveForecastDaysForTimelineRange', [$pastStart, $pastEnd]);
    expect($pastDays)->toBe(1);
});

it('marks non-started slots as unknown regardless of wash-hour ratio', function (): void {
    $route = new moduleWeatherAPIRoute();

    $targets = [
        'degraded_threshold' => 1.0,
        'healthy_threshold' => 1.3,
    ];

    $futureStatus = weather_timeline_range_invoke_private($route, 'calculateStatus', [10, 2.0, false, $targets]);
    expect($futureStatus)->toBe('unknown');

    $missingTargetStatus = weather_timeline_range_invoke_private($route, 'calculateStatus', [10, 2.0, true]);
    expect($missingTargetStatus)->toBe('unknown');

    $startedStatus = weather_timeline_range_invoke_private($route, 'calculateStatus', [10, 2.0, true, $targets]);
    expect($startedStatus)->toBe('healthy');
});
