<?php

namespace Tests\Feature;

use App\Models\User;
use App\Services\ReleaseChecker;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Tests\TestCase;

/**
 * The shared release lookup behind the Versions page, the sidebar update badge and the scheduled
 * refresh. updateAvailable() is a pure cache read (no network); refresh() does the remote check.
 */
class ReleaseCheckerTest extends TestCase
{
    use RefreshDatabase;

    private const TAGS_URL = 'git.bave.dev/api/v1/repos/boban/clusev/tags*';

    protected function setUp(): void
    {
        parent::setUp();
        Cache::flush();
    }

    public function test_update_available_is_true_when_the_cache_holds_a_newer_tag(): void
    {
        config()->set('clusev.version', '0.9.10');
        Cache::put('clusev:latest-release:stable', '0.9.11', now()->addMinutes(30));

        $this->assertTrue(app(ReleaseChecker::class)->updateAvailable());
    }

    public function test_update_available_is_false_when_cache_is_at_or_below_installed_or_empty(): void
    {
        config()->set('clusev.version', '0.9.11');

        $this->assertFalse(app(ReleaseChecker::class)->updateAvailable(), 'empty cache → no badge');

        Cache::put('clusev:latest-release:stable', '0.9.11', now()->addMinutes(30));
        $this->assertFalse(app(ReleaseChecker::class)->updateAvailable(), 'equal version → no badge');

        Cache::put('clusev:latest-release:stable', '0.9.9', now()->addMinutes(30));
        $this->assertFalse(app(ReleaseChecker::class)->updateAvailable(), 'stale older cache → no badge');
    }

    public function test_update_available_does_no_network(): void
    {
        Http::fake();
        config()->set('clusev.version', '0.9.10');
        Cache::put('clusev:latest-release:stable', '0.9.12', now()->addMinutes(30));

        $this->assertTrue(app(ReleaseChecker::class)->updateAvailable());
        Http::assertNothingSent();
    }

    public function test_refresh_fetches_and_caches_the_newest_tag(): void
    {
        Http::fake([self::TAGS_URL => Http::response([['name' => 'v0.9.13'], ['name' => 'v0.9.12']])]);

        $tag = app(ReleaseChecker::class)->refresh('stable');

        $this->assertSame('0.9.13', $tag);
        $this->assertSame('0.9.13', Cache::get('clusev:latest-release:stable'));
    }

    public function test_check_update_command_warms_the_cache(): void
    {
        Http::fake([self::TAGS_URL => Http::response([['name' => 'v0.9.20']])]);

        $this->artisan('clusev:check-update')->assertSuccessful();

        $this->assertSame('0.9.20', Cache::get('clusev:latest-release:stable'));
    }

    public function test_sidebar_shows_the_update_badge_only_when_an_update_is_available(): void
    {
        Http::fake(); // any stray check must not hit the network
        config()->set('clusev.version', '0.9.10');
        $this->actingAs(User::factory()->create(['must_change_password' => false]));

        // No cached latest → no badge.
        $this->get('/audit')->assertOk()->assertDontSee(__('shell.update_available'));

        // Cached newer release → the sidebar Version item carries the badge.
        Cache::put('clusev:latest-release:stable', '0.9.11', now()->addMinutes(30));
        $this->get('/audit')->assertOk()->assertSee(__('shell.update_available'));
    }
}
