<?php

namespace Tests\Feature;

use App\Console\Commands\OperationsSchedulerHeartbeat;
use App\Jobs\ReleaseQueueProbe;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\File;
use Tests\TestCase;

class ReleaseVerificationTest extends TestCase
{
    use RefreshDatabase;

    public function test_scheduler_heartbeat_command_records_fresh_liveness_marker(): void
    {
        Cache::forget(OperationsSchedulerHeartbeat::CACHE_KEY);

        $this->artisan('operations:scheduler-heartbeat')->assertSuccessful();

        $heartbeat = Cache::get(OperationsSchedulerHeartbeat::CACHE_KEY);
        $this->assertIsString($heartbeat);
        $this->assertNotSame('', $heartbeat);
    }

    public function test_queue_probe_job_records_execution_marker_without_business_data(): void
    {
        $token = 'release-probe-test-token';
        $key = ReleaseQueueProbe::cacheKey($token);
        Cache::forget($key);

        (new ReleaseQueueProbe($token))->handle();

        $this->assertIsString(Cache::get($key));
        Cache::forget($key);
    }

    public function test_release_verification_fails_closed_outside_production_and_still_writes_manifest(): void
    {
        $output = storage_path('framework/testing/release-manifest.json');
        File::delete($output);

        try {
            $this->artisan('release:verify', [
                '--output' => $output,
                '--skip-queue-probe' => true,
                '--skip-scheduler-heartbeat' => true,
            ])
                ->expectsOutputToContain('Release verification failed.')
                ->assertFailed();

            $this->assertFileExists($output);
            $manifest = json_decode(File::get($output), true, flags: JSON_THROW_ON_ERROR);

            $this->assertSame(1, $manifest['schema_version']);
            $this->assertSame('failed', $manifest['status']);
            $this->assertSame('fail', $manifest['checks']['production_configuration']['status']);
            $this->assertSame('pass', $manifest['checks']['database_connectivity']['status']);
            $this->assertArrayHasKey('queue_storage', $manifest['checks']);
            $this->assertSame('pass', $manifest['checks']['scheduler_registration']['status']);
            $this->assertNotSame('', $manifest['git_sha']);
            $this->assertArrayNotHasKey('password', $manifest['runtime']);
        } finally {
            File::delete($output);
        }
    }

    public function test_release_commands_and_scheduler_heartbeat_are_registered(): void
    {
        $commands = Artisan::all();

        $this->assertArrayHasKey('release:verify', $commands);
        $this->assertArrayHasKey('operations:scheduler-heartbeat', $commands);
        $this->assertArrayHasKey('security:backup', $commands);

        $this->artisan('schedule:list')
            ->expectsOutputToContain('operations:scheduler-heartbeat')
            ->assertSuccessful();
    }
}
