<?php

namespace Tests\Feature\Console;

use App\Events\CheckoutableCheckedIn;
use App\Mail\BulkDeleteReportMail;
use App\Models\Accessory;
use App\Models\Asset;
use App\Models\CheckoutAcceptance;
use App\Models\Company;
use App\Models\Component;
use App\Models\Consumable;
use App\Models\License;
use App\Models\LicenseSeat;
use App\Models\Maintenance;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Mail;
use Illuminate\Testing\PendingCommand;
use Tests\TestCase;

class BulkDeleteTest extends TestCase
{
    // ---------------------------------------------------------------------------
    // Prompt sequence helpers
    // ---------------------------------------------------------------------------

    /**
     * Builds a PendingCommand with the full prompt sequence pre-answered.
     *
     * Search() falls back as two steps: ask() for the search term, then
     * choice() to select from matching results. Multiselect() and select()
     * each fall back as a single choice() call.
     */
    private function runCommand(
        User $admin,
        array $companyIds,
        array $types,
        string $deleteType = 'soft',
        bool $dryRun = false,
        bool $sendNotifications = false,
        bool $clearLogs = false,
        bool $deleteFiles = false,
        bool $doBackup = false,
        bool $confirm = true,
        bool $sendEmailReport = false,
        string $deleteCompanyType = 'keep',
    ): PendingCommand {
        $hasNotifiableTypes = ! empty(array_intersect($types, ['assets', 'licenses', 'accessories', 'components']));

        $searchLabel = 'Who are you? Search by username, first or last name.';
        $companiesLabel = 'Which companies would you like to check in and delete items for?';
        $typesLabel = 'What item types would you like to check in and delete?';
        $deleteLabel = 'How should items be deleted?';

        $cmd = $this->artisan('snipeit:checkin-delete-items')
            // Step 1: dry run confirm
            ->expectsConfirmation('Is this a dry run?', $dryRun ? 'yes' : 'no')
            // Step 2: search() — ask() for the search term, then choice() to pick from results
            // Using expectsQuestion for both to avoid triggering choices validation
            ->expectsQuestion($searchLabel, $admin->username)
            ->expectsQuestion($searchLabel, (string) $admin->id)
            // Step 3: multisearch for companies — ask() for search term, then multiselectFallback()
            ->expectsQuestion($companiesLabel, '')
            ->expectsQuestion($companiesLabel, $companyIds)
            // Step 4: multiselect for item types
            ->expectsQuestion($typesLabel, $types)
            // Step 5: select for delete mode
            ->expectsQuestion($deleteLabel, $deleteType);

        // Step 6: notification confirm only shown for checkiable types
        if ($hasNotifiableTypes) {
            $cmd->expectsConfirmation('Should we send checkin notifications?', $sendNotifications ? 'yes' : 'no');
        }

        // Steps 7–11 and final confirm
        $cmd->expectsConfirmation('Should we clear related action logs?', $clearLogs ? 'yes' : 'no');

        // Step 8: file deletion prompt — only shown when deleteType !== 'none'
        if ($deleteType !== 'none') {
            $cmd->expectsConfirmation('Should we also delete associated image and upload files?', $deleteFiles ? 'yes' : 'no');
        }

        // Step 9: company deletion — only shown when real companies (not just __null__) were selected
        if (! empty($companyIds)) {
            $cmd->expectsQuestion('Should the selected companies also be deleted?', $deleteCompanyType);
        }

        $cmd->expectsConfirmation('Should we run a backup before proceeding?', $doBackup ? 'yes' : 'no');

        // Email report prompt — only shown when admin has an email address
        if ($admin->email) {
            $cmd->expectsConfirmation("Send an email report to {$admin->email}?", $sendEmailReport ? 'yes' : 'no');
        }

        if (! $dryRun) {
            $cmd->expectsConfirmation('Are you sure you want to proceed? This cannot be undone.', $confirm ? 'yes' : 'no');
        }

        return $cmd;
    }

    // ---------------------------------------------------------------------------
    // Assets
    // ---------------------------------------------------------------------------

