<?php

/*
 * @author TRYDEA - 2024
 */

namespace Webapp\FileManagement\Service\XmlUtils\Normalizer\Webapp;

use Doctrine\Common\Collections\Collection;
use Webapp\Core\Entity\Modality;
use Webapp\Core\Entity\Treatment;
use Webapp\FileManagement\Dto\Common\ReferencesDto;
use Webapp\FileManagement\Entity\RequestFile;
use Webapp\FileManagement\Exception\ParsingException;
use Webapp\FileManagement\Service\XmlUtils\Normalizer\AbstractXmlNormalizer;
use Webapp\FileManagement\Service\XmlUtils\Normalizer\XmlImportConfig;

/**
 * @template-extends AbstractXmlNormalizer<Treatment, TreatmentXmlDto>
 *
 * @psalm-type TreatmentXmlDto = array{
 *     "@nom": string,
 *     "@nomCourt": string,
 *     "@nbRepetitions": ?int,
 *     "@combinaisons": Collection<int, Modality>
 * }
 */
final class TreatmentNormalizer extends AbstractXmlNormalizer
{
    private const ATTR_NOM = '@nom';
    private const ATTR_NOM_COURT = '@nomCourt';
    private const ATTR_NB_REPETITIONS = '@nbRepetitions';
    private const ATTR_COMBINAISONS = '@combinaisons';

    protected function getClass(): string
    {
        return Treatment::class;
    }

    protected function getImportDataConfig(array $context): array
    {
        return [
            self::ATTR_NOM => 'string',
            self::ATTR_NOM_COURT => 'string',
            self::ATTR_NB_REPETITIONS => 'int',
            self::ATTR_COMBINAISONS => XmlImportConfig::references(Modality::class),
        ];
    }

    /**
     * @throws ParsingException
     */
    protected function validateImportData($data, array $context): void
    {
        if (
            !isset($data[self::ATTR_NOM])
            || !isset($data[self::ATTR_NOM_COURT])
            || !isset($data[self::ATTR_COMBINAISONS])
        ) {
            throw new ParsingException('', RequestFile::ERROR_PROTOCOL_INFO_MISSING);
        }

        $readerHelper = self::getReaderHelper($context);
        foreach (explode(' ', trim($data[self::ATTR_COMBINAISONS])) as $item) {
            if (!$readerHelper->exists($item)) {
                throw new ParsingException('', RequestFile::ERROR_MODALITY_ITEM_NOT_FOUND);
            }
            if (Modality::class !== \get_class($readerHelper->getObject($item))) {
                throw new ParsingException('', RequestFile::ERROR_MODALITY_ITEM_NOT_FOUND);
            }
        }
    }

    protected function generateImportedObject($data, array $context): Treatment
    {
        return new Treatment();
    }

    protected function completeImportedObject($object, $data, ?string $format, array $context): Treatment
    {
        $object
            ->setName($data[self::ATTR_NOM])
            ->setShortName($data[self::ATTR_NOM_COURT])
            ->setRepetitions($data[self::ATTR_NB_REPETITIONS] ?? 1)
            ->setModalities($data[self::ATTR_COMBINAISONS]);

        return $object;
    }

    protected function extractData($object, array $context): array
    {
        return [
            self::ATTR_NOM => $object->getName(),
            self::ATTR_NOM_COURT => $object->getShortName(),
            self::ATTR_NB_REPETITIONS => $object->getRepetitions(),
            self::ATTR_COMBINAISONS => new ReferencesDto($object->getModalities()),
        ];
    }
}
