<?php

namespace Tests\Unit\AdOps;

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

/**
 * isApiSuccess exists because the legacy CI3 advertisers7 API routinely
 * returns HTTP 200 with {"status":false,"message":"..."} for business-logic
 * failures. Without this check every call that hits that pattern was recorded
 * as a success in both the UI and Shorty.adcenter_log.
 */
final class ImportExportServiceSuccessTest extends TestCase
{
    public function testHttp2xxWithNoStatusKeyIsSuccess(): void
    {
        $res  = ['status' => 200];
        $body = ['id' => 42];
        $this->assertTrue(ImportExportService::isApiSuccess($res, $body));
    }

    public function testHttp2xxWithApplicationStatusFalseIsFailure(): void
    {
        // The regression this function exists to fix.
        $res  = ['status' => 200];
        $body = ['status' => false, 'message' => 'Invalid bid'];
        $this->assertFalse(ImportExportService::isApiSuccess($res, $body));
    }

    public function testHttp2xxWithApplicationStatusTrueIsSuccess(): void
    {
        $res  = ['status' => 200];
        $body = ['status' => true, 'id' => 42];
        $this->assertTrue(ImportExportService::isApiSuccess($res, $body));
    }

    public function testHttp4xxIsAlwaysFailure(): void
    {
        $res  = ['status' => 422];
        $body = ['status' => true]; // Even if the body lies
        $this->assertFalse(ImportExportService::isApiSuccess($res, $body));
    }

    public function testTransportFailure599IsFailure(): void
    {
        // ApiClient returns status=599 on Throwable so `< 400` success
        // checks reliably treat network errors as failures.
        $res  = ['status' => 599];
        $body = [];
        $this->assertFalse(ImportExportService::isApiSuccess($res, $body));
    }

    public function testHttp201CreatedIsSuccess(): void
    {
        $res  = ['status' => 201];
        $body = ['id' => 99];
        $this->assertTrue(ImportExportService::isApiSuccess($res, $body));
    }

    public function testHttp3xxIsSuccessBoundary(): void
    {
        // The condition is < 400, so redirects are treated as success.
        // This documents the boundary rather than asserts correctness —
        // the legacy API should never redirect, but if it does, callers
        // treat it as success today.
        $res  = ['status' => 302];
        $body = [];
        $this->assertTrue(ImportExportService::isApiSuccess($res, $body));
    }

    /**
     * describeErrors() exists because a bad creative-type upload previously
     * surfaced a raw "HTTP 422" (no top-level `message`, only `errors`) or,
     * on the legacy side, a literal "Array" from concatenating errors[]
     * directly into a string.
     */
    public function testDescribeErrorsFormatsFieldMessagePairs(): void
    {
        $errors = [
            ['field' => 'type', 'message' => 'Invalid creative type'],
        ];
        $this->assertSame('Field-type (Invalid creative type)', ImportExportService::describeErrors($errors));
    }

    public function testDescribeErrorsJoinsMultiplePairs(): void
    {
        $errors = [
            ['field' => 'type', 'message' => 'Invalid creative type'],
            ['field' => 'size', 'message' => 'Required'],
        ];
        $this->assertSame(
            'Field-type (Invalid creative type); Field-size (Required)',
            ImportExportService::describeErrors($errors)
        );
    }

    public function testDescribeErrorsReturnsPlainStringAsIs(): void
    {
        $this->assertSame(
            'Rank field should be blank if parent_creative_id is not present !!',
            ImportExportService::describeErrors('Rank field should be blank if parent_creative_id is not present !!')
        );
    }

    public function testDescribeErrorsReturnsNullWhenEmpty(): void
    {
        $this->assertNull(ImportExportService::describeErrors(null));
        $this->assertNull(ImportExportService::describeErrors([]));
        $this->assertNull(ImportExportService::describeErrors(''));
    }
}
