<?php

namespace App\Dto\Output;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\Client;
use App\Entity\Partition;
use Symfony\Component\Serializer\Annotation\Groups;

#[Get(shortName: 'Client')]
final class ClientOutput extends AbstractOutput
{
    CONST string TYPE = 'client';

    #[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])]
    public string $name;

    #[Groups(['client:read', 'organizational-unit:read'])]
    public string $type = self::TYPE;

    #[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])]
    public ?string $ip = '';

    #[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])]
    public ?string $mac = '';

    #[Groups(['client:read'])]
    public ?string $firmwareType = '';

    #[Groups(['client:read', 'organizational-unit:read', 'trace:read'])]
    public ?string $serialNumber = '';

    #[Groups(['client:read'])]
    public ?string $netiface = '';

    #[Groups(['client:read'])]
    public ?string $netDriver = '';

    #[Groups(['client:read'])]
    #[ApiProperty(readableLink: true)]
    public ?OrganizationalUnitOutput $organizationalUnit = null;

    #[Groups(['client:read'])]
    public array $partitions = [];

    #[Groups(['client:read'])]
    public ?MenuOutput $menu = null;

    #[Groups(['client:read'])]
    #[ApiProperty(readableLink: true )]
    public ?HardwareProfileOutput $hardwareProfile = null;

    #[Groups(['client:read'])]
    #[ApiProperty(readableLink: true )]
    public ?ImageRepositoryOutput $repository = null;

    #[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])]
    #[ApiProperty(readableLink: true )]
    public ?PxeTemplateOutput $pxeTemplate = null;

    #[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])]
    #[ApiProperty(readableLink: true )]
    public ?OgLiveOutput $ogLive = null;

    #[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])]
    public ?string $subnet = null;

    #[Groups(['client:read', 'organizational-unit:read'])]
    public ?array $position = ['x' => 0, 'y' => 0];

    #[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])]
    public ?string $status = '';

    #[Groups(['client:read'])]
    public \DateTime $createdAt;

    #[Groups(['client:read'])]
    public ?string $createdBy = null;

    #[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])]
    public ?bool $maintenance = false;

    #[Groups(['client:read'])]
    public ?bool $pxeSync = false;

    public function __construct(Client $client)
    {
        parent::__construct($client);

        $this->name = $client->getName();
        $this->serialNumber = $client->getSerialNumber();
        $this->mac = $client->getMac();
        $this->ip = $client->getIp();
        $this->netiface = $client->getNetiface();
        $this->netDriver = $client->getNetDriver();
        $this->firmwareType = $client->getFirmwareType();

        if ($client->getOrganizationalUnit()) {
            $this->organizationalUnit = new OrganizationalUnitOutput($client->getOrganizationalUnit());
        }

        $this->partitions = $client->getPartitions()->map(
            fn(Partition $partition) => new PartitionOutput($partition)
        )->toArray();

        $this->menu = $client->getMenu() ? new MenuOutput($client->getMenu()) : null;
        $this->position = $client->getPosition();

        $repository = $client->getRepository()
            ?? $client->getOrganizationalUnit()?->getNetworkSettings()?->getRepository();

        $this->repository = $repository ? new ImageRepositoryOutput($repository) : null;

        $ogLive = $client->getOgLive()
            ?? $client->getOrganizationalUnit()?->getNetworkSettings()?->getOgLive();

        $this->ogLive = $ogLive ? new OgLiveOutput($ogLive) : null;

        $template = $client->getTemplate()
            ?? $client->getOrganizationalUnit()?->getNetworkSettings()?->getPxeTemplate();

        $this->pxeTemplate = $template ? new PxeTemplateOutput($template) : null;

        $this->hardwareProfile = $client->getHardwareProfile() ? new HardwareProfileOutput($client->getHardwareProfile()) : null;

        if ($client->getSubnet()){
            $this->subnet = $client->getSubnet()?->getIpAddress().'/'
                . $this->convertMaskToCIDR($client->getSubnet() ? $client->getSubnet()->getNetmask() : $client->getOrganizationalUnit()->getNetworkSettings()->getNetmask());
        }

        $this->status = $client->getStatus();
        $this->createdAt = $client->getCreatedAt();
        $this->createdBy = $client->getCreatedBy();
        $this->maintenance = $client->isMaintenance();
        $this->pxeSync = $client->isPxeSync();
    }

    public function convertMaskToCIDR($mask): int
    {
        $bits = 0;
        $mask = explode(".", $mask);

        foreach ($mask as $oct)
            $bits += strlen(str_replace("0", "", decbin($oct)));

        return $bits;
    }
}