<?php

namespace Tests\Unit\Uploads;

use App\Models\User;
use App\Uploads\Services\CleanupService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Tests\TestCase;

class CleanupServiceTest extends TestCase
{
    use RefreshDatabase;

    private function insertUploadRow(array $overrides = []): string
    {
        $id = (string) Str::uuid();

        $defaults = [
            'id' => $id,
            'user_id' => User::factory()->create()->id,
            'type' => 'image',
            'status' => 'draft',
            'title' => null,
            'slug' => null,
            'category_id' => null,
            'description' => null,
            'tags' => null,
            'license' => null,
            'nsfw' => false,
            'is_scanned' => false,
            'has_tags' => false,
            'preview_path' => null,
            'published_at' => null,
            'final_path' => null,
            'expires_at' => null,
            'created_at' => now(),
            'updated_at' => now(),
        ];

        DB::table('uploads')->insert(array_merge($defaults, $overrides));

        return $id;
    }

    public function test_deletes_expired_draft_uploads_and_returns_count(): void
    {
        Storage::fake('local');

        $uploadId = $this->insertUploadRow([
            'status' => 'draft',
            'expires_at' => now()->subMinute(),
        ]);

        Storage::disk('local')->put("tmp/drafts/{$uploadId}/meta.json", '{}');

        $deleted = app(CleanupService::class)->cleanupStaleDrafts();

        $this->assertSame(1, $deleted);
        $this->assertFalse(DB::table('uploads')->where('id', $uploadId)->exists());
    }

    public function test_keeps_active_drafts_untouched(): void
    {
        Storage::fake('local');

        $uploadId = $this->insertUploadRow([
            'status' => 'draft',
            'expires_at' => now()->addDay(),
            'updated_at' => now()->subHours(2),
        ]);

        Storage::disk('local')->put("tmp/drafts/{$uploadId}/meta.json", '{}');

        $deleted = app(CleanupService::class)->cleanupStaleDrafts();

        $this->assertSame(0, $deleted);
        $this->assertTrue(DB::table('uploads')->where('id', $uploadId)->exists());
        $this->assertTrue(Storage::disk('local')->exists("tmp/drafts/{$uploadId}/meta.json"));
    }

    public function test_removes_temp_folder_when_deleting_stale_drafts(): void
    {
        Storage::fake('local');

        $uploadId = $this->insertUploadRow([
            'status' => 'draft',
            'updated_at' => now()->subHours(25),
        ]);

        Storage::disk('local')->put("tmp/drafts/{$uploadId}/main/file.bin", 'x');
        $this->assertTrue(Storage::disk('local')->exists("tmp/drafts/{$uploadId}/main/file.bin"));

        $deleted = app(CleanupService::class)->cleanupStaleDrafts();

        $this->assertSame(1, $deleted);
        $this->assertFalse(Storage::disk('local')->exists("tmp/drafts/{$uploadId}/main/file.bin"));
    }

    public function test_enforces_hard_cleanup_limit_of_100_per_run(): void
    {
        Storage::fake('local');

        for ($index = 0; $index < 120; $index++) {
            $uploadId = $this->insertUploadRow([
                'status' => 'draft',
                'updated_at' => now()->subHours(30),
            ]);

            Storage::disk('local')->put("tmp/drafts/{$uploadId}/meta.json", '{}');
        }

        $deleted = app(CleanupService::class)->cleanupStaleDrafts(999);

        $this->assertSame(100, $deleted);
        $this->assertSame(20, DB::table('uploads')->count());
    }

    public function test_never_deletes_published_uploads(): void
    {
        Storage::fake('local');

        $uploadId = $this->insertUploadRow([
            'status' => 'published',
            'updated_at' => now()->subDays(5),
            'published_at' => now()->subDays(4),
        ]);

        Storage::disk('local')->put("tmp/drafts/{$uploadId}/meta.json", '{}');

        $deleted = app(CleanupService::class)->cleanupStaleDrafts();

        $this->assertSame(0, $deleted);
        $this->assertTrue(DB::table('uploads')->where('id', $uploadId)->where('status', 'published')->exists());
        $this->assertTrue(Storage::disk('local')->exists("tmp/drafts/{$uploadId}/meta.json"));
    }
}
