<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\CoreBundle\Payments;

use Ferienpass\CoreBundle\Repository\PaymentRepository;
use Ferienpass\CoreBundle\Settings\SystemSettingsManager;

class ReceiptNumberGenerator
{
    private int $length = 0;

    public function __construct(private readonly SystemSettingsManager $systemSettingsManager, private readonly PaymentRepository $payments)
    {
    }

    public function generate(): string
    {
        $prefix = $this->systemSettingsManager->getReceiptNumberPrefix() ?? '';
        $offset1 = mb_strlen($prefix);

        $qb = $this->payments->createQueryBuilder('p');

        $select = 'p.receiptNumber';
        if (0 !== $offset1) {
            $select = \sprintf('substring(%s, %s)', $select, ++$offset1);
        }

        // Easy way to "cast" to integer (substring returns string, no natural sorting)
        // when CAST() function is not available in ORM.
        $select = "$select + 0";

        $qb->select("$select AS docNumber");

        if ('' !== $prefix && '0' !== $prefix) {
            $qb->where($qb->expr()->like('p.receiptNumber', ':prefix'));
            $qb->setParameter('prefix', addcslashes($prefix, '%_\\').'%');
        }

        $qb->orderBy('docNumber', 'DESC');

        $result = $qb->setMaxResults(1)->getQuery()->getOneOrNullResult();
        $docNumber = null === $result ? 0 : ((int) ($result['docNumber'] ?? 0));

        return \sprintf('%s%s', $prefix, str_pad((string) ++$docNumber, $this->length, '0', \STR_PAD_LEFT));
    }
}
