<?php
declare(strict_types=1);

namespace ROITheme\Shared\Domain\ValueObjects;

use ROITheme\Shared\Domain\Exceptions\InvalidComponentException;

/**
 * ComponentVisibility - Value Object inmutable para visibilidad de componente
 *
 * RESPONSABILIDAD: Representar y validar la visibilidad de un componente en diferentes dispositivos
 *
 * REGLAS DE NEGOCIO:
 * - Un componente puede estar habilitado o deshabilitado globalmente
 * - Un componente puede tener visibilidad específica por dispositivo (desktop, tablet, mobile)
 * - Si está deshabilitado globalmente, las visibilidades por dispositivo no importan
 * - Al menos un dispositivo debe tener visibilidad si está habilitado globalmente
 *
 * CASOS DE USO:
 * - Componente visible solo en desktop
 * - Componente visible solo en mobile
 * - Componente visible en todos los dispositivos
 * - Componente completamente deshabilitado
 *
 * USO:
 * ```php
 * // Visible en todos los dispositivos
 * $visibility = ComponentVisibility::allDevices();
 *
 * // Visible solo en desktop
 * $visibility = ComponentVisibility::desktopOnly();
 *
 * // Personalizado
 * $visibility = new ComponentVisibility(
 *     enabled: true,
 *     visibleDesktop: true,
 *     visibleTablet: true,
 *     visibleMobile: false
 * );
 * ```
 *
 * @package ROITheme\Shared\Domain\ValueObjects
 */
final readonly class ComponentVisibility
{
    /**
     * Constructor
     *
     * @param bool $enabled Componente habilitado globalmente
     * @param bool $visibleDesktop Visible en desktop
     * @param bool $visibleTablet Visible en tablet
     * @param bool $visibleMobile Visible en mobile
     * @throws InvalidComponentException
     */
    public function __construct(
        private bool $enabled,
        private bool $visibleDesktop,
        private bool $visibleTablet,
        private bool $visibleMobile
    ) {
        $this->validate();
    }

    /**
     * Verificar si está habilitado globalmente
     *
     * @return bool
     */
    public function isEnabled(): bool
    {
        return $this->enabled;
    }

    /**
     * Verificar si es visible en desktop
     *
     * @return bool
     */
    public function isVisibleOnDesktop(): bool
    {
        return $this->enabled && $this->visibleDesktop;
    }

    /**
     * Verificar si es visible en tablet
     *
     * @return bool
     */
    public function isVisibleOnTablet(): bool
    {
        return $this->enabled && $this->visibleTablet;
    }

    /**
     * Verificar si es visible en mobile
     *
     * @return bool
     */
    public function isVisibleOnMobile(): bool
    {
        return $this->enabled && $this->visibleMobile;
    }

    /**
     * Verificar si es visible en al menos un dispositivo
     *
     * @return bool
     */
    public function isVisibleOnAnyDevice(): bool
    {
        return $this->enabled && (
            $this->visibleDesktop ||
            $this->visibleTablet ||
            $this->visibleMobile
        );
    }

    /**
     * Verificar si es visible en todos los dispositivos
     *
     * @return bool
     */
    public function isVisibleOnAllDevices(): bool
    {
        return $this->enabled &&
            $this->visibleDesktop &&
            $this->visibleTablet &&
            $this->visibleMobile;
    }

    /**
     * Convertir a array
     *
     * @return array
     */
    public function toArray(): array
    {
        return [
            'enabled' => $this->enabled,
            'visible_desktop' => $this->visibleDesktop,
            'visible_tablet' => $this->visibleTablet,
            'visible_mobile' => $this->visibleMobile
        ];
    }

    /**
     * Validar reglas de negocio
     *
     * @throws InvalidComponentException
     * @return void
     */
    private function validate(): void
    {
        // Regla: Si está habilitado, al menos un dispositivo debe tener visibilidad
        if ($this->enabled && !$this->visibleDesktop && !$this->visibleTablet && !$this->visibleMobile) {
            throw new InvalidComponentException(
                'Component is enabled but not visible on any device. At least one device must be visible.'
            );
        }
    }

    /**
     * Factory: Componente deshabilitado
     *
     * @return self
     */
    public static function disabled(): self
    {
        return new self(
            enabled: false,
            visibleDesktop: false,
            visibleTablet: false,
            visibleMobile: false
        );
    }

    /**
     * Factory: Componente visible en todos los dispositivos
     *
     * @return self
     */
    public static function allDevices(): self
    {
        return new self(
            enabled: true,
            visibleDesktop: true,
            visibleTablet: true,
            visibleMobile: true
        );
    }

    /**
     * Factory: Componente visible solo en desktop
     *
     * @return self
     */
    public static function desktopOnly(): self
    {
        return new self(
            enabled: true,
            visibleDesktop: true,
            visibleTablet: false,
            visibleMobile: false
        );
    }

    /**
     * Factory: Componente visible solo en mobile
     *
     * @return self
     */
    public static function mobileOnly(): self
    {
        return new self(
            enabled: true,
            visibleDesktop: false,
            visibleTablet: false,
            visibleMobile: true
        );
    }

    /**
     * Factory: Componente visible solo en tablet
     *
     * @return self
     */
    public static function tabletOnly(): self
    {
        return new self(
            enabled: true,
            visibleDesktop: false,
            visibleTablet: true,
            visibleMobile: false
        );
    }

    /**
     * Crear desde array
     *
     * @param array $data
     * @return self
     */
    public static function fromArray(array $data): self
    {
        return new self(
            enabled: (bool) ($data['enabled'] ?? false),
            visibleDesktop: (bool) ($data['visible_desktop'] ?? true),
            visibleTablet: (bool) ($data['visible_tablet'] ?? true),
            visibleMobile: (bool) ($data['visible_mobile'] ?? true)
        );
    }

    /**
     * Comparar con otro ComponentVisibility
     *
     * @param ComponentVisibility $other
     * @return bool
     */
    public function equals(ComponentVisibility $other): bool
    {
        return $this->enabled === $other->enabled &&
            $this->visibleDesktop === $other->visibleDesktop &&
            $this->visibleTablet === $other->visibleTablet &&
            $this->visibleMobile === $other->visibleMobile;
    }
}