    public function test_assigned_asset_is_checked_in_and_soft_deleted(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $user = User::factory()->forCompany($company->id)->create();
        $asset = Asset::factory()->for($company)->assignedToUser($user)->create();

        $this->assertNotNull($asset->assigned_to);

        $this->runCommand($admin, [$company->id], ['assets'])
            ->assertExitCode(0);

        $this->assertSoftDeleted($asset);
        $this->assertNull($asset->fresh()->assigned_to);
    }

    public function test_unassigned_asset_is_soft_deleted(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $asset = Asset::factory()->for($company)->create();

        $this->runCommand($admin, [$company->id], ['assets'])
            ->assertExitCode(0);

        $this->assertSoftDeleted($asset);
    }

    public function test_asset_is_hard_deleted(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $asset = Asset::factory()->for($company)->assignedToUser()->create();

        $this->runCommand($admin, [$company->id], ['assets'], deleteType: 'hard')
            ->assertExitCode(0);

        $this->assertDatabaseMissing('assets', ['id' => $asset->id]);
    }

    public function test_asset_checkin_event_fired_when_notifications_enabled(): void
    {
        Event::fake([CheckoutableCheckedIn::class]);

        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $asset = Asset::factory()->for($company)->assignedToUser()->create();

        $this->runCommand($admin, [$company->id], ['assets'], sendNotifications: true)
            ->assertExitCode(0);

        Event::assertDispatched(CheckoutableCheckedIn::class, fn ($e) => $e->checkoutable->is($asset));
    }

    public function test_asset_checkin_event_not_fired_when_notifications_suppressed(): void
    {
        Event::fake([CheckoutableCheckedIn::class]);

        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        Asset::factory()->for($company)->assignedToUser()->create();

        $this->runCommand($admin, [$company->id], ['assets'], sendNotifications: false)
            ->assertExitCode(0);

        Event::assertNotDispatched(CheckoutableCheckedIn::class);
    }

    public function test_asset_scoped_to_correct_company(): void
    {
        $admin = User::factory()->superuser()->create();
        [$companyA, $companyB] = Company::factory()->count(2)->create();

        $assetA = Asset::factory()->for($companyA)->create();
        $assetB = Asset::factory()->for($companyB)->create();

        $this->runCommand($admin, [$companyA->id], ['assets'])
            ->assertExitCode(0);

        $this->assertSoftDeleted($assetA);
        $this->assertNotSoftDeleted($assetB);
    }

    public function test_asset_delete_clears_all_checkout_acceptances(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $asset = Asset::factory()->for($company)->create();

        CheckoutAcceptance::factory()->create([
            'checkoutable_type' => Asset::class,
            'checkoutable_id' => $asset->id,
        ]);

        $this->runCommand($admin, [$company->id], ['assets'])
            ->assertExitCode(0);

        $this->assertDatabaseMissing('checkout_acceptances', [
            'checkoutable_type' => Asset::class,
            'checkoutable_id' => $asset->id,
        ]);
    }

    public function test_asset_checkin_clears_linked_license_seats(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $user = User::factory()->forCompany($company->id)->create();
        $asset = Asset::factory()->for($company)->assignedToUser($user)->create();
        $seat = LicenseSeat::factory()->create(['asset_id' => $asset->id, 'assigned_to' => $user->id]);

        $this->runCommand($admin, [$company->id], ['assets'])
            ->assertExitCode(0);

        $this->assertNull($seat->fresh()->assigned_to);
    }

    // ---------------------------------------------------------------------------
    // Licenses
    // ---------------------------------------------------------------------------

    public function test_assigned_license_seat_is_checked_in_and_license_soft_deleted(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $license = License::factory()->for($company)->create();
        $seat = LicenseSeat::factory()->for($license)->assignedToUser()->create();

        $this->assertNotNull($seat->assigned_to);

        $this->runCommand($admin, [$company->id], ['licenses'])
            ->assertExitCode(0);

        $this->assertSoftDeleted($license);
        $this->assertNull($seat->fresh()->assigned_to);
        $this->assertNull($seat->fresh()->asset_id);
    }

