<?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', 'hardware-profile:read'])]
    #[ApiProperty(
        description: 'El nombre del cliente',
        example: 'PC-Aula-01'
    )]
    public string $name;

    #[Groups(['client:read', 'organizational-unit:read'])]
    #[ApiProperty(
        description: 'El tipo de entidad',
        example: 'client'
    )]
    public string $type = self::TYPE;

    #[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read', 'hardware-profile:read'])]
    #[ApiProperty(
        description: 'La dirección IP del cliente',
        example: '192.168.1.100'
    )]
    public ?string $ip = '';

    #[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read', 'hardware-profile:read'])]
    #[ApiProperty(
        description: 'La dirección MAC del cliente',
        example: '00:1A:2B:3C:4D:5E'
    )]
    public ?string $mac = '';

    #[Groups(['client:read'])]
    #[ApiProperty(
        description: 'El tipo de firmware (BIOS/UEFI)',
        example: 'UEFI'
    )]
    public ?string $firmwareType = '';

    #[Groups(['client:read', 'organizational-unit:read', 'trace:read'])]
    #[ApiProperty(
        description: 'El número de serie del cliente',
        example: 'SN123456789'
    )]
    public ?string $serialNumber = '';

    #[Groups(['client:read'])]
    #[ApiProperty(
        description: 'La interfaz de red',
        example: 'eth0'
    )]
    public ?string $netiface = '';

    #[Groups(['client:read'])]
    #[ApiProperty(
        description: 'El controlador de red',
        example: 'e1000'
    )]
    public ?string $netDriver = '';

    #[Groups(['client:read'])]
    #[ApiProperty(
        description: 'La unidad organizativa a la que pertenece el cliente',
        readableLink: true
    )]
    public ?OrganizationalUnitOutput $organizationalUnit = null;

    #[Groups(['client:read'])]
    #[ApiProperty(
        description: 'Las particiones del disco del cliente',
        example: []
    )]
    public array $partitions = [];

    #[Groups(['client:read'])]
    #[ApiProperty(
        description: 'El menú de arranque asignado al cliente',
        example: null
    )]
    public ?MenuOutput $menu = null;

    #[Groups(['client:read'])]
    #[ApiProperty(
        description: 'El repositorio de imágenes asignado al cliente',
        readableLink: true
    )]
    public ?ImageRepositoryOutput $repository = null;

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

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

    #[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])]
    #[ApiProperty(
        description: 'La subred del cliente en formato CIDR',
        example: '192.168.1.0/24'
    )]
    public ?string $subnet = null;

    #[Groups(['client:read', 'organizational-unit:read'])]
    #[ApiProperty(
        description: 'La posición del cliente en la interfaz gráfica',
        example: ['x' => 100, 'y' => 200]
    )]
    public ?array $position = ['x' => 0, 'y' => 0];

    #[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])]
    #[ApiProperty(
        description: 'El estado actual del cliente',
        example: 'online'
    )]
    public ?string $status = '';

    #[Groups(['client:read'])]
    #[ApiProperty(
        description: 'Fecha de creación del cliente',
        example: '2024-01-15T10:30:00+00:00'
    )]
    public \DateTime $createdAt;

    #[Groups(['client:read'])]
    #[ApiProperty(
        description: 'Usuario que creó este registro',
        example: 'admin'
    )]
    public ?string $createdBy = null;

    #[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])]
    #[ApiProperty(
        description: 'Indica si el cliente está en modo mantenimiento',
        example: false
    )]
    public ?bool $maintenance = false;

    #[Groups(['client:read'])]
    #[ApiProperty(
        description: 'Indica si la configuración PXE está sincronizada',
        example: true
    )]
    public ?bool $pxeSync = false;

    #[Groups(['client:read'])]
    #[ApiProperty(
        description: 'La resolución del cliente',
        example: '1920x1080'
    )]
    public ?string $resolution = null;

    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;

        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();
        $this->resolution = $client->getResolution();
    }

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

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

        return $bits;
    }
}