<?php

namespace Tests\Tenant;

use App\Services\MeilisearchService;
use Mockery\MockInterface;
use Mtc\MercuryDataModels\Vehicle;
use Tests\TenantTestCase;

class PruneVehiclesFromMeilisearchTest extends TenantTestCase
{
    /**
     * Documents whose vehicle is missing, unpublished or soft-deleted are removed,
     * while documents for active vehicles are kept. Pagination is exercised with a
     * small batch size, and removal is a single batch request after the full scan.
     */
    public function test_prunes_orphaned_documents_and_keeps_active_vehicles(): void
    {
        $activeOne = Vehicle::factory()->create(['is_published' => 1]);
        $activeTwo = Vehicle::factory()->create(['is_published' => 1]);
        $unpublished = Vehicle::factory()->create(['is_published' => 0]);
        $trashed = Vehicle::factory()->create(['is_published' => 1]);
        $trashed->delete();
        $missingId = 999999;

        $this->partialMock(MeilisearchService::class, function (MockInterface $mock) use (
            $activeOne,
            $activeTwo,
            $unpublished,
            $trashed,
            $missingId
        ) {
            $mock->shouldReceive('getIndexedVehicleIds')
                ->times(3)
                ->andReturn(
                    [$activeOne->id, $missingId],
                    [$activeTwo->id, $unpublished->id],
                    [$trashed->id],
                );

            $mock->shouldReceive('deleteVehicles')
                ->once()
                ->with([$missingId, $unpublished->id, $trashed->id]);
        });

        $this->artisan('meilisearch:prune-vehicles', ['--batch-size' => 2])
            ->assertSuccessful();
    }

    /**
     * A dry run reports orphans but never issues a delete request.
     */
    public function test_dry_run_does_not_delete(): void
    {
        $active = Vehicle::factory()->create(['is_published' => 1]);
        $trashed = Vehicle::factory()->create(['is_published' => 1]);
        $trashed->delete();

        $this->partialMock(MeilisearchService::class, function (MockInterface $mock) use ($active, $trashed) {
            $mock->shouldReceive('getIndexedVehicleIds')
                ->once()
                ->andReturn([$active->id, $trashed->id]);

            $mock->shouldNotReceive('deleteVehicles');
        });

        $this->artisan('meilisearch:prune-vehicles', ['--dry-run' => true])
            ->assertSuccessful();
    }

    /**
     * When the index cannot be scanned (e.g. it does not exist for the tenant),
     * the command exits successfully so a `tenants:run` sweep is not broken.
     */
    public function test_missing_index_does_not_fail(): void
    {
        $this->partialMock(MeilisearchService::class, function (MockInterface $mock) {
            $mock->shouldReceive('getIndexedVehicleIds')
                ->once()
                ->andThrow(new \Exception('Index `1_vehicles` not found.'));

            $mock->shouldNotReceive('deleteVehicles');
        });

        $this->artisan('meilisearch:prune-vehicles')
            ->assertSuccessful();
    }
}
