<?php

declare(strict_types=1);

require_once __DIR__ . \DIRECTORY_SEPARATOR . 'ExportProduct.php';
require_once __DIR__ . \DIRECTORY_SEPARATOR . 'Clinique.php';
require_once __DIR__ . \DIRECTORY_SEPARATOR . '..' . \DIRECTORY_SEPARATOR . 'Service' . \DIRECTORY_SEPARATOR . 'CsvExporter.php';
require_once __DIR__ . \DIRECTORY_SEPARATOR . '..' . \DIRECTORY_SEPARATOR . 'Service' . \DIRECTORY_SEPARATOR . 'ExportAppVeto' . \DIRECTORY_SEPARATOR . 'ExportGenerator.php';
require_once __DIR__ . \DIRECTORY_SEPARATOR . '..' . \DIRECTORY_SEPARATOR . 'Service' . \DIRECTORY_SEPARATOR . 'ExportAppVeto' . \DIRECTORY_SEPARATOR . 'ExportSender.php';
require_once __DIR__ . \DIRECTORY_SEPARATOR . '..' . \DIRECTORY_SEPARATOR . 'Service' . \DIRECTORY_SEPARATOR . 'RecommandationManagerApi' . \DIRECTORY_SEPARATOR . 'RecommandationController.php';

class WebserviceSpecificManagementRecommandations implements WebserviceSpecificManagementInterface
{
    /**
     * @var WebserviceOutputBuilderCore|null
     */
    protected $objOutput;

    /**
     * @var mixed
     */
    protected $output;

    /** @var WebserviceRequestCore|null */
    protected $wsObject;

    /**
     * @var int
     */
    private $idEmployee;

    /**
     * @var array<string, mixed>|null
     */
    private $requestBody = [];

    /**
     * @var int|null
     */
    private $statusCodeResponse = null;

    public function setObjectOutput(WebserviceOutputBuilderCore $obj): ?WebserviceSpecificManagementInterface
    {
        $this->objOutput = $obj;

        return $this;
    }

    public function getObjectOutput(): ?WebserviceOutputBuilderCore
    {
        return $this->objOutput;
    }

    public function setWsObject(WebserviceRequestCore $obj): ?WebserviceSpecificManagementInterface
    {
        $this->wsObject = $obj;

        return $this;
    }

    public function getWsObject(): ?WebserviceRequestCore
    {
        return $this->wsObject;
    }

    public function manage(): void
    {
        $ret = [];
        try {
            /** @var WebserviceRequestCore $wsObject */
            $wsObject = $this->getWsObject();
            $this->idEmployee = method_exists($wsObject, 'getIdEmployee') ? $wsObject->getIdEmployee() : 0;

            switch ($_SERVER['REQUEST_METHOD']) {
                case 'GET':
                    if (
                        isset($this->wsObject->urlSegment[0], $this->wsObject->urlSegment[1], $this->wsObject->urlSegment[2], $this->wsObject->urlSegment[3])
                        && 'recommandations' === $this->wsObject->urlSegment[0]
                        && 'validity' === $this->wsObject->urlSegment[2]
                    ) {
                        // /modules/myvetshopclinique/api/recommandations/<code>/validity/<customer_id>?access_token=
                        // Vérification que le code reco est valide pour un client donné
                        $customerId = (int) $this->wsObject->urlSegment[3];
                        $ret = $this->checkCodeReco($this->wsObject->urlSegment[1], $customerId);
                    } elseif (
                        isset($this->wsObject->urlSegment[0], $this->wsObject->urlSegment[1], $this->wsObject->urlSegment[2])
                        && 'recommandations' === $this->wsObject->urlSegment[0]
                        && 'pdf' === $this->wsObject->urlSegment[2]
                    ) {
                        // /modules/myvetshopclinique/api/recommandations/<id>/pdf?access_token=
                        // PDF de la reco
                        $this->pdf((int) $this->wsObject->urlSegment[1]);
                    } elseif (
                        isset($this->wsObject->urlSegment[0], $this->wsObject->urlSegment[1])
                        && 'recommandations' === $this->wsObject->urlSegment[0]
                    ) {
                        // /modules/myvetshopclinique/api/recommandations/<id>?access_token=
                        // Récupérer reco par son id
                        $ret = $this->getRecoById((int) $this->wsObject->urlSegment[1]); // Récupération d'un recommandation
                    } elseif (
                        // Listing des recommandations
                        // /modules/myvetshopclinique/api/recommandations?access_token=
                        isset($this->wsObject->urlSegment[0])
                        && 'recommandations' === $this->wsObject->urlSegment[0]
                    ) {
                        $filters = Tools::getValue('filter');
                        if (is_array($filters) && isset($filters['id_customer'])) {
                            // TODO : Implémenter des filtres plus complexes (ou revoir carrément tout ce fichier pour voir si PrestaShop ne peut pas gérer ça tout seul)
                            $idCustomer = (int) $filters['id_customer'];

                            $ret = $this->listRecoByCustomer($idCustomer);
                        }
                    }

                    break;

                case 'POST':      // Import reco
                    $this->requestBody = $this->extractBodyRequest();

                    if (isset($this->requestBody['code_reco'], $this->requestBody['id_animal'], $this->requestBody['id_customer'])) {
                        $ret = $this->importReco();
                    }

                    break;

                case 'PUT':     // Maj reco
                    if (isset($this->wsObject->urlSegment[1])) {
                        $this->requestBody = $this->extractBodyRequest();
                        if (isset($this->requestBody['id_animal'])) {
                            $ret = $this->updateReco((int) $this->wsObject->urlSegment[1]);
                        }
                    }
                    break;

                case 'DELETE':    // Suppression reco
                    // /modules/myvetshopclinique/api/recommandations/<id>?access_token=
                    if (isset($this->wsObject->urlSegment[1])) {
                        $ret = $this->deleteReco((int) $this->wsObject->urlSegment[1]);
                    }

                    break;
            }

            echo json_encode($ret, \JSON_PRETTY_PRINT);
            exit;
        } catch (Exception $exception) {
            header('Content-Type: application/json');
            $this->statusCodeResponse ? http_response_code($this->statusCodeResponse) : http_response_code(500);
            echo json_encode(['error' => $exception->getMessage()]);
            exit;
        }
    }

