<?php

app_require('classes/department_wash_count_service.php');

use classes\department_wash_count_service;

final class DepartmentWashCountFakeResult
{
    public int $num_rows;
    private int $cursor = 0;

    public function __construct(private readonly array $rows)
    {
        $this->num_rows = count($rows);
    }

    public function fetch_assoc(): ?array
    {
        if (!array_key_exists($this->cursor, $this->rows)) {
            return null;
        }

        return $this->rows[$this->cursor++];
    }
}

final class DepartmentWashCountFakeDb
{
    public array $queries = [];

    public function escape_string(string $value): string
    {
        return addslashes($value);
    }

    public function getDatabase(): string
    {
        return 'test_db';
    }

    public function query(string $sql): DepartmentWashCountFakeResult
    {
        $this->queries[] = $sql;

        if (str_contains($sql, 'information_schema.COLUMNS') || str_contains($sql, 'information_schema.STATISTICS')) {
            return new DepartmentWashCountFakeResult([['c' => 1, 'DATA_TYPE' => 'text']]);
        }

        if (str_contains($sql, 'COUNT(DISTINCT o.id) AS quantity')) {
            return new DepartmentWashCountFakeResult([[
                'quantity' => 3,
                'products' => 5,
                'earnings' => 250,
            ]]);
        }

        return new DepartmentWashCountFakeResult([[
            'department_id' => 7,
            'hour_bucket' => '2026-04-01 12:00:00',
            'wash_count' => 2,
        ]]);
    }
}

function department_wash_count_find_query(array $queries, string $needle): string
{
    foreach ($queries as $query) {
        if (str_contains($query, $needle)) {
            return $query;
        }
    }

    return '';
}

it('builds wash counts from order washes and completed self-serve sessions with linked-order dedupe', function (): void {
    $hadDb = array_key_exists('db', $GLOBALS);
    $previousDb = $GLOBALS['db'] ?? null;
    $fakeDb = new DepartmentWashCountFakeDb();
    $GLOBALS['db'] = $fakeDb;

    try {
        $service = new department_wash_count_service();

        $rows = $service->countByHourForDepartments('2026-04-01 00:00:00', '2026-04-01 23:59:59', [7]);

        expect($rows)->toBe([[
            'department_id' => 7,
            'hour_bucket' => '2026-04-01 12:00:00',
            'wash_count' => 2,
        ]]);

        $query = department_wash_count_find_query($fakeDb->queries, 'FROM selfserve_wash_sessions s');
        expect($query)->toContain('FROM selfserve_wash_sessions s')
            ->and($query)->toContain("UPPER(TRIM(s.status)) = 'COMPLETED'")
            ->and($query)->toContain('s.completed_at IS NOT NULL')
            ->and($query)->toContain('COALESCE(linked_o.created_at, s.completed_at)')
            ->and($query)->toContain("CONCAT('order:', linked_o.id)")
            ->and($query)->toContain('GROUP BY dedupe_key, department_id');
    } finally {
        if ($hadDb) {
            $GLOBALS['db'] = $previousDb;
        } else {
            unset($GLOBALS['db']);
        }
    }
});

it('keeps transaction totals order-based while using expanded wash counts', function (): void {
    $hadDb = array_key_exists('db', $GLOBALS);
    $previousDb = $GLOBALS['db'] ?? null;
    $fakeDb = new DepartmentWashCountFakeDb();
    $GLOBALS['db'] = $fakeDb;

    try {
        $service = new department_wash_count_service();

        $summary = $service->transactionSummary('2026-04-01 00:00:00', '2026-04-01 23:59:59', [7]);

        expect($summary)->toBe([
            'quantity' => 3,
            'products' => 5,
            'earnings' => 250,
            'washes' => 2,
        ]);
        $summaryQuery = department_wash_count_find_query($fakeDb->queries, 'COUNT(DISTINCT o.id) AS quantity');
        $countQuery = department_wash_count_find_query($fakeDb->queries, 'FROM selfserve_wash_sessions s');
        expect($summaryQuery)->toContain('COUNT(DISTINCT o.id) AS quantity')
            ->and($summaryQuery)->not->toContain('selfserve_wash_sessions')
            ->and($countQuery)->toContain('selfserve_wash_sessions');
    } finally {
        if ($hadDb) {
            $GLOBALS['db'] = $previousDb;
        } else {
            unset($GLOBALS['db']);
        }
    }
});
