<?php

namespace Tests\Unit\AdOps;

use App\Services\AdOps\BulkTextEdit;
use PHPUnit\Framework\TestCase;

/**
 * Bulk Edit validated only 'complete' mode, the one whose new value arrives whole.
 * The other three compute the result in SQL (REPLACE / CONCAT), so nothing in PHP
 * ever saw it — appending arbitrary text to a destination stored something that is
 * not a URL, and appending to a display URL could push it past creative_url's 50
 * characters and truncate silently.
 */
final class BulkTextEditTest extends TestCase
{
    public function testAppendingToADestinationIsJudgedOnTheHostNotTheTail(): void
    {
        // The destination rule matches a PREFIX on purpose — it mirrors the API's own
        // MY_Form_validation::url(), and a destination legitimately carries a query
        // string, a fragment and tracking macros. So an append that leaves the host
        // intact is accepted whatever follows it; what the check catches is an edit
        // that destroys the host or the scheme, covered below.
        $result = BulkTextEdit::resultOf('append', 'https://www.example.com/shop', ['append_str' => '&sub=abc']);

        $this->assertSame('https://www.example.com/shop&sub=abc', $result);
        $this->assertTrue(BulkTextEdit::accepts('destination', $result));
    }

    public function testAppendingPlainTextToADisplayUrlIsRejected(): void
    {
        // The display rule IS anchored at both ends, so trailing prose is refused
        // here — this is the field QA typed plain text into.
        $result = BulkTextEdit::resultOf('append', 'www.example.com', ['append_str' => 'hello there']);

        $this->assertFalse(BulkTextEdit::accepts('display_url', $result));
    }

    public function testAppendingATrackingParameterToADestinationIsAccepted(): void
    {
        $result = BulkTextEdit::resultOf('append', 'https://www.example.com/shop', ['append_str' => '?utm_source=ad']);

        $this->assertTrue(BulkTextEdit::accepts('destination', $result));
    }

    public function testAReplaceThatDestroysTheHostIsRejected(): void
    {
        $result = BulkTextEdit::resultOf('partial', 'https://www.example.com/shop', [
            'search'  => 'www.example.com',
            'replace' => 'our new site',
        ]);

        $this->assertFalse(BulkTextEdit::accepts('destination', $result));
    }

    public function testAReplaceThatSwapsOneDomainForAnotherIsAccepted(): void
    {
        $result = BulkTextEdit::resultOf('partial', 'https://www.example.com/shop', [
            'search'  => 'example.com',
            'replace' => 'example.co.uk',
        ]);

        $this->assertSame('https://www.example.co.uk/shop', $result);
        $this->assertTrue(BulkTextEdit::accepts('destination', $result));
    }

    public function testRemovingTheSchemeFromADestinationIsRejected(): void
    {
        // A destination needs the scheme — the API's own rule requires "//".
        $result = BulkTextEdit::resultOf('remove', 'https://www.example.com', ['search' => 'https://']);

        $this->assertFalse(BulkTextEdit::accepts('destination', $result));
    }

    public function testADisplayUrlPushedPastTheColumnWidthIsRejected(): void
    {
        // creative_url is varchar(50), so this used to truncate without a word.
        $result = BulkTextEdit::resultOf('append', 'www.example.com', [
            'append_str' => '/' . str_repeat('a', 60),
        ]);

        $this->assertGreaterThan(BulkTextEdit::DISPLAY_URL_MAX, mb_strlen($result));
        $this->assertFalse(BulkTextEdit::accepts('display_url', $result));
    }

    public function testADisplayUrlNeedsNoSchemeToBeAccepted(): void
    {
        // Most stored display URLs have none.
        $this->assertTrue(BulkTextEdit::accepts('display_url', 'www.example.com/shop'));
    }

    public function testASchemeWithNoTldIsRejectedForBothFields(): void
    {
        $this->assertFalse(BulkTextEdit::accepts('destination', 'http://foo'));
        $this->assertFalse(BulkTextEdit::accepts('display_url', 'http://foo'));
    }

    public function testAnEmptyResultIsRejected(): void
    {
        $result = BulkTextEdit::resultOf('remove', 'www.example.com', ['search' => 'www.example.com']);

        $this->assertSame('', $result);
        $this->assertFalse(BulkTextEdit::accepts('display_url', $result));
    }

    public function testReplaceIsCaseSensitiveLikeTheSql(): void
    {
        // MySQL's REPLACE() is case-sensitive, so this has to be too or the value
        // validated here is not the value stored.
        $result = BulkTextEdit::resultOf('partial', 'https://www.Example.com', [
            'search'  => 'example.com',
            'replace' => 'other.com',
        ]);

        $this->assertSame('https://www.Example.com', $result);
    }

    public function testOnlyTheTwoUrlColumnsAreSubjectToTheseRules(): void
    {
        $this->assertTrue(BulkTextEdit::isUrlField('destination'));
        $this->assertTrue(BulkTextEdit::isUrlField('display_url'));
        // Headline and description are free text; a URL check there would be wrong.
        $this->assertFalse(BulkTextEdit::isUrlField('title'));
        $this->assertFalse(BulkTextEdit::isUrlField('description'));
    }
}
