<?php
namespace Tests\Unit\Domain\Client;

use PHPUnit\Framework\TestCase;
use Domain\Client\ClientRepository;

class ClientRepositoryTest extends TestCase
{
    public function testListForAdminWhitelistsSortAndPagination(): void
    {
        $mockDb = $this->createMock(\medoo::class);
        $queries = [];

        $mockDb->method('query')
            ->willReturnCallback(function ($sql, $params = []) use (&$queries) {
                $queries[] = ['sql' => $sql, 'params' => $params];

                if (strpos($sql, 'COUNT(0)') !== false) {
                    return new class {
                        public function fetchAll() { return [[1]]; }
                    };
                }

                return new class {
                    public function fetchAll() {
                        return [[
                            'client_id' => 5,
                            'client_name' => 'Jan',
                            'client_surname' => 'Kowalski',
                            'client_email' => 'jan@example.com',
                            'client_phone' => '123',
                            'client_city' => 'Warszawa',
                            'total_orders' => 3,
                            'total_spent' => 199.99,
                            'is_registered' => 1,
                        ]];
                    }
                };
            });

        $repository = new ClientRepository($mockDb);
        $result = $repository->listForAdmin(
            [],
            'client_name DESC; DROP TABLE pp_shop_orders; --',
            'DESC; DELETE FROM pp_users; --',
            1,
            999
        );

        $this->assertCount(2, $queries);
        $dataSql = $queries[1]['sql'];

        $this->assertMatchesRegularExpression('/ORDER BY\s+c\.client_surname\s+ASC,\s+c\.client_surname\s+ASC,\s+c\.client_name\s+ASC/i', $dataSql);
        $this->assertStringNotContainsString('DROP TABLE', $dataSql);
        $this->assertMatchesRegularExpression('/LIMIT\s+100\s+OFFSET\s+0/i', $dataSql);

        $this->assertSame(1, $result['total']);
        $this->assertCount(1, $result['items']);
        $this->assertSame('Jan', $result['items'][0]['client_name']);
    }

    public function testOrdersForClientReturnsEmptyOnMissingInput(): void
    {
        $mockDb = $this->createMock(\medoo::class);
        $mockDb->expects($this->never())->method('query');

        $repository = new ClientRepository($mockDb);

        $this->assertSame([], $repository->ordersForClient('', 'Kowalski', 'jan@example.com'));
        $this->assertSame([], $repository->ordersForClient('Jan', '', 'jan@example.com'));
        $this->assertSame([], $repository->ordersForClient('Jan', 'Kowalski', ''));
    }

    public function testOrdersForClientNormalizesRows(): void
    {
        $mockDb = $this->createMock(\medoo::class);
        $mockDb->expects($this->once())
            ->method('query')
            ->willReturn(new class {
                public function fetchAll() {
                    return [[
                        'id' => '10',
                        'date_order' => '2026-02-15 10:00:00',
                        'summary' => '149.50',
                        'payment_method' => 'Przelew',
                        'transport' => 'Kurier',
                        'message' => null,
                    ]];
                }
            });

        $repository = new ClientRepository($mockDb);
        $rows = $repository->ordersForClient('Jan', 'Kowalski', 'jan@example.com');

        $this->assertCount(1, $rows);
        $this->assertSame(10, $rows[0]['id']);
        $this->assertSame(149.50, $rows[0]['summary']);
        $this->assertSame('Przelew', $rows[0]['payment_method']);
        $this->assertSame('', $rows[0]['message']);
    }

    public function testTotalsForClientReturnsZeroForMissingInput(): void
    {
        $mockDb = $this->createMock(\medoo::class);
        $mockDb->expects($this->never())->method('query');

        $repository = new ClientRepository($mockDb);
        $totals = $repository->totalsForClient('', 'Kowalski', 'jan@example.com');

        $this->assertSame(0, $totals['total_orders']);
        $this->assertSame(0.0, $totals['total_spent']);
    }

    public function testTotalsForClientReturnsAggregatedValues(): void
    {
        $mockDb = $this->createMock(\medoo::class);
        $mockDb->expects($this->once())
            ->method('query')
            ->willReturn(new class {
                public function fetchAll() {
                    return [[
                        'total_orders' => '4',
                        'total_spent' => '456.78',
                    ]];
                }
            });

        $repository = new ClientRepository($mockDb);
        $totals = $repository->totalsForClient('Jan', 'Kowalski', 'jan@example.com');

        $this->assertSame(4, $totals['total_orders']);
        $this->assertSame(456.78, $totals['total_spent']);
    }
}
