<?php

/*
 * Copyright 2005 - 2025 Centreon (https://www.centreon.com/)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * For more information : contact@centreon.com
 *
 */

declare(strict_types=1);

namespace Centreon\Domain\PlatformTopology\Model;

use Centreon\Domain\PlatformTopology\Interfaces\PlatformInterface;

/**
 * Class designed to retrieve servers to be added using the wizard
 */
class PlatformRegistered implements PlatformInterface
{
    public const TYPE_CENTRAL = 'central';
    public const TYPE_POLLER = 'poller';
    public const TYPE_REMOTE = 'remote';
    public const TYPE_MAP = 'map';
    public const TYPE_MBI = 'mbi';

    /**
     * Available server types
     */
    private const AVAILABLE_TYPES = [
        self::TYPE_CENTRAL,
        self::TYPE_POLLER,
        self::TYPE_REMOTE,
        self::TYPE_MAP,
        self::TYPE_MBI,
    ];

    /** @var int|null Id of server */
    private $id;

    /** @var string|null chosen name : "virtual name" */
    private $name;

    /** @var string|null platform's real name : "physical name" */
    private $hostname;

    /** @var string|null Server type */
    private $type;

    /** @var string|null Server address */
    private $address;

    /** @var string|null Server parent address */
    private $parentAddress;

    /** @var int|null Server parent id */
    private $parentId;

    /** @var int|null Server nagios ID for Central only */
    private $serverId;

    /** @var bool */
    private $isLinkedToAnotherServer = false;

    /** @var PlatformRelation|null Communication type between topology and parent */
    private $relation;

    /**
     * @var bool define if the platform is in a pending state or is already registered
     *           By default Platform entities are not pending platforms
     */
    private $isPending = false;

    /**
     * @inheritDoc
     */
    public function getId(): ?int
    {
        return $this->id;
    }

    /**
     * @inheritDoc
     */
    public function setId(?int $id): PlatformInterface
    {
        $this->id = $id;

        return $this;
    }

    /**
     * @inheritDoc
     */
    public function getType(): ?string
    {
        return $this->type;
    }

    /**
     * @inheritDoc
     */
    public function setType(?string $type): PlatformInterface
    {
        if ($type !== null) {
            $type = strtolower($type);

            // Check if the server_type is available
            if (! in_array($type, self::AVAILABLE_TYPES)) {
                throw new \InvalidArgumentException(
                    sprintf(
                        _("The platform type of '%s'@'%s' is not consistent"),
                        $this->getName(),
                        $this->getAddress()
                    )
                );
            }
        }
        $this->type = $type;

        return $this;
    }

    /**
     * @inheritDoc
     */
    public function getName(): ?string
    {
        return $this->name;
    }

    /**
     * @inheritDoc
     */
    public function setName(?string $name): PlatformInterface
    {
        $this->name = $name;

        return $this;
    }

    /**
     * @inheritDoc
     */
    public function getHostname(): ?string
    {
        return $this->hostname;
    }

    /**
     * @inheritDoc
     */
    public function setHostname(?string $hostname): PlatformInterface
    {
        $this->hostname = $hostname;

        return $this;
    }

    /**
     * @inheritDoc
     */
    public function getAddress(): ?string
    {
        return $this->address;
    }

    /**
     * @inheritDoc
     */
    public function setAddress(?string $address): PlatformInterface
    {
        $this->address = $this->checkIpAddress($address);

        return $this;
    }

    /**
     * @inheritDoc
     */
    public function getParentAddress(): ?string
    {
        return $this->parentAddress;
    }

    /**
     * @inheritDoc
     */
    public function setParentAddress(?string $parentAddress): PlatformInterface
    {
        if ($parentAddress !== null && $this->getType() === static::TYPE_CENTRAL) {
            throw new \InvalidArgumentException(_('Cannot use parent address on a Central server type'));
        }
        $this->parentAddress = $this->checkIpAddress($parentAddress);

        return $this;
    }

    /**
     * @inheritDoc
     */
    public function getParentId(): ?int
    {
        return $this->parentId;
    }

    /**
     * @inheritDoc
     */
    public function setParentId(?int $parentId): PlatformInterface
    {
        if ($parentId !== null && $this->getType() === static::TYPE_CENTRAL) {
            throw new \InvalidArgumentException(_('Cannot set parent id to a central server'));
        }
        $this->parentId = $parentId;

        return $this;
    }

    /**
     * @inheritDoc
     */
    public function getServerId(): ?int
    {
        return $this->serverId;
    }

    /**
     * @inheritDoc
     */
    public function setServerId(?int $serverId): PlatformInterface
    {
        $this->serverId = $serverId;

        return $this;
    }

    /**
     * @inheritDoc
     */
    public function isLinkedToAnotherServer(): bool
    {
        return $this->isLinkedToAnotherServer;
    }

    /**
     * @inheritDoc
     */
    public function setLinkedToAnotherServer(bool $isLinked): PlatformInterface
    {
        $this->isLinkedToAnotherServer = $isLinked;

        return $this;
    }

    /**
     * @inheritDoc
     */
    public function getRelation(): ?PlatformRelation
    {
        return $this->relation;
    }

    /**
     * @inheritDoc
     */
    public function setRelation(?string $relationType): PlatformInterface
    {
        if ($this->getParentId() !== null) {
            $this->relation = (new PlatformRelation())
                ->setSource($this->getId())
                ->setRelation($relationType)
                ->setTarget($this->getParentId());
        }

        return $this;
    }

    /**
     * @inheritDoc
     */
    public function isPending(): bool
    {
        return $this->isPending;
    }

    /**
     * @inheritDoc
     */
    public function setPending(bool $isPending): PlatformInterface
    {
        $this->isPending = $isPending;

        return $this;
    }

    /**
     * Validate address consistency
     *
     * @param string|null $address the address to be tested
     * @return string|null
     */
    private function checkIpAddress(?string $address): ?string
    {
        if (
            $address !== null
            && ! filter_var($address, FILTER_VALIDATE_IP)
            && ! filter_var($address, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)
        ) {
            throw new \InvalidArgumentException(
                sprintf(
                    _("The address '%s' of '%s' is not valid or not resolvable"),
                    $address,
                    $this->getName()
                )
            );
        }

        return $address;
    }
}
