<?php

use App\Models\Artwork;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

uses(RefreshDatabase::class);

function createUploadRowForQuota(int $userId, array $overrides = []): string
{
    $id = (string) Str::uuid();

    $defaults = [
        'id' => $id,
        'user_id' => $userId,
        '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;
}

function attachMainUploadFileForQuota(string $uploadId, int $size, string $hash = 'hash-main'): void
{
    DB::table('upload_files')->insert([
        'upload_id' => $uploadId,
        'path' => "tmp/drafts/{$uploadId}/main/file.bin",
        'type' => 'main',
        'hash' => $hash,
        'size' => $size,
        'mime' => 'application/octet-stream',
        'created_at' => now(),
    ]);
}

it('enforces draft count limit', function () {
    Storage::fake('local');
    config(['uploads.draft_quota.max_drafts_per_user' => 1]);

    $user = User::factory()->create();
    createUploadRowForQuota($user->id, ['status' => 'draft']);

    $main = UploadedFile::fake()->image('wallpaper.jpg', 600, 400);

    $response = $this->actingAs($user)->postJson('/api/uploads/preload', [
        'main' => $main,
    ]);

    $response->assertStatus(429)
        ->assertJsonPath('message', 'draft_limit')
        ->assertJsonPath('code', 'draft_limit');
});

it('enforces draft storage limit', function () {
    Storage::fake('local');
    config([
        'uploads.draft_quota.max_drafts_per_user' => 20,
        'uploads.draft_quota.max_draft_storage_mb_per_user' => 1,
    ]);

    $user = User::factory()->create();

    $existingDraftId = createUploadRowForQuota($user->id, ['status' => 'draft']);
    attachMainUploadFileForQuota($existingDraftId, 400 * 1024, 'existing-hash');

    $main = UploadedFile::fake()->create('large.jpg', 700, 'image/jpeg');

    $response = $this->actingAs($user)->postJson('/api/uploads/preload', [
        'main' => $main,
    ]);

    $response->assertStatus(413)
        ->assertJsonPath('message', 'storage_limit')
        ->assertJsonPath('code', 'storage_limit');
});

it('blocks duplicate hash when policy is block', function () {
    Storage::fake('local');
    config([
        'uploads.draft_quota.max_drafts_per_user' => 20,
        'uploads.draft_quota.duplicate_hash_policy' => 'block',
    ]);

    $owner = User::factory()->create();
    $uploader = User::factory()->create();

    $main = UploadedFile::fake()->image('dupe.jpg', 400, 400);
    $hash = hash_file('sha256', $main->getPathname());

    Artwork::factory()->create([
        'user_id' => $owner->id,
        'hash' => $hash,
        'artwork_status' => 'published',
        'published_at' => now()->subMinute(),
        'is_public' => true,
    ]);

    $response = $this->actingAs($uploader)->postJson('/api/uploads/preload', [
        'main' => $main,
    ]);

    $response->assertStatus(422)
        ->assertJsonPath('message', 'duplicate_upload')
        ->assertJsonPath('code', 'duplicate_upload');
});

it('allows duplicate hash and returns warning when policy is warn', function () {
    Storage::fake('local');
    config([
        'uploads.draft_quota.max_drafts_per_user' => 20,
        'uploads.draft_quota.duplicate_hash_policy' => 'warn',
    ]);

    $owner = User::factory()->create();
    $uploader = User::factory()->create();

    $main = UploadedFile::fake()->image('dupe-warn.jpg', 400, 400);
    $hash = hash_file('sha256', $main->getPathname());

    Artwork::factory()->create([
        'user_id' => $owner->id,
        'hash' => $hash,
        'artwork_status' => 'published',
        'published_at' => now()->subMinute(),
        'is_public' => true,
    ]);

    $response = $this->actingAs($uploader)->postJson('/api/uploads/preload', [
        'main' => $main,
    ]);

    $response->assertOk()
        ->assertJsonStructure(['upload_id', 'status', 'expires_at', 'warnings'])
        ->assertJsonPath('warnings.0', 'duplicate_hash');
});

it('does not count published uploads as drafts', function () {
    Storage::fake('local');
    config(['uploads.draft_quota.max_drafts_per_user' => 1]);

    $user = User::factory()->create();
    createUploadRowForQuota($user->id, [
        'status' => 'published',
        'published_at' => now()->subHour(),
    ]);

    $main = UploadedFile::fake()->image('new.jpg', 640, 480);

    $response = $this->actingAs($user)->postJson('/api/uploads/preload', [
        'main' => $main,
    ]);

    $response->assertOk()->assertJsonStructure([
        'upload_id',
        'status',
        'expires_at',
    ]);
});

it('ignores duplicate hashes that exist only in temporary upload tables', function () {
    Storage::fake('local');
    config([
        'uploads.draft_quota.max_drafts_per_user' => 20,
        'uploads.draft_quota.duplicate_hash_policy' => 'block',
    ]);

    $owner = User::factory()->create();
    $uploader = User::factory()->create();

    $main = UploadedFile::fake()->image('temp-only-dupe.jpg', 400, 400);
    $hash = hash_file('sha256', $main->getPathname());

    $publishedUploadId = createUploadRowForQuota($owner->id, [
        'status' => 'published',
        'published_at' => now()->subMinute(),
    ]);

    attachMainUploadFileForQuota($publishedUploadId, (int) $main->getSize(), $hash);

    $response = $this->actingAs($uploader)->postJson('/api/uploads/preload', [
        'main' => $main,
    ]);

    $response->assertOk()->assertJsonStructure([
        'upload_id',
        'status',
        'expires_at',
    ]);
});

it('returns stable machine codes for quota errors', function () {
    Storage::fake('local');
    config(['uploads.draft_quota.max_drafts_per_user' => 1]);

    $user = User::factory()->create();
    createUploadRowForQuota($user->id, ['status' => 'draft']);

    $main = UploadedFile::fake()->image('machine-code.jpg', 600, 400);

    $response = $this->actingAs($user)->postJson('/api/uploads/preload', [
        'main' => $main,
    ]);

    $response->assertStatus(429)
        ->assertJson([
            'message' => 'draft_limit',
            'code' => 'draft_limit',
        ]);
});
