<?php

declare(strict_types=1);

namespace Myvetshop\Module\Clinique\Handler;

use Animal;
use Myvetshop\Module\Clinique\Api\CricCrocApi;
use Recommandation;
use Symfony\Component\Translation\TranslatorInterface;

class RecommandationHandler
{
    private \Customer $customer;

    private TranslatorInterface $translator;

    private CricCrocApi $api;

    public function __construct(\Customer $customer, TranslatorInterface $translator)
    {
        $this->customer = $customer;
        $this->translator = $translator;
        $this->api = new CricCrocApi();
    }

    /**
     * @return array{
     *    code: string,
     *    petname: string,
     *    race: string,
     *    act: string,
     *    age: string,
     *    date: string,
     *    esp: string,
     *    sex: int,
     *    stadePhysio: string,
     *    patho: string,
     *    actualw: float,
     *    idealw: float,
     *    be: int,
     *    nbrAliment: int,
     *    dob: string,
     *    productIDmvs1: int|null,
     *    productIDmvs2: int|null,
     *    productIDmvs3: int|null,
     *    qteAliment1: int|null,
     *    qteAliment2: int|null,
     *    qteAliment3: int|null,
     *    transition12: int|null,
     *    transition23: int|null,
     *    products: array<int, array{entity: \Product, quantity: int, months: int}>
     * }
     *
     * @throws \PrestaShopDatabaseException
     * @throws \PrestaShopException
     */
    public function getByCode(string $code): array
    {
        $context = \Context::getContext();
        \assert(null !== $context);

        $code = \trim(\strtoupper($code));

        if (empty($code)) {
            throw new \Exception('Le code fourni est invalide');
        }

        if (\Recommandation::codeExist($code)) {
            throw new \Exception('Le code fourni a déjà été importé');
        }

        $data = $this->api->getRecommandationByCode($code);

        $clinique = \Clinique::getByCodePrivilege($data['code']);

        if ($this->customer->isLogged() && $clinique && !$clinique->hasCustomer($this->customer->id)) {
            throw new \Exception('Le code fourni n\'est pas reconnu');
        }

        $products = [];

        $i = 1;

        $productKey = 'productIDmvs' . $i;
        while (\array_key_exists($productKey, $data)) {
            \assert(\is_null($data[$productKey]) || \is_int($data[$productKey]));
            $productId = (int) $data[$productKey];
            \assert(
                \is_null($data['qteAliment' . $i] ?? null)
                || \is_int($data['qteAliment' . $i] ?? null)
            );
            $qtAliment = (int) ($data['qteAliment' . $i] ?? null);
            $transitionKey = 'transition' . $i . ($i + 1);
            if (\array_key_exists($transitionKey, $data)) {
                \assert(
                    \is_null($data[$transitionKey])
                    || \is_int($data[$transitionKey])
                );
                $transition = (int) $data[$transitionKey];
            } else {
                $transition = 0;
            }

            if ($productId) {
                $products[] = [
                    'entity' => new \Product($productId, false, $context->language->id),
                    'quantity' => $qtAliment,
                    'months' => $transition,
                ];
            }

            ++$i;
            $productKey = 'productIDmvs' . $i;
        }

        $data['products'] = $products;

        return $data;
    }

