<?php

namespace Tests\Unit\Dashboard\Stats;

use App\Dashboard\Stats\ApprovalRate;
use App\Dashboard\Stats\DailySeriesStat;
use App\Enums\ApprovalStatusEnum;
use App\Models\RouteArticle;
use App\Support\DateRange;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Carbon;
use Tests\TestCase;

class ApprovalRateTest extends TestCase
{
    use RefreshDatabase;

    private function range(): DateRange
    {
        return new DateRange(
            Carbon::parse('2026-07-01 00:00:00'),
            Carbon::parse('2026-07-31 23:59:59'),
        );
    }

    /**
     * @return array<string, float|null>
     */
    private function values(): array
    {
        $result = (new ApprovalRate)->for($this->range());

        return array_combine($result->labels, $result->series[0]->values);
    }

    private function decision(ApprovalStatusEnum $status, string $decidedAt): void
    {
        RouteArticle::factory()->create([
            'approval_status' => $status,
            'decided_at' => Carbon::parse($decidedAt),
        ]);
    }

    public function test_it_computes_the_approval_share_of_daily_decisions(): void
    {
        $this->decision(ApprovalStatusEnum::APPROVED, '2026-07-10 09:00:00');
        $this->decision(ApprovalStatusEnum::APPROVED, '2026-07-10 10:00:00');
        $this->decision(ApprovalStatusEnum::APPROVED, '2026-07-10 11:00:00');
        $this->decision(ApprovalStatusEnum::REJECTED, '2026-07-10 12:00:00');

        $this->assertSame(75.0, $this->values()['2026-07-10']);
    }

    public function test_it_excludes_pending_articles_from_the_denominator(): void
    {
        $this->decision(ApprovalStatusEnum::APPROVED, '2026-07-10 09:00:00');

        RouteArticle::factory()->create([
            'approval_status' => ApprovalStatusEnum::PENDING,
            'decided_at' => null,
            'created_at' => Carbon::parse('2026-07-10 09:00:00'),
        ]);

        $this->assertSame(100.0, $this->values()['2026-07-10']);
    }

    public function test_it_reports_no_rate_for_a_day_with_no_decisions(): void
    {
        $this->decision(ApprovalStatusEnum::APPROVED, '2026-07-10 09:00:00');

        $this->assertNull($this->values()['2026-07-11']);
    }

    public function test_it_reports_a_zero_rate_when_everything_was_rejected(): void
    {
        $this->decision(ApprovalStatusEnum::REJECTED, '2026-07-10 09:00:00');
        $this->decision(ApprovalStatusEnum::REJECTED, '2026-07-10 10:00:00');

        $this->assertSame(0.0, $this->values()['2026-07-10']);
    }

    public function test_it_buckets_by_decision_time_not_creation_time(): void
    {
        RouteArticle::factory()->create([
            'approval_status' => ApprovalStatusEnum::APPROVED,
            'created_at' => Carbon::parse('2026-07-05 09:00:00'),
            'decided_at' => Carbon::parse('2026-07-20 09:00:00'),
        ]);

        $values = $this->values();

        $this->assertNull($values['2026-07-05']);
        $this->assertSame(100.0, $values['2026-07-20']);
    }

    public function test_it_ignores_articles_decided_before_the_column_existed(): void
    {
        RouteArticle::factory()->create([
            'approval_status' => ApprovalStatusEnum::APPROVED,
            'created_at' => Carbon::parse('2026-07-10 09:00:00'),
            'decided_at' => null,
        ]);

        $this->assertNull($this->values()['2026-07-10']);
    }

    public function test_it_excludes_decisions_outside_the_range(): void
    {
        $this->decision(ApprovalStatusEnum::APPROVED, '2026-06-30 23:59:59');
        $this->decision(ApprovalStatusEnum::APPROVED, '2026-08-01 00:00:00');

        $this->assertSame(
            [],
            array_filter($this->values(), fn (?float $value): bool => $value !== null)
        );
    }

    public function test_it_reports_a_meaningful_zero_as_data(): void
    {
        $this->decision(ApprovalStatusEnum::REJECTED, '2026-07-10 09:00:00');

        $this->assertFalse((new ApprovalRate)->for($this->range())->hasNoData());
    }

    public function test_it_counts_every_decided_status_in_the_denominator(): void
    {
        $decided = array_filter(
            ApprovalStatusEnum::cases(),
            fn (ApprovalStatusEnum $status): bool => $status->isDecided(),
        );

        foreach ($decided as $status) {
            $this->decision($status, '2026-07-10 09:00:00');
        }

        $this->assertSame(
            round(100 / count($decided), 1),
            $this->values()['2026-07-10'],
        );
    }

    public function test_it_is_a_daily_series_stat(): void
    {
        $stat = new ApprovalRate;

        $this->assertInstanceOf(DailySeriesStat::class, $stat);
        $this->assertTrue($stat->for(DateRange::preset('all'))->isTooWide());
    }
}
