<?php

namespace Webapp\Core\Dto\Notes;

use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\Api\OperationType;
use ApiPlatform\Core\DataTransformer\DataTransformerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface;
use Webapp\Core\Entity\Block;
use Webapp\Core\Entity\Experiment;
use Webapp\Core\Entity\Individual;
use Webapp\Core\Entity\Platform;
use Webapp\Core\Entity\SubBlock;
use Webapp\Core\Entity\SurfacicUnitPlot;

/**
 * Class NotesCsvTransformer
 * @package Webapp\Core\Dto\Experiment
 */
class NotesCsvTransformer implements DataTransformerInterface
{

    public function __construct(IriConverterInterface $iriConverter, ContainerBagInterface $params)
    {
        $this->iriConverter = $iriConverter;
        $this->params = $params;
    }

    /**
     * @param Experiment| Platform $object
     * @param string $to
     * @param array $context
     * @return NotesCsvOutputDto[]
     */
    public function transform($object, string $to, array $context = []): array
    {
        $output = [];

        if ($object instanceof Platform) {
            $platformName = $object->getName();
            foreach ($object->getExperiments() as $experiment) {
                $this->handleExperiment($experiment, $output, $platformName);
            }
        } else {
            $this->handleExperiment($object, $output);
        }

        return $output;
    }

    public function supportsTransformation($data, string $to, array $context = []): bool
    {
        if (!$data instanceof Experiment && !$data instanceof Platform) {
            return false;
        }
        return NotesCsvOutputDto::class === $to &&
            $context['operation_type'] === OperationType::ITEM &&
            $context['item_operation_name'] === 'exportNotes';
    }

    /**
     * @param array $output
     * @param $plotContainer
     * @param $experimentName
     * @param $blockName
     * @param $subBlockName
     * @return void
     */
    private function handleUnitPlotContainer(array &$output, $plotContainer, $platformName, $experimentName, $blockName, $subBlockName = null)
    {
        /** @var Block | SubBlock $plotContainer */
        foreach ($plotContainer->getUnitPlots() as $unitPlot) {
            $unitPlotName = $unitPlot->getNumber();
            $modalities = $unitPlot->getTreatment()->getModalities();
            $this->addNotes($unitPlot, $output, $platformName, $experimentName, $blockName, $subBlockName, $unitPlotName, $unitPlot, $modalities);
            foreach ($unitPlot->getIndividuals() as $individual) {
                $this->addNotes($individual, $output, $platformName, $experimentName, $blockName, $subBlockName, $unitPlotName, $unitPlot, $modalities);
            }
        }
        foreach ($plotContainer->getSurfacicUnitPlots() as $surfacicUnitPlot) {
            $unitPlotName = $surfacicUnitPlot->getNumber();
            $modalities = $surfacicUnitPlot->getTreatment()->getModalities();
            $this->addNotes($surfacicUnitPlot, $output, $platformName, $experimentName, $blockName, $subBlockName, $unitPlotName, $surfacicUnitPlot, $modalities);
        }
    }

    /**
     * @param $experiment
     * @param array $output
     * @param null $platformName
     * @return void
     */
    private function handleExperiment($experiment, array &$output, $platformName = null): void
    {
        $experimentName = $experiment->getName();
        $this->addNotes($experiment, $output, $platformName, $experimentName);

        foreach ($experiment->getBlocks() as $block) {
            $blockName = $block->getNumber();
            $this->addNotes($block, $output, $platformName, $experimentName, $blockName);
            foreach ($block->getSubBlocks() as $subBlock) {
                $subBlockName = $subBlock->getNumber();
                $this->addNotes($subBlock, $output, $platformName, $experimentName, $blockName, $subBlockName);
                $this->handleUnitPlotContainer($output, $subBlock, $platformName, $experimentName, $blockName, $subBlockName);
            }
            $this->handleUnitPlotContainer($output, $block, $platformName, $experimentName, $blockName);
        }
    }

    private function addNotes($object, array &$output, $platformName = null, $experimentName = null, $blockName = null, $subBlockName = null, $unitPlotName = null, $unitPlot = null, $modalities = null)
    {
        foreach ($object->getNotes() as $note) {
            $csvLine = (new NotesCsvOutputDto())
                ->setNote($note->getText())
                ->setOwner($note->getCreatorLogin())
                ->setCreated($note->getCreationDate())
                ->setPlatform($platformName)
                ->setExperiment($experimentName)
                ->setBlock($blockName)
                ->setSubBlock($subBlockName)
                ->setUp($unitPlotName);
            if ($object instanceof Individual || $object instanceof SurfacicUnitPlot) {
                $csvLine
                    ->setX($object->getX())
                    ->setY($object->getY())
                    ->setAppeared($object->getAppeared())
                    ->setDisapeared($object->getDisappeared())
                    ->setDead($object->isDead())
                    ->setId($object->getIdentifier());
                if ($object instanceof Individual){
                    $csvLine->setIndividual($object->getNumber());
                }
            }
            if($unitPlot !== null){
                $csvLine
                    ->setTreatment($unitPlot->getTreatment()->getName())
                    ->setShortTreatment($unitPlot->getTreatment()->getShortName());
            }
            if($modalities !== null){
                $csvLine
                    ->setFactor1($modalities->get(0)->getValue())
                    ->setFactor1Id($modalities->get(0)->getIdentifier())
                    ->setFactor1ShortName($modalities->get(0)->getShortName())
                    ->setFactor2($modalities->containsKey(1) ? $modalities->get(1)->getValue() : null)
                    ->setFactor2Id($modalities->containsKey(1) ? $modalities->get(1)->getIdentifier() : null)
                    ->setFactor2ShortName($modalities->containsKey(1) ? $modalities->get(1)->getShortName() : null)
                    ->setFactor3($modalities->containsKey(2) ? $modalities->get(2)->getValue() : null)
                    ->setFactor3Id($modalities->containsKey(2) ? $modalities->get(2)->getIdentifier() : null)
                    ->setFactor3ShortName($modalities->containsKey(2) ? $modalities->get(2)->getShortName() : null);
            }
            $output[] = $csvLine;
        }
    }
}
