<?php

namespace MintyPHP\Tests\Module\Helpdesk\Service;

use MintyPHP\Module\Helpdesk\Service\BcODataGateway;
use MintyPHP\Module\Helpdesk\Service\DomainListService;
use MintyPHP\Module\Helpdesk\Service\DomainSecurityLevelService;
use PHPUnit\Framework\TestCase;

class DomainListServiceTest extends TestCase
{
    private const TENANT_ID = 7;

    public function testFiltersByState(): void
    {
        $service = $this->buildService($this->sampleDomains());
        $result = $service->query(self::TENANT_ID, ['state' => 'Aktiv']);

        $this->assertSame(2, $result['total']);
        $this->assertEqualsCanonicalizing(
            ['DNS001', 'DNS002'],
            array_column($result['rows'], 'No')
        );
    }

    public function testFiltersBySearchAcrossMultipleColumns(): void
    {
        $service = $this->buildService($this->sampleDomains());
        $result = $service->query(self::TENANT_ID, ['search' => 'example.com']);

        $this->assertSame(1, $result['total']);
        $this->assertSame('DNS001', $result['rows'][0]['No']);
    }

    public function testAllValueDisablesFilter(): void
    {
        $service = $this->buildService($this->sampleDomains());
        $result = $service->query(self::TENANT_ID, ['state' => 'all']);

        $this->assertSame(3, $result['total']);
    }

    public function testSortingAscAndDesc(): void
    {
        $domains = $this->sampleDomains();
        $service = $this->buildService($domains);

        $asc = $service->query(self::TENANT_ID, ['order' => 'No', 'dir' => 'asc']);
        $desc = $service->query(self::TENANT_ID, ['order' => 'No', 'dir' => 'desc']);

        $this->assertSame(['DNS001', 'DNS002', 'DNS003'], array_column($asc['rows'], 'No'));
        $this->assertSame(['DNS003', 'DNS002', 'DNS001'], array_column($desc['rows'], 'No'));
    }

    public function testLimitAndOffsetPaging(): void
    {
        $service = $this->buildService($this->sampleDomains());
        $result = $service->query(self::TENANT_ID, [
            'order' => 'No',
            'dir' => 'asc',
            'limit' => 1,
            'offset' => 1,
        ]);

        $this->assertSame(3, $result['total'], 'total counts the filtered set before paging');
        $this->assertCount(1, $result['rows']);
        $this->assertSame('DNS002', $result['rows'][0]['No']);
    }

    public function testEnrichesRowsWithSecurityLevelVariantAndNote(): void
    {
        $levels = $this->createMock(DomainSecurityLevelService::class);
        $levels->method('getAllDetailsForDomains')->willReturn([
            'DNS001' => ['level' => 'hoch', 'note' => 'important'],
        ]);

        $gateway = $this->createMock(BcODataGateway::class);
        $gateway->method('listDomains')->willReturn($this->sampleDomains());
        $gateway->method('listDomainContractLines')->willReturn([]);

        $service = new DomainListService($gateway, $levels);
        $result = $service->query(self::TENANT_ID, ['order' => 'No', 'dir' => 'asc']);

        $first = $result['rows'][0];
        $this->assertSame('hoch', $first['security_level']);
        $this->assertSame('important', $first['security_level_note']);
        $this->assertSame(DomainSecurityLevelService::getBadgeVariant('hoch'), $first['security_level_variant']);
    }

    public function testBcFailureReturnsEmptyResult(): void
    {
        $gateway = $this->createMock(BcODataGateway::class);
        $gateway->method('listDomains')->willThrowException(new \RuntimeException('upstream down'));

        $levels = $this->createMock(DomainSecurityLevelService::class);

        $service = new DomainListService($gateway, $levels);
        $result = $service->query(self::TENANT_ID, []);

        $this->assertSame(['rows' => [], 'total' => 0], $result);
    }

    public function testSecurityLevelFilterRestrictsTenantScoped(): void
    {
        $gateway = $this->createMock(BcODataGateway::class);
        $gateway->method('listDomains')->willReturn($this->sampleDomains());
        $gateway->method('listDomainContractLines')->willReturn([]);

        $levels = $this->createMock(DomainSecurityLevelService::class);
        $levels->expects($this->once())
            ->method('getAllLevelsForDomains')
            ->with(self::TENANT_ID, $this->callback(static fn (array $nos): bool => $nos === ['DNS001', 'DNS002', 'DNS003']))
            ->willReturn(['DNS002' => 'hoch']);
        $levels->method('getAllDetailsForDomains')->willReturn([]);

        $service = new DomainListService($gateway, $levels);
        $result = $service->query(self::TENANT_ID, ['security_level' => 'hoch']);

        $this->assertSame(1, $result['total']);
        $this->assertSame('DNS002', $result['rows'][0]['No']);
    }

    /**
     * @param list<array<string,mixed>> $domains
     */
    private function buildService(array $domains): DomainListService
    {
        $gateway = $this->createMock(BcODataGateway::class);
        $gateway->method('listDomains')->willReturn($domains);
        $gateway->method('listDomainContractLines')->willReturn([]);

        $levels = $this->createMock(DomainSecurityLevelService::class);
        $levels->method('getAllDetailsForDomains')->willReturn([]);
        $levels->method('getAllLevelsForDomains')->willReturn([]);

        return new DomainListService($gateway, $levels);
    }

    /**
     * @return list<array<string,mixed>>
     */
    private function sampleDomains(): array
    {
        return [
            ['No' => 'DNS001', 'Customer_No' => 'C-1', 'Customer_Name' => 'Acme GmbH',   'URL' => 'example.com', 'State' => 'Aktiv',            'Administration' => 'A'],
            ['No' => 'DNS002', 'Customer_No' => 'C-2', 'Customer_Name' => 'Beta AG',     'URL' => 'beta.de',     'State' => 'Aktiv',            'Administration' => 'A'],
            ['No' => 'DNS003', 'Customer_No' => 'C-3', 'Customer_Name' => 'Gamma KG',    'URL' => 'gamma.io',    'State' => 'In Vorbereitung', 'Administration' => 'B'],
        ];
    }
}
