<?php

namespace Tests\Feature;

use App\Campaigns\Platforms\Platforms;
use App\Models\Campaign;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use PHPUnit\Framework\Attributes\DataProvider;
use Tests\TestCase;

/**
 * The preview is drawn at the width of the device the ad set targets.
 *
 * It was one fixed width whatever the campaign targeted, so a desktop-only
 * campaign was reviewed at phone width and a mobile-only one at desktop width.
 * That is not a cosmetic difference: Meta lays the two out differently and the
 * headline is what gets truncated, which is the single thing a buyer opens the
 * preview to check.
 *
 * Asserted against the rendered partial rather than a helper, because the
 * decision is made in the template and nothing below it knows the preview
 * exists.
 */
class AdPreviewDeviceTest extends TestCase
{
    use RefreshDatabase;

    private function campaignWithAnAd(array $devices): Campaign
    {
        $campaign = Campaign::create([
            'user_id' => User::factory()->create()->id,
            'name' => 'Test',
            'platform' => 'meta',
            'status' => 'draft',
            'landing_url' => 'https://example.com',
            'audience' => ['devices' => $devices],
        ]);

        // The preview block only renders once there is something to preview.
        $campaign->ads()->create([
            'headline' => 'A headline',
            'primary_text' => 'Some body copy.',
            'cta' => 'LEARN_MORE',
        ]);

        return $campaign->fresh();
    }

    private function panel(Campaign $campaign): string
    {
        return view('partials.campaign-panel', [
            'campaign' => $campaign,
            'rules' => app(Platforms::class)->for($campaign),
            'progress' => [],
            'nextStep' => null,
            'blocking' => [],
            'sources' => [],
            'pending' => [],
            'needsRebuild' => [],
            'campaigns' => collect([$campaign]),
            'assets' => collect(),
        ])->render();
    }

    /**
     * @param  list<string>  $devices
     */
    #[DataProvider('singleDeviceCampaigns')]
    public function test_a_campaign_targeting_one_device_previews_on_that_device(array $devices, string $expected): void
    {
        $html = $this->panel($this->campaignWithAnAd($devices));

        $this->assertStringContainsString('mb-ad-mockups mb-3 is-'.$expected, $html);
    }

    /**
     * @return array<string, array{list<string>, string}>
     */
    public static function singleDeviceCampaigns(): array
    {
        return [
            'mobile only' => [['mobile'], 'mobile'],
            'desktop only' => [['desktop'], 'desktop'],
        ];
    }

    /**
     * A device the ad set will never serve is not offered.
     *
     * Previewing a placement that cannot happen is a preview of nothing, and it
     * invites a buyer to sign off copy against a layout their campaign will not
     * use.
     */
    public function test_a_device_the_campaign_does_not_target_is_not_offered(): void
    {
        $html = $this->panel($this->campaignWithAnAd(['desktop']));

        $this->assertStringNotContainsString('data-ad-device="mobile"', $html);
        $this->assertStringContainsString('only device this ad set targets', $html);
    }

    /** Both targeted means both offered, opening on mobile. */
    public function test_both_devices_are_offered_when_both_are_targeted(): void
    {
        $html = $this->panel($this->campaignWithAnAd(['mobile', 'desktop']));

        $this->assertStringContainsString('data-ad-device="mobile"', $html);
        $this->assertStringContainsString('data-ad-device="desktop"', $html);
        $this->assertStringContainsString('mb-ad-mockups mb-3 is-mobile', $html);
    }

    /**
     * Nothing chosen yet is not the same as nothing targeted.
     *
     * The device question comes after the ads are drafted, so the preview exists
     * before the answer does. Showing one device then would be picking on the
     * buyer's behalf and recording it nowhere.
     */
    public function test_a_campaign_with_no_devices_yet_offers_both(): void
    {
        $html = $this->panel($this->campaignWithAnAd([]));

        $this->assertStringContainsString('data-ad-device="mobile"', $html);
        $this->assertStringContainsString('data-ad-device="desktop"', $html);
    }

    /** The order the devices were stored in does not decide the preview. */
    public function test_the_stored_order_does_not_change_which_device_opens(): void
    {
        $html = $this->panel($this->campaignWithAnAd(['desktop', 'mobile']));

        $this->assertStringContainsString('mb-ad-mockups mb-3 is-mobile', $html);
    }
}