    public function test_license_hard_delete_removes_seats_and_their_checkout_acceptances(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $license = License::factory()->for($company)->create();
        $seat = LicenseSeat::factory()->for($license)->assignedToUser()->create();

        CheckoutAcceptance::factory()->create([
            'checkoutable_type' => LicenseSeat::class,
            'checkoutable_id' => $seat->id,
        ]);

        $this->runCommand($admin, [$company->id], ['licenses'], deleteType: 'hard')
            ->assertExitCode(0);

        $this->assertDatabaseMissing('licenses', ['id' => $license->id]);
        $this->assertDatabaseMissing('license_seats', ['id' => $seat->id]);
        $this->assertDatabaseMissing('checkout_acceptances', [
            'checkoutable_type' => LicenseSeat::class,
            'checkoutable_id' => $seat->id,
        ]);
    }

    public function test_license_soft_delete_also_soft_deletes_seats(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $license = License::factory()->for($company)->create();
        $seat = LicenseSeat::factory()->for($license)->create();

        $this->runCommand($admin, [$company->id], ['licenses'])
            ->assertExitCode(0);

        $this->assertSoftDeleted($license);
        $this->assertSoftDeleted($seat);
    }

    public function test_license_scoped_to_correct_company(): void
    {
        $admin = User::factory()->superuser()->create();
        [$companyA, $companyB] = Company::factory()->count(2)->create();

        $licenseA = License::factory()->for($companyA)->create();
        $licenseB = License::factory()->for($companyB)->create();

        $this->runCommand($admin, [$companyA->id], ['licenses'])
            ->assertExitCode(0);

        $this->assertSoftDeleted($licenseA);
        $this->assertNotSoftDeleted($licenseB);
    }

    // ---------------------------------------------------------------------------
    // Accessories
    // ---------------------------------------------------------------------------

    public function test_checked_out_accessory_is_checked_in_and_soft_deleted(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $accessory = Accessory::factory()->for($company)->checkedOutToUser()->create();

        $this->assertEquals(1, $accessory->checkouts->count());

        $this->runCommand($admin, [$company->id], ['accessories'])
            ->assertExitCode(0);

        $this->assertSoftDeleted($accessory);
        $this->assertEquals(0, $accessory->fresh()->checkouts->count());
    }

    public function test_accessory_scoped_to_correct_company(): void
    {
        $admin = User::factory()->superuser()->create();
        [$companyA, $companyB] = Company::factory()->count(2)->create();

        $accessoryA = Accessory::factory()->for($companyA)->checkedOutToUser()->create();
        $accessoryB = Accessory::factory()->for($companyB)->checkedOutToUser()->create();

        $this->runCommand($admin, [$companyA->id], ['accessories'])
            ->assertExitCode(0);

        $this->assertSoftDeleted($accessoryA);
        $this->assertNotSoftDeleted($accessoryB);
    }

    // ---------------------------------------------------------------------------
    // Components
    // ---------------------------------------------------------------------------

    public function test_checked_out_component_is_checked_in_and_soft_deleted(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $component = Component::factory()->for($company)->checkedOutToAsset()->create();

        $this->assertDatabaseHas('components_assets', ['component_id' => $component->id]);

        $this->runCommand($admin, [$company->id], ['components'])
            ->assertExitCode(0);

        $this->assertSoftDeleted($component);
        $this->assertDatabaseMissing('components_assets', ['component_id' => $component->id]);
    }

    // ---------------------------------------------------------------------------
    // Consumables
    // ---------------------------------------------------------------------------

    public function test_consumable_is_soft_deleted(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $consumable = Consumable::factory()->for($company)->create();

        $this->runCommand($admin, [$company->id], ['consumables'])
            ->assertExitCode(0);

        $this->assertSoftDeleted($consumable);
    }

    public function test_consumable_is_hard_deleted(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $consumable = Consumable::factory()->for($company)->create();

        $this->runCommand($admin, [$company->id], ['consumables'], deleteType: 'hard')
            ->assertExitCode(0);

        $this->assertDatabaseMissing('consumables', ['id' => $consumable->id]);
    }

    // ---------------------------------------------------------------------------
    // Users
    // ---------------------------------------------------------------------------

