<?php

namespace Tests\Tenant;

use App\Facades\Settings;
use App\Services\NewCarBulkUpdateService;
use Illuminate\Support\Facades\Queue;
use Mtc\MercuryDataModels\Media;
use Mtc\MercuryDataModels\NewCar;
use Tests\TenantTestCase;
use Tests\UserForTenant;

class NewCarBulkUpdateServiceTest extends TenantTestCase
{
    use UserForTenant;

    protected function setUp(): void
    {
        parent::setUp();

        // setUsesForModel dispatches media-size generation jobs that resolve the
        // tenant from the central connection, which the test DB doesn't carry.
        Queue::fake();
    }

    private function enableNewCarVersioning(): void
    {
        tenant()->tier = 'pro';
        Settings::make([
            'tab' => 'test',
            'section' => 'test',
            'group' => 'test',
            'name' => 'test',
            'value' => true,
            'type' => 'bool',
            'config_key' => 'new-cars-versioning-enabled',
        ]);
    }

    public function testVersioningPublishAppliesLiveAndCreatesActiveVersion(): void
    {
        $this->enableNewCarVersioning();
        $this->actingAs($this->getUser());
        $car = NewCar::factory()->create(['price' => 1000]);

        $count = $this->service()->update('same', [$car->id], ['field' => 'price', 'value' => 4200], 'publish');

        $this->assertSame(1, $count);
        $this->assertEquals(4200, $car->fresh()->price);

        $versions = $car->versions()->get();
        $this->assertCount(1, $versions);
        $this->assertTrue((bool) $versions->first()->is_active);
        $this->assertEquals(4200, $versions->first()->data['price'] ?? null);
    }

    public function testVersioningDraftCreatesInactiveVersion(): void
    {
        $this->enableNewCarVersioning();
        $this->actingAs($this->getUser());
        $car = NewCar::factory()->create(['price' => 1000]);

        $count = $this->service()->update('same', [$car->id], ['field' => 'price', 'value' => 2222], 'draft');

        $this->assertSame(1, $count);
        $this->assertEquals(2222, $car->fresh()->price);

        $version = $car->versions()->first();
        $this->assertNotNull($version);
        $this->assertFalse((bool) $version->is_active);
    }

    private function service(): NewCarBulkUpdateService
    {
        return app(NewCarBulkUpdateService::class);
    }

    private function flagsFor(NewCar $newCar, int $mediaId): array
    {
        return $newCar->fresh()->mediaUses()
            ->where('media_id', $mediaId)
            ->value('flags') ?? [];
    }

    public function testFieldsIncludeImageFields(): void
    {
        $fields = collect($this->service()->getFields())->keyBy('name');

        foreach (['hero_image', 'mobile_hero_image', 'listing_image'] as $name) {
            $this->assertTrue($fields->has($name), "Expected '{$name}' in bulk update fields.");
            $this->assertSame('image', $fields[$name]['type']);
        }
    }

    public function testSameModeAppliesHeroFlagAcrossSelectedCars(): void
    {
        $carA = NewCar::factory()->create();
        $carB = NewCar::factory()->create();
        $media = Media::factory()->create();

        $count = $this->service()->update('same', [$carA->id, $carB->id], [
            'field' => 'hero_image',
            // UI submits media objects carrying an id.
            'value' => [['id' => $media->id, 'src' => 'thumb.jpg']],
        ]);

        $this->assertSame(2, $count);
        $this->assertTrue($this->flagsFor($carA, $media->id)['hero'] ?? false);
        $this->assertTrue($this->flagsFor($carB, $media->id)['hero'] ?? false);
    }

    public function testReplacingHeroImageMovesFlagAndRemovesOrphanUse(): void
    {
        $car = NewCar::factory()->create();
        $oldMedia = Media::factory()->create();
        $newMedia = Media::factory()->create();

        // Pre-existing hero use on the old media (hero is its only flag).
        $car->mediaUses()->create(['media_id' => $oldMedia->id, 'flags' => ['hero' => true]]);

        $this->service()->update('same', [$car->id], [
            'field' => 'hero_image',
            'value' => [$newMedia->id],
        ]);

        // Old media's use is gone (it carried no other flag), new media is hero.
        $this->assertSame(0, $car->fresh()->mediaUses()->where('media_id', $oldMedia->id)->count());
        $this->assertTrue($this->flagsFor($car, $newMedia->id)['hero'] ?? false);
    }

    public function testUpdatingHeroPreservesOtherFlagsOnSharedMedia(): void
    {
        $car = NewCar::factory()->create();
        $shared = Media::factory()->create();
        $newHero = Media::factory()->create();

        // One image acts as both hero and listing.
        $car->mediaUses()->create(['media_id' => $shared->id, 'flags' => ['hero' => true, 'listing' => true]]);

        $this->service()->update('same', [$car->id], [
            'field' => 'hero_image',
            'value' => [$newHero->id],
        ]);

        // Shared media keeps its listing flag and loses only hero; it is not deleted.
        $sharedFlags = $this->flagsFor($car, $shared->id);
        $this->assertArrayNotHasKey('hero', $sharedFlags);
        $this->assertTrue($sharedFlags['listing'] ?? false);
        $this->assertTrue($this->flagsFor($car, $newHero->id)['hero'] ?? false);
    }

    public function testDifferentModeSetsImagesPerCar(): void
    {
        $carA = NewCar::factory()->create();
        $carB = NewCar::factory()->create();
        $mediaA = Media::factory()->create();
        $mediaB = Media::factory()->create();

        $this->service()->update('different', [$carA->id, $carB->id], [
            'updates' => [
                $carA->id => ['hero_image' => [['id' => $mediaA->id]]],
                $carB->id => ['listing_image' => [['id' => $mediaB->id]]],
            ],
        ]);

        $this->assertTrue($this->flagsFor($carA, $mediaA->id)['hero'] ?? false);
        $this->assertTrue($this->flagsFor($carB, $mediaB->id)['listing'] ?? false);
    }

    public function testGetNewCarDataReturnsImageDescriptors(): void
    {
        $car = NewCar::factory()->create();
        $media = Media::factory()->create();
        $car->mediaUses()->create(['media_id' => $media->id, 'flags' => ['hero' => true]]);

        $data = $this->service()->getNewCarData([$car->id]);

        $this->assertArrayHasKey($car->id, $data);
        $this->assertCount(1, $data[$car->id]['hero_image']);
        $this->assertSame($media->id, $data[$car->id]['hero_image'][0]['id']);
        $this->assertArrayHasKey('src', $data[$car->id]['hero_image'][0]);
        // A flag with no media returns an empty list.
        $this->assertSame([], $data[$car->id]['mobile_hero_image']);
    }
}
