<?php

namespace Tests\Unit\Dashboard\Stats;

use App\Dashboard\Stats\DailySeriesStat;
use App\Dashboard\Stats\Series;
use App\Dashboard\Stats\SeriesResult;
use App\Support\DateRange;
use Illuminate\Support\Carbon;
use Tests\TestCase;

class DailySeriesStatTest extends TestCase
{
    private function bucketableRange(): DateRange
    {
        return new DateRange(
            Carbon::parse('2026-07-01 00:00:00'),
            Carbon::parse('2026-07-07 23:59:59'),
        );
    }

    public function test_for_calls_series_and_returns_its_result_on_a_bucketable_range(): void
    {
        $range = $this->bucketableRange();
        $expected = new SeriesResult($range->days(), [new Series('Approved', [1, 2, 3, 4, 5, 6, 7])]);

        $stat = new class($expected) extends DailySeriesStat
        {
            public bool $seriesWasCalled = false;

            public function __construct(private readonly SeriesResult $result) {}

            public function key(): string
            {
                return 'fake';
            }

            public function label(): string
            {
                return 'Fake';
            }

            protected function series(DateRange $range, array $days): SeriesResult
            {
                $this->seriesWasCalled = true;

                return $this->result;
            }
        };

        $result = $stat->for($range);

        $this->assertTrue($stat->seriesWasCalled);
        $this->assertSame($expected, $result);
    }

    public function test_for_returns_a_too_wide_result_without_calling_series_on_a_non_bucketable_range(): void
    {
        Carbon::setTestNow('2026-07-15 13:45:00');
        $range = DateRange::preset('all');

        $stat = new class extends DailySeriesStat
        {
            public bool $seriesWasCalled = false;

            public function key(): string
            {
                return 'fake';
            }

            public function label(): string
            {
                return 'Fake';
            }

            protected function series(DateRange $range, array $days): SeriesResult
            {
                $this->seriesWasCalled = true;

                return new SeriesResult([], []);
            }
        };

        $result = $stat->for($range);

        $this->assertFalse($stat->seriesWasCalled);
        $this->assertTrue($result->isTooWide());
    }

    public function test_for_passes_the_ranges_days_through_to_series(): void
    {
        $range = $this->bucketableRange();

        $stat = new class extends DailySeriesStat
        {
            /** @var array<int, string>|null */
            public ?array $receivedDays = null;

            public function key(): string
            {
                return 'fake';
            }

            public function label(): string
            {
                return 'Fake';
            }

            protected function series(DateRange $range, array $days): SeriesResult
            {
                $this->receivedDays = $days;

                return new SeriesResult($days, []);
            }
        };

        $stat->for($range);

        $this->assertSame($range->days(), $stat->receivedDays);
    }
}
