<?php

/*
 * @author TRYDEA - 2024
 */

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

use Doctrine\Common\Collections\Collection;
use Mobile\Device\Entity\Block;
use Mobile\Device\Entity\Device;
use Mobile\Device\Entity\EntryNote;
use Mobile\Device\Entity\OutExperimentationZone;
use Mobile\Device\Entity\Protocol;
use Webapp\FileManagement\Dto\Mobile\AnnotationDto;
use Webapp\FileManagement\Entity\RequestFile;
use Webapp\FileManagement\Exception\ParsingException;
use Webapp\FileManagement\Service\XmlUtils\Normalizer\AbstractXmlNormalizer;
use Webapp\FileManagement\Service\XmlUtils\Normalizer\XmlExportConfig;
use Webapp\FileManagement\Service\XmlUtils\Normalizer\XmlImportConfig;

/**
 * @template-extends AbstractXmlNormalizer<Device, DeviceXmlDto>
 *
 * @psalm-type DeviceXmlDto = array{
 *      "@dateCreation": ?\DateTime,
 *      "@dateValidation": ?\DateTime,
 *      "@nom": ?string,
 *      "@puSurfacique": ?bool,
 *      blocs: Collection<int, Block>,
 *      notes: Collection<int, EntryNote>,
 *      protocoles: ?Protocol,
 *      zheAvecEpaisseurs: Collection<int, OutExperimentationZone>
 * }
 */
class DeviceNormalizer extends AbstractXmlNormalizer
{
    protected const ATTR_NOM = '@nom';
    protected const ATTR_DATE_CREATION = '@dateCreation';
    protected const ATTR_DATE_VALIDATION = '@dateValidation';
    protected const ATTR_PU_SURFACIQUE = '@puSurfacique';
    protected const TAG_PROTOCOLES = 'protocoles';
    protected const TAG_BLOCS = 'blocs';
    protected const TAG_ZHE_AVEC_EPAISSEURS = 'zheAvecEpaisseurs';
    protected const TAG_NOTES = 'notes';
    protected const ATTR_SOURCE = '@source';
    protected const ATTR_ETAT = '@etat';
    protected const TAG_METADONNEES = 'metadonnees';
    protected const TAG_ANOMALIES = 'anomalies';

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

    protected function extractData($object, array $context): array
    {
        self::getWriterHelper($context)->addSessionAnnotations(AnnotationDto::fromCollection($object->getAnnotations(), $object));

        return [
            self::ATTR_NOM => $object->getName(),
            self::ATTR_DATE_CREATION => $object->getCreationDate(),
            self::ATTR_SOURCE => $object->getProtocol()->getName(),
            self::ATTR_ETAT => 'nonDeverrouillable',
            self::ATTR_DATE_VALIDATION => $object->getValidationDate(),
            self::TAG_PROTOCOLES => new XmlExportConfig($object->getProtocol(), null, XmlExportConfig::NONE),
            self::TAG_BLOCS => $object->getBlocks(),
            self::TAG_ZHE_AVEC_EPAISSEURS => $object->getOutExperimentationZones(),
            self::TAG_ANOMALIES => self::getWriterHelper($context)->getAnomalies(),
            self::TAG_NOTES => $object->getNotes(),
        ];
    }

    protected function validateImportData($data, array $context): void
    {
        if (!isset($data[self::TAG_PROTOCOLES])) {
            throw new ParsingException('', RequestFile::ERROR_NO_PROTOCOL);
        }
    }

    protected function getImportDataConfig(array $context): array
    {
        return [
            self::ATTR_NOM => 'string',
            self::ATTR_DATE_CREATION => \DateTime::class,
            self::ATTR_DATE_VALIDATION => \DateTime::class,
            self::ATTR_PU_SURFACIQUE => 'bool',
            self::TAG_PROTOCOLES => XmlImportConfig::value(Protocol::class),
            self::TAG_BLOCS => XmlImportConfig::collection(Block::class),
            self::TAG_ZHE_AVEC_EPAISSEURS => XmlImportConfig::collection(OutExperimentationZone::class),
            self::TAG_NOTES => XmlImportConfig::collection(EntryNote::class),
        ];
    }

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

    protected function completeImportedObject($object, $data, ?string $format, array $context): Device
    {
        $object
            ->setCreationDate($data[self::ATTR_DATE_CREATION])
            ->setValidationDate($data[self::ATTR_DATE_VALIDATION])
            ->setIndividualPU(!($data[self::ATTR_PU_SURFACIQUE] ?? false))
            ->setProtocol($data[self::TAG_PROTOCOLES])
            ->setBlocks($data[self::TAG_BLOCS])
            ->setOutExperimentationZones($data[self::TAG_ZHE_AVEC_EPAISSEURS])
            ->setNotes($data[self::TAG_NOTES])
            ->setName($data[self::ATTR_NOM] ?? '0');

        return $object;
    }
}
