<?php

namespace Tests\Unit\Models;

use App\Models\RouteArticle;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class RouteArticleRetryTest extends TestCase
{
    use RefreshDatabase;

    public function test_first_failure_schedules_the_shortest_backoff(): void
    {
        /** @var RouteArticle $routeArticle */
        $routeArticle = RouteArticle::factory()->approved()->create();

        $this->freezeTime(function () use ($routeArticle) {
            $routeArticle->recordPublishAttemptFailed();

            $this->assertSame(1, $routeArticle->publish_attempts);
            $this->assertSame(
                now()->addMinutes(5)->format('Y-m-d H:i:s'),
                $routeArticle->next_attempt_at->format('Y-m-d H:i:s')
            );
        });
    }

    public function test_backoff_grows_with_each_failure(): void
    {
        /** @var RouteArticle $routeArticle */
        $routeArticle = RouteArticle::factory()->approved()->create();

        $this->freezeTime(function () use ($routeArticle) {
            foreach ([5, 30, 120, 360] as $expectedDelay) {
                $routeArticle->recordPublishAttemptFailed();

                $this->assertSame(
                    now()->addMinutes($expectedDelay)->format('Y-m-d H:i:s'),
                    $routeArticle->next_attempt_at->format('Y-m-d H:i:s'),
                    "Attempt {$routeArticle->publish_attempts} should wait {$expectedDelay} minutes"
                );
            }
        });
    }

    public function test_attempts_are_exhausted_after_the_configured_maximum(): void
    {
        /** @var RouteArticle $routeArticle */
        $routeArticle = RouteArticle::factory()->approved()->create();

        for ($i = 0; $i < RouteArticle::MAX_PUBLISH_ATTEMPTS - 1; $i++) {
            $routeArticle->recordPublishAttemptFailed();
            $this->assertFalse($routeArticle->hasExhaustedPublishAttempts());
        }

        $routeArticle->recordPublishAttemptFailed();

        $this->assertTrue($routeArticle->hasExhaustedPublishAttempts());
    }

    public function test_a_successful_publish_clears_previous_attempts(): void
    {
        /** @var RouteArticle $routeArticle */
        $routeArticle = RouteArticle::factory()->approved()->create();

        $routeArticle->recordPublishAttemptFailed();
        $routeArticle->recordPublishAttemptFailed();

        $routeArticle->clearPublishAttempts();

        $this->assertSame(0, $routeArticle->publish_attempts);
        $this->assertNull($routeArticle->next_attempt_at);
        $this->assertFalse($routeArticle->hasExhaustedPublishAttempts());
    }
}
