<?php

namespace App\Service;

use App\Entity\OrderNumber;
use App\Repository\OrderNumberRepository;
use Doctrine\ORM\EntityManagerInterface;

class OrderNumberService
{
    public function __construct(
        private OrderNumberRepository $repository,
        private EntityManagerInterface $em,
    ) {
    }

    /**
     * Genere le prochain numero de commande au format MM/YYYY-XXXXX.
     * Reutilise en priorite un OrderNumber existant non utilise (isUsed = false),
     * sinon cree un nouveau (compteur XXXXX reset chaque mois).
     */
    public function generate(): OrderNumber
    {
        $unused = $this->repository->createQueryBuilder('o')
            ->where('o.isUsed = false')
            ->orderBy('o.createdAt', 'ASC')
            ->setMaxResults(1)
            ->getQuery()
            ->getOneOrNullResult();

        if (null !== $unused) {
            return $unused;
        }

        $now = new \DateTimeImmutable();
        $prefix = $now->format('m/Y').'-';

        $lastOrder = $this->repository->createQueryBuilder('o')
            ->where('o.numOrder LIKE :prefix')
            ->setParameter('prefix', $prefix.'%')
            ->orderBy('o.numOrder', 'DESC')
            ->setMaxResults(1)
            ->getQuery()
            ->getOneOrNullResult();

        if (null !== $lastOrder) {
            $lastNum = (int) substr($lastOrder->getNumOrder(), \strlen($prefix));
            $nextNum = $lastNum + 1;
        } else {
            $nextNum = 1;
        }

        $numOrder = $prefix.str_pad((string) $nextNum, 5, '0', \STR_PAD_LEFT);

        $orderNumber = new OrderNumber($numOrder);
        $this->em->persist($orderNumber);
        $this->em->flush();

        return $orderNumber;
    }

    /**
     * Genere et marque comme utilise en une seule operation.
     */
    public function generateAndUse(): OrderNumber
    {
        $orderNumber = $this->generate();
        $orderNumber->markAsUsed();
        $this->em->flush();

        return $orderNumber;
    }

    /**
     * Recupere le prochain numero sans le creer.
     * Reutilise un OrderNumber existant non utilise (isUsed = false) en priorite,
     * sinon calcule le prochain numero du mois courant.
     */
    public function preview(): string
    {
        $unused = $this->repository->createQueryBuilder('o')
            ->where('o.isUsed = false')
            ->orderBy('o.createdAt', 'ASC')
            ->setMaxResults(1)
            ->getQuery()
            ->getOneOrNullResult();

        if (null !== $unused) {
            return $unused->getNumOrder();
        }

        $now = new \DateTimeImmutable();
        $prefix = $now->format('m/Y').'-';

        $lastOrder = $this->repository->createQueryBuilder('o')
            ->where('o.numOrder LIKE :prefix')
            ->setParameter('prefix', $prefix.'%')
            ->orderBy('o.numOrder', 'DESC')
            ->setMaxResults(1)
            ->getQuery()
            ->getOneOrNullResult();

        $nextNum = null !== $lastOrder
            ? (int) substr($lastOrder->getNumOrder(), \strlen($prefix)) + 1
            : 1;

        return $prefix.str_pad((string) $nextNum, 5, '0', \STR_PAD_LEFT);
    }
}
