<?php

namespace Tests\Unit\Campaign;

use App\Services\Campaign\TargetingJson;
use PHPUnit\Framework\TestCase;

/**
 * Overlay of form-built targeting onto the stored JSON.
 *
 * Pins the two properties that keep XML whitelist (and other unmodeled keys)
 * alive across a campaign Save:
 *
 *  1. Top-level keys the form did not write (`affiliates`, `pop_type`) are
 *     copied forward from the stored document.
 *  2. Nested `exclude` is merged so a posted zip overlay does not wipe a
 *     sibling `exclude.countries` the form never sent. Form-posted keys win.
 */
final class TargetingJsonTest extends TestCase
{
    public function testPreservesUnmodeledKeysAndMergesExclude(): void
    {
        $existing = [
            'affiliates' => ['120438'],
            'pop_type'   => 'tab',
            'countries'  => ['USA'],
            'exclude'    => [
                'countries' => ['CAN'],
            ],
        ];

        $fromForm = [
            'countries' => ['USA'],
            'ron'       => 0,
            'exclude'   => [
                'zip' => ['90210'],
            ],
        ];

        $merged = TargetingJson::mergeFormOntoExisting($fromForm, $existing);

        $this->assertSame(['120438'], $merged['affiliates']);
        $this->assertSame('tab', $merged['pop_type']);
        $this->assertSame(['USA'], $merged['countries']);
        $this->assertSame(0, $merged['ron']);
        $this->assertSame(['CAN'], $merged['exclude']['countries']);
        $this->assertSame(['90210'], $merged['exclude']['zip']);
    }

    public function testFormPostedKeysWin(): void
    {
        $existing = [
            'affiliates' => ['120438'],
            'countries'  => ['USA'],
            'ron'        => 1,
            'exclude'    => [
                'zip' => ['10001'],
            ],
        ];

        $fromForm = [
            'countries' => ['GBR'],
            'ron'       => 0,
            'exclude'   => [
                'zip' => ['90210'],
            ],
        ];

        $merged = TargetingJson::mergeFormOntoExisting($fromForm, $existing);

        $this->assertSame(['GBR'], $merged['countries']);
        $this->assertSame(0, $merged['ron']);
        $this->assertSame(['90210'], $merged['exclude']['zip']);
        $this->assertSame(['120438'], $merged['affiliates']);
    }

    public function testEmptyExistingReturnsFormArray(): void
    {
        $fromForm = [
            'countries' => ['USA'],
            'ron'       => 0,
            'exclude'   => ['zip' => []],
        ];

        $this->assertSame($fromForm, TargetingJson::mergeFormOntoExisting($fromForm, []));
    }

    public function testExistingExcludeSurvivesWhenFormOmitsExclude(): void
    {
        $existing = [
            'pop_type' => 'tab',
            'exclude'  => ['countries' => ['MEX']],
        ];
        $fromForm = [
            'countries' => ['USA'],
            'ron'       => 1,
        ];

        $merged = TargetingJson::mergeFormOntoExisting($fromForm, $existing);

        $this->assertSame('tab', $merged['pop_type']);
        $this->assertSame(['MEX'], $merged['exclude']['countries']);
    }

    public function testClearedFrequencyDoesNotComeBackFromExisting(): void
    {
        $existing = [
            'frequency'  => 100,
            'affiliates' => ['120438'],
        ];
        $fromForm = [
            'countries' => ['USA'],
            'ron'       => 0,
        ];

        $merged = TargetingJson::mergeFormOntoExisting($fromForm, $existing, ['frequency']);

        $this->assertArrayNotHasKey('frequency', $merged);
        $this->assertSame(['120438'], $merged['affiliates']);
        $this->assertSame(['USA'], $merged['countries']);
    }

    public function testOmittingFrequencyWithoutClearKeepsExistingCap(): void
    {
        $existing = [
            'frequency'  => 100,
            'affiliates' => ['120438'],
        ];
        $fromForm = [
            'countries' => ['USA'],
            'ron'       => 0,
        ];

        $merged = TargetingJson::mergeFormOntoExisting($fromForm, $existing);

        $this->assertSame(100, $merged['frequency']);
        $this->assertSame(['120438'], $merged['affiliates']);
    }

    public function testClearedModeledKeysDoNotComeBackFromExisting(): void
    {
        $existing = [
            'connection_types' => ['wifi'],
            'categories'       => ['include' => ['IAB1-1']],
            'affiliates'       => ['120438'],
            'pop_type'         => 'tab',
        ];
        $fromForm = [
            'countries' => ['USA'],
        ];

        $merged = TargetingJson::mergeFormOntoExisting(
            $fromForm,
            $existing,
            ['connection_types', 'categories']
        );

        $this->assertArrayNotHasKey('connection_types', $merged);
        $this->assertArrayNotHasKey('categories', $merged);
        $this->assertSame(['120438'], $merged['affiliates']);
        $this->assertSame('tab', $merged['pop_type']);
    }
}
