<?php

namespace App\Service;

use App\Entity\Client;
use App\Entity\OperativeSystem;
use App\Entity\Partition;
use App\Model\PartitionTypes;
use App\Service\Utils\GetPartitionCodeService;
use Doctrine\ORM\EntityManagerInterface;
use Exception;

class CreatePartitionService
{
    public function __construct(
        protected EntityManagerInterface $entityManager,
        protected GetPartitionCodeService $partitionCodeService
    )
    {
    }

    public function __invoke(array $data, Client $clientEntity): void
    {
        $currentPartitions = $this->entityManager->getRepository(Partition::class)
            ->findBy(['client' => $clientEntity]);

        $receivedPartitions = [];

        $filteredCfg = array_filter($data['cfg'], function ($cfg) {
            return isset($cfg['disk'], $cfg['par'], $cfg['tam'], $cfg['uso'], $cfg['fsi']);
        });

        foreach ($data['cfg'] as $cfg) {
            if (!empty($cfg['fwt'])) {
                $clientEntity->setFirmwareType($cfg['fwt']);
                $this->entityManager->persist($clientEntity);
                break;
            }
        }

        foreach ($filteredCfg as $cfg) {
            $partitionEntity = $this->entityManager->getRepository(Partition::class)
                ->findOneBy(['client' => $clientEntity, 'diskNumber' => $cfg['disk'], 'partitionNumber' => $cfg['par']]);

            if (!$partitionEntity) {
                $partitionEntity = new Partition();
            }

            $partitionEntity->setOperativeSystem(null);

            if (isset($cfg['soi']) && $cfg['soi'] !== '') {
                if ($cfg['soi'] === 'DATA') {
                    $partitionEntity->setImage(null);
                } else {
                    $operativeSystem = $this->entityManager->getRepository(OperativeSystem::class)
                        ->findOneBy(['name' => $cfg['soi']]);

                    if (!$operativeSystem) {
                        $operativeSystem = new OperativeSystem();
                        $operativeSystem->setName($cfg['soi']);
                        $this->entityManager->persist($operativeSystem);
                    }
                    $partitionEntity->setOperativeSystem($operativeSystem);
                }
            }

            $partitionEntity->setClient($clientEntity);
            $partitionEntity->setDiskNumber($cfg['disk']);
            $partitionEntity->setPartitionNumber($cfg['par']);
            $partitionEntity->setSize($cfg['tam']);

            if (isset($cfg['cpt']) && $cfg['cpt'] !== '') {
                if ($cfg['par'] === "0") {
                    $partitionType = $this->partitionCodeService->__invoke($cfg['cpt']);
                } else {
                    $decimalValue = hexdec($cfg['cpt']);
                    $partitionType = PartitionTypes::getPartitionType($decimalValue);
                }

                if ($partitionType) {
                    $partitionEntity->setPartitionCode($partitionType['name'] ?? $partitionType);
                }
            } else {
                $partitionEntity->setPartitionCode(PartitionTypes::getPartitionType(0)['name']);
            }

            $partitionEntity->setFilesystem($cfg['fsi']);
            $partitionEntity->setMemoryUsage(((int) $cfg['uso']) * 100);
            $this->entityManager->persist($partitionEntity);

            $receivedPartitions[] = ['disk' => $cfg['disk'], 'partition' => $cfg['par']];
        }

        foreach ($currentPartitions as $currentPartition) {
            $exists = false;

            foreach ($receivedPartitions as $receivedPartition) {
                if ($currentPartition->getDiskNumber() == $receivedPartition['disk'] &&
                    $currentPartition->getPartitionNumber() == $receivedPartition['partition']) {
                    $exists = true;
                    break;
                }
            }

            if (!$exists) {
                $this->entityManager->remove($currentPartition);
            }
        }

        $this->entityManager->flush();
    }
}