    public function import(string $code, ?int $animalId = null): \Recommandation
    {
        $code = trim(strtoupper($code));

        $data = $this->getByCode($code);

        $species = $data['esp'];
        $animal = new \Animal($animalId);

        if (null === $animalId) {
            $animal = new \Animal();
            $animal->nom = $data['petname'];
            $animal->espece = $data['esp'];
            $animal->race = $data['race'];
            $animal->id_gender = $data['sex'];
            $animal->date_naissance = $data['dob'] ?? '';
            $animal->id_customer = (int) $this->customer->id;
            $animal->add();
        }

        if (!\Validate::isLoadedObject($animal) || $animal->isDeleted()) {
            throw new \Exception('L\'animal n\'existe pas');
        }

        if (!$animal->hasCustomer($this->customer->id)) {
            throw new \Exception('L\'animal et le client ne correspondent pas');
        }

        if (!$animal->isSpecies($species)) {
            throw new \Exception('L\'espèce de la recommandation et de l\'animal ne correspondent pas.');
        }

        // On se prépare à ajouter une nouvelle recommandation. Il faut donc "supprimer" l'ancienne de l'animal
        $animalReco = $animal->getRecommandation();
        if ($animalReco) {
            $animalReco->delete();
        }

        $recommandation = new \Recommandation();
        $recommandation->id_animal = (int) $animal->id;
        $recommandation->code_reco = $code;
        $recommandation->id_customer = $this->customer->id;
        $recommandation->date_reco = $data['date'];
        $recommandation->code_clinique = $data['code'];
        $recommandation->petname = $data['petname'];
        $recommandation->espece = $data['esp'];
        $recommandation->race = $data['race'];
        $recommandation->id_gender = $data['sex'];
        $recommandation->activite = $data['act'];
        $recommandation->age = $data['age'];
        $recommandation->date_birth = $data['dob'] ?? '';
        $recommandation->stade_physio = $data['stadePhysio'];
        $recommandation->pathologie = $data['patho'];
        $recommandation->poids_actuel = $data['actualw'];
        $recommandation->poids_ideal = $data['idealw'];
        $recommandation->be = $data['be'];
        $recommandation->nbr_aliment = $data['nbrAliment'];
        $recommandation->product_id_mvs1 = (int) $data['productIDmvs1'];
        $recommandation->product_id_mvs2 = $data['productIDmvs2'];
        $recommandation->product_id_mvs3 = $data['productIDmvs3'];
        $recommandation->qte_aliment1 = (int) $data['qteAliment1'];
        $recommandation->qte_aliment2 = $data['qteAliment2'];
        $recommandation->qte_aliment3 = $data['qteAliment3'];
        $recommandation->transition12 = $data['transition12'];
        $recommandation->transition23 = $data['transition23'];

        $recommandation->save();

        $previous = null;

        foreach ($data['products'] as $row) {
            $product = $row['entity'];

            $recommandationProduct = new \MyvetshopRecommandationProduct();
            $recommandationProduct->id_recommandation = (int) $recommandation->id;
            $recommandationProduct->id_product = (int) $product->id;
            $recommandationProduct->quantity = $row['quantity'];
            $recommandationProduct->months = $row['months'];

            $recommandationProduct->save();

            if (null !== $previous) {
                $previous->id_recommandation_product_next = (int) $recommandationProduct->id;
                $previous->save();
            }

            if (!$recommandation->id_recommandation_product) {
                $recommandation->id_recommandation_product = (int) $recommandationProduct->id;
            }

            $previous = $recommandationProduct;
        }

        // On sauvegarde de nouveau la recommandation pour lui permettre de créer le nouveau cartRule
        $recommandation->update();

        return $recommandation;
    }

    public function update(int $recommandationId, int $animalId, int $recommandationProductId): void
    {
        $recommandation = new \Recommandation($recommandationId);
        $recommandationProduct = new \MyvetshopRecommandationProduct($recommandationProductId);
        $animal = new \Animal($animalId);

        if (
            !\Validate::isLoadedObject($recommandation)
            || !$recommandation->hasCustomer($this->customer->id)
        ) {
            $message = $this->translator->trans(
                'Il n\'est pas possible de modifier cette recommandation.',
                [],
                'Modules.Myvetshopclinique.Shop'
            );

            throw new \Exception($message);
        }

        if (
            !\Validate::isLoadedObject($animal)
            || !$animal->hasCustomer($this->customer->id)
            || !$animal->isSpecies($recommandation->espece)
        ) {
            $message = $this->translator->trans(
                'Il n\'est pas possible de modifier cette recommandation.',
                [],
                'Modules.Myvetshopclinique.Shop'
            );

            throw new \Exception($message);
        }

        if (
            !\Validate::isLoadedObject($recommandationProduct)
            || $recommandationProduct->id_recommandation != $recommandation->id
        ) {
            $message = $this->translator->trans(
                'Il n\'est pas possible de modifier cette recommandation.',
                [],
                'Modules.Myvetshopclinique.Shop'
            );

            throw new \Exception($message);
        }

        $recommandation->id_animal = (int) $animal->id;
        $recommandation->id_recommandation_product = (int) $recommandationProduct->id;

        $recommandation->update();

        // Maintenant on recalcule la ration de l'animal
        $recommandationProduct = new \MyvetshopRecommandationProduct($recommandation->id_recommandation_product);

        $animal->ration = (int) $recommandationProduct->quantity;

        $animal->save();
    }

    public function delete(int $recommandationId): void
    {
        $recommandation = new \Recommandation($recommandationId);

        if (!\Validate::isLoadedObject($recommandation) || !$recommandation->hasCustomer($this->customer->id)) {
            $message = $this->translator->trans(
                'Il n\'est pas possible de supprimer cette recommandation.',
                [],
                'Modules.Myvetshopclinique.Shop'
            );
            throw new \Exception($message);
        }

        $recommandation->delete();
    }

    public function getPdf(int $recommandationId): ?string
    {
        $recommandation = new \Recommandation($recommandationId);

        if (\Validate::isLoadedObject($recommandation) && $recommandation->hasCustomer((int) $this->customer->id)) {
            return $this->api->getPdf($recommandation->code_reco);
        }

        return null;
    }
}
