<?php

namespace Tests\Tenant;

use Illuminate\Support\Facades\Queue;
use Mtc\ContentManager\Facades\Media as MediaFacade;
use Mtc\MercuryDataModels\Media;
use Mtc\MercuryDataModels\MediaUse;
use Mtc\MercuryDataModels\Vehicle;
use Tests\TenantTestCase;

class MediaPrimaryUseTest extends TenantTestCase
{
    /**
     * Mirrors the AutoTrader scenario: a vehicle is first synced with a single
     * primary image, then a later sync adds another image as the new primary.
     * The previous primary must be cleared so only one primary remains.
     */
    public function testSettingANewPrimaryClearsThePreviousPrimary()
    {
        Queue::fake();

        $vehicle = Vehicle::factory()->create();
        $firstImage = Media::factory()->create(['external' => true]);
        $secondImage = Media::factory()->create(['external' => true]);

        // Initial sync - first image becomes primary.
        MediaFacade::setUsesForModel([$firstImage->id], $vehicle, ['primary' => true], false);

        $this->assertTrue((bool) $this->useFor($vehicle, $firstImage->id)->primary);

        // Later sync - a newly added image is set as the new primary.
        MediaFacade::setUsesForModel([$secondImage->id], $vehicle, ['primary' => true], false);

        $primaryUses = MediaUse::query()
            ->where('owner_type', $vehicle->getMorphClass())
            ->where('owner_id', $vehicle->id)
            ->where('primary', true)
            ->get();

        $this->assertCount(1, $primaryUses, 'A vehicle must only ever have a single primary image.');
        $this->assertSame($secondImage->id, $primaryUses->first()->media_id);
        $this->assertFalse((bool) $this->useFor($vehicle, $firstImage->id)->primary);
    }

    /**
     * A re-sync (or manual media deletion) can leave a vehicle with images but no primary use,
     * so primaryMediaUse resolves to null and the front-end shows a placeholder. ensurePrimaryUse
     * must promote the lowest-ordered use in that case.
     */
    public function testEnsurePrimaryUsePromotesLowestOrderWhenNoPrimaryExists()
    {
        Queue::fake();

        $vehicle = Vehicle::factory()->create();
        $first = Media::factory()->create(['external' => true]);
        $second = Media::factory()->create(['external' => true]);

        // Attach both with no primary flagged (the broken zero-primary state).
        MediaFacade::setUsesForModel([$first->id, $second->id], $vehicle, ['primary' => false], false);
        $this->assertCount(0, $this->primaryUses($vehicle));

        MediaFacade::ensurePrimaryUse($vehicle);

        $primaryUses = $this->primaryUses($vehicle);
        $this->assertCount(1, $primaryUses, 'A single primary should be elected.');
        $this->assertSame($first->id, $primaryUses->first()->media_id, 'The lowest-ordered use wins.');
    }

    /**
     * ensurePrimaryUse must never override an existing primary (e.g. one chosen manually in admin),
     * only fill in a missing one.
     */
    public function testEnsurePrimaryUseLeavesAnExistingPrimaryUntouched()
    {
        Queue::fake();

        $vehicle = Vehicle::factory()->create();
        $first = Media::factory()->create(['external' => true]);
        $second = Media::factory()->create(['external' => true]);

        MediaFacade::setUsesForModel([$first->id, $second->id], $vehicle, ['primary' => false], false);
        // Mark the higher-ordered image as primary, as a manual selection would.
        $this->useFor($vehicle, $second->id)->update(['primary' => true]);

        MediaFacade::ensurePrimaryUse($vehicle);

        $primaryUses = $this->primaryUses($vehicle);
        $this->assertCount(1, $primaryUses);
        $this->assertSame($second->id, $primaryUses->first()->media_id, 'The existing primary is preserved.');
        $this->assertFalse((bool) $this->useFor($vehicle, $first->id)->primary);
    }

    /**
     * A vehicle with no media at all must be handled without error.
     */
    public function testEnsurePrimaryUseIsANoOpWhenThereIsNoMedia()
    {
        $vehicle = Vehicle::factory()->create();

        MediaFacade::ensurePrimaryUse($vehicle);

        $this->assertCount(0, $this->primaryUses($vehicle));
    }

    private function primaryUses(Vehicle $vehicle)
    {
        return MediaUse::query()
            ->where('owner_type', $vehicle->getMorphClass())
            ->where('owner_id', $vehicle->id)
            ->where('primary', true)
            ->get();
    }

    private function useFor(Vehicle $vehicle, int $mediaId): MediaUse
    {
        return MediaUse::query()
            ->where('owner_type', $vehicle->getMorphClass())
            ->where('owner_id', $vehicle->id)
            ->where('media_id', $mediaId)
            ->firstOrFail();
    }
}