    /**
     * @return array<string, mixed>
     *
     * @throws Exception
     */
    private function deleteReco(int $idReco): array
    {
        $recommandation = new Recommandation($idReco);

        if (!$recommandation->id) {
            $this->statusCodeResponse = 404;
            throw new Exception('La recommandation n\'existe pas');
        }

        $customer = new Customer($recommandation->id_customer);

        \assert(\method_exists($customer, 'checkGroup'));

        if (!$customer->checkGroup($this->idEmployee)) {
            $this->statusCodeResponse = 401;
            throw new Exception('Le client n\'appartient pas à la clinique');
        }

        $recommandationManagerApi = new RecommandationController($customer);

        return $recommandationManagerApi->actionCricCrocDelete($recommandation->id);
    }

    /**
     * @return array<string, mixed>
     *
     * @throws Exception
     */
    private function updateReco(int $idReco)
    {
        $recommandation = new Recommandation($idReco);
        if (!$recommandation->id) {
            $this->statusCodeResponse = 404;
            throw new Exception('La recommandation n\'existe pas');
        }

        $customer = new Customer($recommandation->id_customer);

        \assert(\method_exists($customer, 'checkGroup'));

        if (!$customer->checkGroup($this->idEmployee)) {
            $this->statusCodeResponse = 401;
            throw new Exception('Le client n\'appartient pas à la clinique');
        }

        $recommandationManagerApi = new RecommandationController($customer);

        return $recommandationManagerApi->actionCricCrocUpdate(
            (int) $recommandation->id,
            \intval($this->requestBody['id_animal'] ?? 0)
        );
    }

    /**
     * @return array<string, mixed>
     *
     * @throws Exception
     */
    private function importReco()
    {
        $customer = new Customer(\intval($this->requestBody['id_customer'] ?? 0));

        if (!$customer->id) {
            $this->statusCodeResponse = 404;
            throw new Exception('Le client n\'existe pas');
        }

        \assert(\method_exists($customer, 'checkGroup'));

        if (!$customer->checkGroup($this->idEmployee)) {
            $this->statusCodeResponse = 401;
            throw new Exception('Le client n\'appartient pas à la clinique');
        }

        // TODO : Inutile à supprimer ?
        if ('_new' !== \strval($this->requestBody['id_animal'] ?? '')) {
            $animal = new Animal(\intval($this->requestBody['id_animal'] ?? 0));

            if (!$animal->id || $animal->deleted) {
                $this->statusCodeResponse = 404;
                throw new Exception('L\'animal n\'existe pas');
            }
            if ($animal->id_customer != $customer->id) {
                $this->statusCodeResponse = 401;
                throw new Exception('L\'animal n\'appartient pas au client');
            }
        }

        $recommandationManagerApi = new RecommandationController($customer);

        return $recommandationManagerApi->actionCricCrocImport(
            \trim(\strtoupper(\strval($this->requestBody['code_reco'] ?? ''))),
            \strval($this->requestBody['id_animal'] ?? '') // string car peut être '_new'
        );
    }

