<?php

declare(strict_types=1);

require_once __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'classes' . DIRECTORY_SEPARATOR . 'Recommandation.php';
require_once __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'classes' . DIRECTORY_SEPARATOR . 'Animal.php';
require_once __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'class' . DIRECTORY_SEPARATOR . 'CricCrocApi.php';

/**
 * Cette classe permet de gérer les recommandations depuis l'app client ou l'app veto
 * Elle se comporte comme un Controller et retourne les informations prêtes à serializer en JSON
 */
class RecommandationController
{
    /**
     * @var Customer
     */
    private $customer;

    public function __construct(Customer $customer)
    {
        $this->customer = $customer;
    }

    /**
     * @return array<string, mixed>
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    public function actionCricCrocImport(string $codeReco, string $idAnimal): array
    {
        $reco = $this->actionCricCrocGetReco($codeReco);

        if (!$reco instanceof Recommandation) {
            http_response_code(500);

            return [
                'error' => 'Erreur lors de la récupération de la recommandation',
            ];
        }

        $animal = null;

        if (!$idAnimal) {
            header('HTTP/1.0 400 Bad Request');

            return [
                'error' => "L'id de l'animal est invalide",
            ];
        }

        if ('_new' !== $idAnimal) {
            $animal = new Animal((int) $idAnimal);
            if (!$animal->id || $animal->deleted) {
                header('HTTP/1.0 400 Bad Request');

                return [
                    'error' => "L'animal n'existe pas",
                ];
            }

            if ($animal->id_customer != $this->customer->id) {
                header('HTTP/1.0 400 Bad Request');

                return [
                    'error' => "L'animal et le client ne correspondent pas",
                ];
            }

            if ($animal->espece !== $reco->espece) {
                header('HTTP/1.0 400 Bad Request');

                return [
                    'error' => "L\'espèce de la recommandation et de l\'animal ne correspondent pas.",
                ];
            }
        }
        // si l'animal est null il faut le creer à partir de la reco
        if (is_null($animal)) {
            $animal = Animal::hydrateAnimalWithReco($reco);
            $animal->id_customer = $this->customer->id;
            $animal->save();
        } else {
            // Ajout de la reco à un animal existant
            // Suppression de l'ancienne reco si l'animal en avait deja une
            if ($animal->getReco() && isset($animal->getReco()['id_recommandation'])) {
                $oldReco = new Recommandation($animal->getReco()['id_recommandation']);
                $oldReco->deleted = true;
                $oldReco->update();
            }
        }

        $animal->setRationReco($reco);
        $animal->update();

        // Force l'association avec le client
        $reco->id_customer = $this->customer->id;
        $reco->code_reco = trim(strtoupper($codeReco));
        $reco->id_animal = $animal->id;
        $reco->save();
        $reco->createDiscountCode();

        return $this->serializeRecommandation($reco);
    }

    /**
     * @return array<string, mixed>|Recommandation
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    public function actionCricCrocGetReco(string $codeReco)
    {
        $codeReco = trim(strtoupper($codeReco));
        // Check si le client n'a pas déjà importé ce code sur son compte
        $db = Db::getInstance(false);
        $sql = 'SELECT COUNT(id_recommandation) as numberOfReco
             FROM `' . _DB_PREFIX_ . 'recommandation` `r`
             WHERE `r`.`id_customer` = ' . (int) $this->customer->id . ' AND `r`.`deleted` = 0 AND `r`.`code_reco` = "' . $db->escape($codeReco) . '"';

        $result = $db->getRow($sql);

        if (!is_array($result) || !isset($result['numberOfReco']) || $result['numberOfReco'] > 0) {
            header('HTTP/1.0 400 Bad Request');

            return [
                'error' => 'Le code fourni a déjà été importé',
            ];
        }

        if ('' == $codeReco) {
            header('HTTP/1.0 400 Bad Request');

            return [
                'error' => 'Le code fourni est invalide',
            ];
        }

        // Récupération des infos de recommandation depuis le site CricCroc
        $api = new CricCrocApi();
        try {
            $recoJson = $api->getRecoJson($codeReco);
            $reco = $api->parseRecoJson($recoJson);
            $reco->code_reco = $codeReco;
        } catch (Exception $e) {
            header('HTTP/1.0 400 Bad Request');

            return [
                'error' => "Le code fourni n'est pas reconnu",
            ];
        }

        // Check correspondance clinique client et clinique de la recommandation
        $group = new Group($this->customer->id_default_group);
        $groupName = $group->name[1];

        if (false === strpos($reco->code_clinique, $groupName)) {
            header('HTTP/1.0 400 Bad Request');

            return [
                'error' => "Le code fourni n'est pas reconnu",
            ];
        }

        return $reco;
    }

    /**
     * @return array<string, mixed>
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    public function actionCricCrocDelete(int $idReco): array
    {
        if (!$idReco) {
            header('HTTP/1.0 400 Bad Request');

            return [
                'error' => "L'identifiant de la recommandation est invalide",
            ];
        }

        $recommandation = new Recommandation((int) $idReco);

        if ($recommandation->id_customer != $this->customer->id) {
            header('HTTP/1.0 400 Bad Request');

            return [
                'error' => 'Le client ne correspond pas à la recommandation',
            ];
        }

        if (!$recommandation->id) {
            header('HTTP/1.0 400 Bad Request');

            return [
                'error' => "La recommandation n'existe pas",
            ];
        }

        $recommandation->deleted = true;
        $recommandation->update();

        return $this->serializeRecommandation($recommandation);
    }

    /**
     * @return array<string, mixed>
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    public function actionCricCrocUpdate(int $idReco, int $idAnimal, ?int $idProduct = null, ?int $ration = null): array
    {
        if (!$idReco) {
            header('HTTP/1.0 400 Bad Request');

            return [
                'error' => "L'identifiant de la recommandation est invalide",
            ];
        }

        if (!$idAnimal) {
            header('HTTP/1.0 400 Bad Request');

            return [
                'error' => "L'identifiant de l'animal est invalide",
            ];
        }

        $recommandation = new Recommandation($idReco);

        if (!$recommandation->id || $recommandation->deleted) {
            header('HTTP/1.0 400 Bad Request');

            return [
                'error' => "La recommandation n'existe pas",
            ];
        }

        $animal = new Animal($idAnimal);

        if (!$animal->id) {
            header('HTTP/1.0 400 Bad Request');

            return [
                'error' => "L'animal n'existe pas",
            ];
        }

        if ($animal->id_customer != $this->customer->id) {
            header('HTTP/1.0 400 Bad Request');

            return [
                'error' => "L'animal et le client ne correspondent pas",
            ];
        }

        if ($recommandation->id_customer != $this->customer->id) {
            header('HTTP/1.0 400 Bad Request');

            return [
                'error' => 'La recommandation et le client ne correspondent pas',
            ];
        }

        // Animal a deja une reco ? Si la reco n'est pas la meme on la supprime
        $oldReco = $animal->getReco();
        if ($oldReco && $oldReco['id_recommandation'] && $oldReco['id_recommandation'] != $recommandation->id) {
            $oldReco = new Recommandation($oldReco['id_recommandation']);
            $oldReco->deleted = true;
            $oldReco->update();
        }

        $recommandation->id_animal = $animal->id;
        $recommandation->update();

        // TODO : A voir pour supprimer ça d'ici
        if (null != $idProduct && null !== $ration) {
            $produit = new Product($idProduct);

            if (!$produit->id) {
                header('HTTP/1.0 400 Bad Request');

                return [
                    'error' => "Le produit n'existe pas",
                ];
            }

            $animal->ration = $ration;
            $animal->id_product = $produit->id;
            $animal->update();
        }

        return $this->serializeRecommandation($recommandation);
    }

    /**
     * @return array<string, mixed>
     */
    public function actionCricCrocCheckCodeReco(string $codeReco): array
    {
        $reco = $this->actionCricCrocGetReco($codeReco);

        if (!$reco instanceof Recommandation) {
            return $reco;
        }

        return $this->serializeRecommandation($reco);
    }

