<?php

namespace Webapp\Core\Dto\BusinessObject;

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\OutExperimentationZone;
use Webapp\Core\Entity\Platform;
use Webapp\Core\Entity\SubBlock;
use Webapp\Core\Entity\UnitPlot;

/**
 * Class ExperimentPostTransformer
 * @package Webapp\Core\Dto\Experiment
 */
class BusinessObjectCsvTransformer 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 BusinessObjectCsvOutputDto[]
     */
    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 BusinessObjectCsvOutputDto::class === $to &&
            $context['operation_type'] === OperationType::ITEM &&
            $context['item_operation_name'] === 'export';
    }

    /**
     * @param array $output
     * @param $plotContainer
     * @param $platformName
     * @param Experiment $experiment
     * @param Block $block
     * @param SubBlock $subBlock
     * @return void
     */
    private function handleUnitPlotContainer(array &$output, $plotContainer, $platformName, $experiment, $block, $subBlock = null)
    {
        /** @var Block | SubBlock $plotContainer */
        foreach ($plotContainer->getUnitPlots() as $unitPlot) {
            $modalities = $unitPlot->getTreatment()->getModalities();
            foreach ($unitPlot->getOutExperimentationZones() as $oez) {
                $this->handleOEZ($output, $oez, $platformName, $experiment, $block, $subBlock, $unitPlot);
            }
            foreach ($unitPlot->getIndividuals() as $individual) {
                $output[] = (new BusinessObjectCsvOutputDto())
                    ->setX($individual->getX())
                    ->setY($individual->getY())
                    ->setAppeared($individual->getAppeared())
                    ->setDisapeared($individual->getDisappeared())
                    ->setDead($individual->isDead())
                    ->setId($individual->getIdentifier())
                    ->setTreatment($unitPlot->getTreatment()->getName())
                    ->setShortTreatment($unitPlot->getTreatment()->getShortName())
                    ->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)
                    ->setPlatform($platformName)
                    ->setExperiment($experiment->getName())
                    ->setExperimentGeometry($experiment->getGeometry())
                    ->setBlock(isset($block) ? $block->getNumber() : null)
                    ->setBlockGeometry(isset($block) ? $block->getGeometry() : null)
                    ->setSubBlock(isset($subBlock) ? $subBlock->getNumber() : null)
                    ->setSubBlockGeometry(isset($subBlock) ? $subBlock->getGeometry() : null)
                    ->setUp($unitPlot->getNumber())
                    ->setUpGeometry($unitPlot->getGeometry())
                    ->setIndividualGeometry($individual->getGeometry());

            }
        }
        foreach ($plotContainer->getSurfacicUnitPlots() as $surfacicUnitPlot) {
            $modalities = $surfacicUnitPlot->getTreatment()->getModalities();
            $output[] = (new BusinessObjectCsvOutputDto())
                ->setX($surfacicUnitPlot->getX())
                ->setY($surfacicUnitPlot->getY())
                ->setAppeared($surfacicUnitPlot->getAppeared())
                ->setDisapeared($surfacicUnitPlot->getDisappeared())
                ->setDead($surfacicUnitPlot->isDead())
                ->setId($surfacicUnitPlot->getIdentifier())
                ->setTreatment($surfacicUnitPlot->getTreatment()->getName())
                ->setShortTreatment($surfacicUnitPlot->getTreatment()->getShortName())
                ->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)
                ->setPlatform($platformName)
                ->setExperiment($experiment->getName())
                ->setExperimentGeometry($experiment->getGeometry())
                ->setBlock(isset($block) ? $block->getNumber() : null)
                ->setBlockGeometry(isset($block) ? $block->getGeometry() : null)
                ->setSubBlock(isset($subBlock) ? $subBlock->getNumber() : null)
                ->setSubBlockGeometry(isset($subBlock) ? $subBlock->getGeometry() : null)
                ->setUp($surfacicUnitPlot->getNumber())
                ->setUpGeometry($surfacicUnitPlot->getGeometry());
        }
    }

    /**
     * @param array $output
     * @param OutExperimentationZone $oez
     * @param $platformName
     * @param Experiment $experiment
     * @param Block $block
     * @param SubBlock $subBlock
     * @param UnitPlot $up
     */
    private function handleOez(array &$output, OutExperimentationZone $oez, $platformName, $experiment, $block = null, $subBlock = null, $up = null)
    {
        $output[] = (new BusinessObjectCsvOutputDto())
            ->setX($oez->getX())
            ->setY($oez->getY())
            ->setZHE($oez->getNature()->getNature())
            ->setPlatform($platformName)
            ->setExperiment($experiment->getName())
            ->setExperimentGeometry($experiment->getGeometry())
            ->setBlock(isset($block) ? $block->getNumber() : null)
            ->setBlockGeometry(isset($block) ? $block->getGeometry() : null)
            ->setSubBlock(isset($subBlock) ? $subBlock->getNumber() : null)
            ->setSubBlockGeometry(isset($subBlock) ? $subBlock->getGeometry() : null)
            ->setUp(isset($up) ? $up->getNumber() : null)
            ->setUpGeometry(isset($up) ? $up->getGeometry() : null);
    }

    /**
     * @param $experiment
     * @param array $output
     * @param null $platformName
     * @return void
     */
    private function handleExperiment($experiment, array &$output, $platformName = null): void
    {
        foreach ($experiment->getOutExperimentationZones() as $oez) {
            $this->handleOEZ($output, $oez, $platformName, $experiment);
        }

        foreach ($experiment->getBlocks() as $block) {
            foreach ($block->getOutExperimentationZones() as $oez) {
                $this->handleOEZ($output, $oez, $platformName, $experiment, $block);
            }
            foreach ($block->getSubBlocks() as $subBlock) {
                foreach ($subBlock->getOutExperimentationZones() as $oez) {
                    $this->handleOEZ($output, $oez, $platformName, $experiment, $block, $subBlock);
                }
                $this->handleUnitPlotContainer($output, $subBlock, $platformName, $experiment, $block, $subBlock);
            }
            $this->handleUnitPlotContainer($output, $block, $platformName, $experiment, $block);
        }
    }
}