    public function test_user_is_soft_deleted(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $user = User::factory()->forCompany($company->id)->create(['activated' => 1]);

        $this->runCommand($admin, [$company->id], ['users'])
            ->assertExitCode(0);

        $this->assertSoftDeleted($user);
    }

    public function test_user_delete_nulls_license_seat_assignments(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $user = User::factory()->forCompany($company->id)->create(['activated' => 1]);
        $seat = LicenseSeat::factory()->create(['assigned_to' => $user->id]);

        $this->runCommand($admin, [$company->id], ['users'])
            ->assertExitCode(0);

        $this->assertNull($seat->fresh()->assigned_to);
    }

    public function test_user_delete_removes_accessory_checkout_records(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $user = User::factory()->forCompany($company->id)->create(['activated' => 1]);
        Accessory::factory()->for($company)->checkedOutToUser($user)->create();

        $this->assertDatabaseHas('accessories_checkout', ['assigned_to' => $user->id]);

        $this->runCommand($admin, [$company->id], ['users'])
            ->assertExitCode(0);

        $this->assertDatabaseMissing('accessories_checkout', ['assigned_to' => $user->id]);
    }

    public function test_user_delete_removes_consumable_assignments(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $user = User::factory()->forCompany($company->id)->create(['activated' => 1]);
        Consumable::factory()->for($company)->checkedOutToUser($user)->create();

        $this->assertDatabaseHas('consumables_users', ['assigned_to' => $user->id]);

        $this->runCommand($admin, [$company->id], ['users'])
            ->assertExitCode(0);

        $this->assertDatabaseMissing('consumables_users', ['assigned_to' => $user->id]);
    }

    public function test_user_delete_removes_checkout_acceptances(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $user = User::factory()->forCompany($company->id)->create(['activated' => 1]);

        CheckoutAcceptance::factory()->create(['assigned_to_id' => $user->id]);

        $this->runCommand($admin, [$company->id], ['users'])
            ->assertExitCode(0);

        $this->assertDatabaseMissing('checkout_acceptances', ['assigned_to_id' => $user->id]);
    }

    public function test_admin_user_is_skipped_during_user_deletion(): void
    {
        $company = Company::factory()->create();
        $admin = User::factory()->superuser()->forCompany($company->id)->create(['activated' => 1]);

        $this->runCommand($admin, [$company->id], ['users'])
            ->assertExitCode(0);

        $this->assertDatabaseHas('users', ['id' => $admin->id, 'deleted_at' => null]);
    }

    // ---------------------------------------------------------------------------
    // Action log clearing
    // ---------------------------------------------------------------------------

    public function test_clear_logs_removes_asset_action_logs(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $user = User::factory()->create();
        $asset = Asset::factory()->for($company)->assignedToUser($user)->create();

        $this->runCommand($admin, [$company->id], ['assets'], clearLogs: true)
            ->assertExitCode(0);

        $this->assertDatabaseMissing('action_logs', [
            'item_type' => Asset::class,
            'item_id' => $asset->id,
        ]);
    }

    // ---------------------------------------------------------------------------
    // Maintenance / related table cleanup
    // ---------------------------------------------------------------------------

    public function test_asset_hard_delete_removes_maintenance_records(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $asset = Asset::factory()->for($company)->create();
        $maintenance = Maintenance::factory()->create(['asset_id' => $asset->id]);

        $this->runCommand($admin, [$company->id], ['assets'], deleteType: 'hard')
            ->assertExitCode(0);

        $this->assertDatabaseMissing('maintenances', ['id' => $maintenance->id]);
    }

    public function test_asset_hard_delete_removes_accessory_checkouts_to_asset(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $asset = Asset::factory()->for($company)->create();
        $accessory = Accessory::factory()->for($company)->create();
        $accessory->checkouts()->create([
            'accessory_id' => $accessory->id,
            'assigned_to' => $asset->id,
            'assigned_type' => Asset::class,
            'created_by' => $admin->id,
        ]);

        $this->assertDatabaseHas('accessories_checkout', [
            'assigned_to' => $asset->id,
            'assigned_type' => Asset::class,
        ]);

        $this->runCommand($admin, [$company->id], ['assets'], deleteType: 'hard')
            ->assertExitCode(0);

        $this->assertDatabaseMissing('accessories_checkout', [
            'assigned_to' => $asset->id,
            'assigned_type' => Asset::class,
        ]);
    }