    /**
     * @return array<string, mixed>
     */
    public function actionCricCrocGetRecoById(int $idReco): array
    {
        $recommandation = new Recommandation($idReco);

        if (!$recommandation->id || $recommandation->deleted) {
            header('HTTP/1.0 400 Bad Request');

            return [
                'error' => 'La recommandation n\'existe pas',
            ];
        }

        if (intval($recommandation->id_customer) !== intval($this->customer->id)) {
            header('HTTP/1.0 400 Bad Request');

            return [
                'error' => 'La recommandation et le client ne correspondent pas',
            ];
        }

        return $this->serializeRecommandation($recommandation);
    }

    /**
     * @return array<string, mixed>
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    public function actionCricCrocList(): array
    {
        $db = Db::getInstance(false);

        $result = $db->executeS(
            'SELECT `r`.*
             FROM `' . _DB_PREFIX_ . 'recommandation` `r`
             WHERE `r`.`id_customer` = ' . (int) $this->customer->id . ' AND `r`.`deleted` = 0'
        );

        $recos = [];
        if (is_array($result)) {
            $recos = ObjectModel::hydrateCollection(
                Recommandation::class, $result
            );
        }

        return array_map(
            [$this, 'serializeRecommandation'],
            $recos
        );
    }

    /**
     * @return array<string, mixed>
     */
    protected function serializeRecommandation(Recommandation $reco): array
    {
        $db = Db::getInstance(false);
        $discount_code = null;
        $result = $db->getRow(
            'SELECT `rule`.code AS discount_code 
             FROM `' . _DB_PREFIX_ . 'cart_rule` `rule`
             WHERE `rule`.code = "' . $db->escape($reco->code_reco) . '"
             AND `rule`.quantity > 0
             AND `rule`.active = 1
             ');
        if ($result && is_array($result) && isset($result['discount_code'])) {
            $discount_code = $result['discount_code'];
        }

        return [
            'id' => $reco->id,
            'id_animal' => $reco->id_animal,
            'code_reco' => $reco->code_reco,
            'date_reco' => $reco->date_reco,
            'petname' => $reco->petname,
            'espece' => $reco->espece,
            'race' => $reco->race,
            'id_gender' => $reco->id_gender,
            'activite' => $reco->activite,
            'age' => $reco->age,
            'stade_physio' => $reco->stade_physio,
            'pathologie' => $reco->pathologie,
            'poids_actuel' => $reco->poids_actuel,
            'poids_ideal' => $reco->poids_ideal,
            'be' => $reco->be,
            'nbr_aliment' => $reco->nbr_aliment,
            'product_id_mvs1' => $reco->product_id_mvs1,
            'product_id_mvs2' => $reco->product_id_mvs2,
            'product_id_mvs3' => $reco->product_id_mvs3,
            'qte_aliment1' => $reco->qte_aliment1,
            'qte_aliment2' => $reco->qte_aliment2,
            'qte_aliment3' => $reco->qte_aliment3,
            'transition12' => $reco->transition12,
            'transition23' => $reco->transition23,
            'date_add' => $reco->date_add,
            'date_upd' => $reco->date_upd,
            'deleted' => $reco->deleted,
            'discount_code' => $discount_code,
        ];
    }

    /**
     * @return array<string, mixed>
     *
     * @throws PrestaShopDatabaseException
     */
    protected function serializeAnimal(Animal $animal): array
    {
        $file_name = 'a_' . md5($animal->id . 'animal');
        $photo_url = null;

        if (is_file(_PS_UPLOAD_DIR_ . $file_name . '.jpg')) {
            $photo_url = 'https://' . $_SERVER['HTTP_HOST'] . '/upload/' . $file_name . '.jpg?t=' . filemtime(_PS_UPLOAD_DIR_ . $file_name . '.jpg');
        }

        $recoArray = $this->serializeRecommandation(new Recommandation($animal->getIdRecoCricCroc()));
        $sacs = [];
        $sacsActuels = $animal->getSacsActuels();
        if (is_array($sacsActuels)) {
            /* @phpstan-ignore-next-line */
            $sacs = array_map([$this, 'serializeAnimalSac'], $sacsActuels);
        }

        return [
            'id_animal' => $animal->id,
            'espece' => $animal->espece,
            'nom' => $animal->nom,
            'race' => $animal->race,
            'id_gender' => $animal->id_gender,
            'robe' => $animal->robe,
            'date_naissance' => $animal->date_naissance,
            'ration' => $animal->ration,
            'id_product' => $animal->id_product,
            'date_add' => $animal->date_add,
            'date_upd' => $animal->date_upd,
            'sacs' => $sacs,
            'photo' => $photo_url,
            'reco' => $recoArray,
        ];
    }

    /**
     * @param array<string, mixed> $animalSac
     *
     * @return array<string, mixed>
     */
    private function serializeAnimalSac(array $animalSac): array
    {
        $cover = Product::getCover($animalSac['id_product']);

        $link = new Link();
        $animalSac['cover_url'] = 'https://' . $link->getImageLink('mobileapp', $cover['id_image'], 'home_default');

        return $animalSac;
    }

    public function actionRecommandationOpenPdf(int $idReco): void
    {
        $recomandation = new Recommandation($idReco);

        $api = new CricCrocApi();
        $pdf = $api->getPdf($recomandation->code_reco);

        header('Content-Type: application/pdf');
        header('Content-Disposition: inline; filename=Recommandation-' . $recomandation->code_reco . '.pdf;');
        echo $pdf;
        exit();
    }
}
