<?php

namespace Myvetshop\Module\Clinique\Adapter\Recommandation;

use Myvetshop\Module\Clinique\Adapter\Repository\CombinationRepository;
use Myvetshop\Module\Clinique\Entity\RecommandationProduct;
use Myvetshop\Module\Clinique\Repository\MyvetshopCliniqueRepository;

class RecommandationProductCombinationSelector implements RecommandationProductCombinationSelectorInterface
{
    private CombinationRepository $combinationRepository;

    private MyvetshopCliniqueRepository $myvetshopCliniqueRepository;

    protected function getCustomer(RecommandationProduct $recommandationProduct): \Customer
    {
        return new \Customer($recommandationProduct->recommandation->idCustomer);
    }

    public function __construct(
        CombinationRepository $combinationRepository,
        MyvetshopCliniqueRepository $myvetshopCliniqueRepository
    ) {
        $this->combinationRepository = $combinationRepository;
        $this->myvetshopCliniqueRepository = $myvetshopCliniqueRepository;
    }

    /**
     * Trouve la meilleure Combination d'un Product.
     *
     * La combination doit être en stock.
     * Le sac s'approche au plus près d'1 mois de croquettes
     *
     * @return \Combination|null
     */
    public function findBestCombination(RecommandationProduct $recommandationProduct, \Product $product): ?\Combination
    {
        $clinique = $this->myvetshopCliniqueRepository->findByGroupId(
            $this->getCustomer($recommandationProduct)->id_default_group
        );

        if (!$clinique) {
            return null;
        }

        /** @var list<array{combination: \Combination, diff: int}> $combinations */
        $combinations = \array_reduce(
            $this->combinationRepository->findByProductInStock($product, $clinique),
            fn (array $carry, \Combination $combination) => \array_merge(
                $carry,
                [
                    $this->getCombinationWithWeight(
                        $combination,
                        $recommandationProduct
                    ),
                ],
            ),
            []
        );

        \usort(
            $combinations,
            function (array $a, array $b) {
                return $a['diff'] - $b['diff'];
            }
        );

        return $combinations[0]['combination'] ?? null;
    }

    /**
     * @return array{combination: \Combination, diff: int}
     */
    public function getCombinationWithWeight(
        \Combination $combination,
        RecommandationProduct $recommandationProduct
    ): array {
        \assert(\property_exists($combination, 'net_weight'));

        // Différence entre le poids net du paquet (en g) et 30 jours de croquettes (en g)
        return [
            'combination' => $combination,
            'diff' => (int) \abs(
                \floor($combination->net_weight * 1000) - (($recommandationProduct->quantity ?? 0) * 30)
            ),
        ];
    }
}