    public function test_asset_hard_delete_nulls_child_asset_assignments(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $target = Asset::factory()->for($company)->create();
        $child = Asset::factory()->create(['assigned_to' => $target->id, 'assigned_type' => Asset::class]);

        $this->runCommand($admin, [$company->id], ['assets'], deleteType: 'hard')
            ->assertExitCode(0);

        $this->assertNull($child->fresh()->assigned_to);
        $this->assertNull($child->fresh()->assigned_type);
    }

    public function test_license_hard_delete_removes_kit_entries(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $license = License::factory()->for($company)->create();
        DB::table('kits_licenses')->insert(['kit_id' => 1, 'license_id' => $license->id, 'quantity' => 1]);

        $this->runCommand($admin, [$company->id], ['licenses'], deleteType: 'hard')
            ->assertExitCode(0);

        $this->assertDatabaseMissing('kits_licenses', ['license_id' => $license->id]);
    }

    public function test_accessory_hard_delete_removes_kit_entries(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $accessory = Accessory::factory()->for($company)->create();
        DB::table('kits_accessories')->insert(['kit_id' => 1, 'accessory_id' => $accessory->id, 'quantity' => 1]);

        $this->runCommand($admin, [$company->id], ['accessories'], deleteType: 'hard')
            ->assertExitCode(0);

        $this->assertDatabaseMissing('kits_accessories', ['accessory_id' => $accessory->id]);
    }

    public function test_consumable_hard_delete_removes_kit_entries(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $consumable = Consumable::factory()->for($company)->create();
        DB::table('kits_consumables')->insert(['kit_id' => 1, 'consumable_id' => $consumable->id, 'quantity' => 1]);

        $this->runCommand($admin, [$company->id], ['consumables'], deleteType: 'hard')
            ->assertExitCode(0);

        $this->assertDatabaseMissing('kits_consumables', ['consumable_id' => $consumable->id]);
    }

    // ---------------------------------------------------------------------------
    // Dry run
    // ---------------------------------------------------------------------------

    public function test_dry_run_does_not_delete_or_checkin_assets(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $user = User::factory()->forCompany($company->id)->create();
        $asset = Asset::factory()->for($company)->assignedToUser($user)->create();

        $this->runCommand($admin, [$company->id], ['assets'], dryRun: true)
            ->assertExitCode(0);

        $this->assertNotSoftDeleted($asset);
        $this->assertNotNull($asset->fresh()->assigned_to);
    }

    // ---------------------------------------------------------------------------
    // Final confirm / abort
    // ---------------------------------------------------------------------------

    public function test_declining_final_confirm_makes_no_changes(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $asset = Asset::factory()->for($company)->create();

        $this->runCommand($admin, [$company->id], ['assets'], confirm: false)
            ->assertExitCode(0);

        $this->assertNotSoftDeleted($asset);
    }

    // ---------------------------------------------------------------------------
    // Multi-company / checkin-only mode
    // ---------------------------------------------------------------------------

    public function test_multiple_companies_are_all_processed(): void
    {
        $admin = User::factory()->superuser()->create();
        [$companyA, $companyB] = Company::factory()->count(2)->create();

        $assetA = Asset::factory()->for($companyA)->create();
        $assetB = Asset::factory()->for($companyB)->create();
        $assetC = Asset::factory()->create(); // no company — should be untouched

        $this->runCommand($admin, [$companyA->id, $companyB->id], ['assets'])
            ->assertExitCode(0);

        $this->assertSoftDeleted($assetA);
        $this->assertSoftDeleted($assetB);
        $this->assertNotSoftDeleted($assetC);
    }

    public function test_checkin_only_mode_checks_in_without_deleting(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $user = User::factory()->forCompany($company->id)->create();
        $asset = Asset::factory()->for($company)->assignedToUser($user)->create();

        $this->runCommand($admin, [$company->id], ['assets'], deleteType: 'none')
            ->assertExitCode(0);

        $this->assertNotSoftDeleted($asset);
        $this->assertNull($asset->fresh()->assigned_to);
    }

