<?php

namespace Tests\Unit;

use App\Enums\DataExportScope;
use App\Jobs\GenerateDataExport;
use App\Models\DataExport;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class DataExportLifecycleTest extends TestCase
{
    use RefreshDatabase;

    public function test_can_retry_only_for_failed_or_canceled_exports(): void
    {
        $user = User::factory()->create();

        $failed = DataExport::query()->create([
            'user_id' => $user->id,
            'status' => DataExport::STATUS_FAILED,
            'scope' => DataExportScope::TENANT->value,
        ]);

        $canceled = DataExport::query()->create([
            'user_id' => $user->id,
            'status' => DataExport::STATUS_CANCELED,
            'scope' => DataExportScope::TENANT->value,
        ]);

        $pending = DataExport::query()->create([
            'user_id' => $user->id,
            'status' => DataExport::STATUS_PENDING,
            'scope' => DataExportScope::TENANT->value,
        ]);

        $this->assertTrue($failed->canRetry());
        $this->assertTrue($canceled->canRetry());
        $this->assertFalse($pending->canRetry());
    }

    public function test_can_cancel_only_for_pending_or_processing_exports(): void
    {
        $user = User::factory()->create();

        $pending = DataExport::query()->create([
            'user_id' => $user->id,
            'status' => DataExport::STATUS_PENDING,
            'scope' => DataExportScope::TENANT->value,
        ]);

        $processing = DataExport::query()->create([
            'user_id' => $user->id,
            'status' => DataExport::STATUS_PROCESSING,
            'scope' => DataExportScope::TENANT->value,
        ]);

        $ready = DataExport::query()->create([
            'user_id' => $user->id,
            'status' => DataExport::STATUS_READY,
            'scope' => DataExportScope::TENANT->value,
        ]);

        $this->assertTrue($pending->canCancel());
        $this->assertTrue($processing->canCancel());
        $this->assertFalse($ready->canCancel());
    }

    public function test_reset_for_retry_clears_export_fields(): void
    {
        $user = User::factory()->create();

        $export = DataExport::query()->create([
            'user_id' => $user->id,
            'status' => DataExport::STATUS_FAILED,
            'scope' => DataExportScope::TENANT->value,
            'error_message' => 'Boom',
            'path' => 'exports/test.zip',
            'size_bytes' => 123,
            'expires_at' => now()->addDay(),
        ]);

        $export->resetForRetry();
        $export->refresh();

        $this->assertSame(DataExport::STATUS_PENDING, $export->status);
        $this->assertNull($export->error_message);
        $this->assertNull($export->path);
        $this->assertNull($export->size_bytes);
        $this->assertNull($export->expires_at);
    }

    public function test_mark_canceled_sets_status_and_clears_export_fields(): void
    {
        $user = User::factory()->create();

        $export = DataExport::query()->create([
            'user_id' => $user->id,
            'status' => DataExport::STATUS_PENDING,
            'scope' => DataExportScope::TENANT->value,
            'path' => 'exports/test.zip',
            'size_bytes' => 321,
            'expires_at' => now()->addDay(),
        ]);

        $export->markCanceled('Manual cancel.');
        $export->refresh();

        $this->assertSame(DataExport::STATUS_CANCELED, $export->status);
        $this->assertSame('Manual cancel.', $export->error_message);
        $this->assertNull($export->path);
        $this->assertNull($export->size_bytes);
        $this->assertNull($export->expires_at);
    }

    public function test_generate_data_export_ignores_non_pending_exports(): void
    {
        $user = User::factory()->create();

        $export = DataExport::query()->create([
            'user_id' => $user->id,
            'status' => DataExport::STATUS_CANCELED,
            'scope' => DataExportScope::TENANT->value,
        ]);

        (new GenerateDataExport($export->id))->handle();

        $export->refresh();

        $this->assertSame(DataExport::STATUS_CANCELED, $export->status);
    }
}