    /**
     * @return array<string, mixed>
     *
     * @throws Exception
     */
    private function getRecoById(int $recoId): array
    {
        $recommandation = new Recommandation($recoId);

        if (!$recommandation->id || $recommandation->deleted) {
            $this->statusCodeResponse = 404;
            throw new Exception('La recommandation n\'existe pas');
        }

        $customer = new Customer($recommandation->id_customer);

        \assert(\method_exists($customer, 'checkGroup'));

        if (!$customer->checkGroup($this->idEmployee)) {
            $this->statusCodeResponse = 401;
            throw new Exception('La recommandation n\'appartient pas à un client de la clinique');
        }

        $recommandationManagerApi = new RecommandationController($customer);

        return $recommandationManagerApi->actionCricCrocGetRecoById($recommandation->id);
    }

    /**
     * @return array<string, mixed>
     *
     * @throws Exception
     */
    private function checkCodeReco(string $codeReco, ?int $customerId): array
    {
        $customer = new Customer($customerId);

        if (!$customer->id) {
            $this->statusCodeResponse = 404;
            throw new Exception('Le client n\'existe pas');
        }

        \assert(\method_exists($customer, 'checkGroup'));

        if (!$customer->checkGroup($this->idEmployee)) {
            $this->statusCodeResponse = 401;
            throw new Exception('Le client n\'appartient pas à la clinique');
        }

        $recommandationManagerApi = new RecommandationController($customer);

        return $recommandationManagerApi->actionCricCrocCheckCodeReco($codeReco);
    }

    /**
     * @return array<string, mixed>
     *
     * @throws Exception
     */
    private function listRecoByCustomer(int $idCustomer): array
    {
        $customer = new Customer($idCustomer);
        if (!$customer->id) {
            $this->statusCodeResponse = 404;
            throw new Exception('Le client n\'existe pas');
        }

        \assert(\method_exists($customer, 'checkGroup'));

        if (!$customer->checkGroup($this->idEmployee)) {
            $this->statusCodeResponse = 401;
            throw new Exception('Le client n\'appartient pas à la clinique');
        }

        $recommandationManagerApi = new RecommandationController($customer);

        return $recommandationManagerApi->actionCricCrocList();
    }

    /**
     * @throws Exception
     */
    private function pdf(int $idReco): void
    {
        $recommandation = new Recommandation($idReco);

        if (!$recommandation->id) {
            $this->statusCodeResponse = 404;
            throw new Exception('La recommandation n\'existe pas');
        }

        $customer = new Customer($recommandation->id_customer);

        \assert(\method_exists($customer, 'checkGroup'));

        if (!$customer->checkGroup($this->idEmployee)) {
            $this->statusCodeResponse = 401;
            throw new Exception('Le client n\'appartient pas à la clinique');
        }

        $recommandationManagerApi = new RecommandationController($customer);
        $recommandationManagerApi->actionRecommandationOpenPdf($recommandation->id);
    }

    /**
     * @return array<string, mixed>
     *
     * @throws Exception
     */
    private function extractBodyRequest(): array
    {
        $json = \file_get_contents('php://input');

        if (!$json) {
            throw new Exception('Une erreur s\'est produite lors de l\'extraction du contenu de la requête');
        }

        $parsedJson = \json_decode($json, true);
        if (!\is_array($parsedJson)) {
            throw new Exception('Une erreur s\'est produite lors de l\'extraction du contenu de la requête');
        }

        return $parsedJson;
    }

    /**
     * This must be return an array with specific values as WebserviceRequest expects.
     *
     * @return array<mixed>|string
     */
    public function getContent()
    {
        if (!$this->objOutput) {
            return [];
        }

        return $this->objOutput->getObjectRender()->overrideContent($this->output);
    }
}