    // ---------------------------------------------------------------------------
    // Company deletion
    // ---------------------------------------------------------------------------

    public function test_company_is_soft_deleted_when_requested(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        Asset::factory()->for($company)->create();

        $this->runCommand($admin, [$company->id], ['assets'], deleteCompanyType: 'soft')
            ->assertExitCode(0);

        $this->assertSoftDeleted($company);
    }

    public function test_company_is_hard_deleted_when_requested(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        Asset::factory()->for($company)->create();

        $this->runCommand($admin, [$company->id], ['assets'], deleteCompanyType: 'hard')
            ->assertExitCode(0);

        $this->assertDatabaseMissing('companies', ['id' => $company->id]);
    }

    public function test_company_is_kept_when_not_requested(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        Asset::factory()->for($company)->create();

        $this->runCommand($admin, [$company->id], ['assets'], deleteCompanyType: 'keep')
            ->assertExitCode(0);

        $this->assertDatabaseHas('companies', ['id' => $company->id, 'deleted_at' => null]);
    }

    // ---------------------------------------------------------------------------
    // Multi-company user handling
    // ---------------------------------------------------------------------------

    public function test_user_in_multiple_companies_is_partially_disassociated(): void
    {
        $admin = User::factory()->superuser()->create();
        [$companyA, $companyB] = Company::factory()->count(2)->create();
        $user = User::factory()->forCompany($companyA->id)->create(['activated' => 1]);
        $user->companies()->syncWithoutDetaching([$companyA->id, $companyB->id]);

        $this->runCommand($admin, [$companyA->id], ['users'])
            ->assertExitCode(0);

        // User should NOT have been deleted
        $this->assertDatabaseHas('users', ['id' => $user->id, 'deleted_at' => null]);
        // companyA pivot entry should be removed
        $this->assertDatabaseMissing('company_user', ['user_id' => $user->id, 'company_id' => $companyA->id]);
        // companyB pivot entry should remain
        $this->assertDatabaseHas('company_user', ['user_id' => $user->id, 'company_id' => $companyB->id]);
    }

    public function test_user_in_only_selected_company_is_fully_deleted(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $user = User::factory()->forCompany($company->id)->create(['activated' => 1]);
        $user->companies()->syncWithoutDetaching([$company->id]);

        $this->runCommand($admin, [$company->id], ['users'])
            ->assertExitCode(0);

        $this->assertSoftDeleted($user);
    }

    public function test_user_hard_delete_removes_company_user_pivot_entries(): void
    {
        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        $user = User::factory()->forCompany($company->id)->create(['activated' => 1]);
        $user->companies()->syncWithoutDetaching([$company->id]);

        $this->assertDatabaseHas('company_user', ['user_id' => $user->id, 'company_id' => $company->id]);

        $this->runCommand($admin, [$company->id], ['users'], deleteType: 'hard')
            ->assertExitCode(0);

        $this->assertDatabaseMissing('users', ['id' => $user->id]);
        $this->assertDatabaseMissing('company_user', ['user_id' => $user->id]);
    }

    // ---------------------------------------------------------------------------
    // Email report
    // ---------------------------------------------------------------------------

    public function test_email_report_is_sent_when_requested(): void
    {
        Mail::fake();

        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        Asset::factory()->for($company)->create();

        $this->runCommand($admin, [$company->id], ['assets'], sendEmailReport: true)
            ->assertExitCode(0);

        Mail::assertSent(BulkDeleteReportMail::class, fn ($mail) => $mail->hasTo($admin->email));
    }

    public function test_email_report_is_not_sent_when_declined(): void
    {
        Mail::fake();

        $admin = User::factory()->superuser()->create();
        $company = Company::factory()->create();
        Asset::factory()->for($company)->create();

        $this->runCommand($admin, [$company->id], ['assets'], sendEmailReport: false)
            ->assertExitCode(0);

        Mail::assertNothingSent();
    }
}
