<?php

namespace App\Services\Menu;

/**
 * Data Transfer Object for menu items.
 *
 * This class represents a single menu item that can be registered
 * by modules for dynamic menu rendering.
 */
class MenuItemDTO
{
    /**
     * @param  string  $name  Display name (will be translated via __())
     * @param  string|null  $url  URL path (e.g., '/payroll/dashboard')
     * @param  string|null  $icon  Icon class (e.g., 'menu-icon bx bx-money')
     * @param  string|array<string>|null  $slug  Route name(s) for active state detection
     * @param  string|null  $addon  Module name for addon-based visibility
     * @param  array<string>  $roles  Roles that can see this item (empty = all roles)
     * @param  string|null  $permission  Permission slug for access control
     * @param  array{0: string, 1: string}|null  $badge  Badge [color, text] e.g., ['danger', 'Beta']
     * @param  array<MenuItemDTO|array<string, mixed>>  $submenu  Nested menu items
     * @param  int  $priority  Sort order (lower = higher in menu)
     * @param  string|null  $menuHeader  Section header text (if this is a header, not a link)
     * @param  string|null  $target  HTML target attribute (e.g., '_blank')
     * @param  string|null  $menuKey  Unique identifier for this menu (used as parent reference)
     * @param  string|null  $parentKey  Reference to parent menu's menuKey (for grouping)
     */
    public function __construct(
        public string $name,
        public ?string $url = null,
        public ?string $icon = null,
        public string|array|null $slug = null,
        public ?string $addon = null,
        public array $roles = [],
        public ?string $permission = null,
        public ?array $badge = null,
        public array $submenu = [],
        public int $priority = 100,
        public ?string $menuHeader = null,
        public ?string $target = null,
        public ?string $menuKey = null,
        public ?string $parentKey = null,
    ) {}

    /**
     * Create a MenuItemDTO from an array.
     *
     * @param  array<string, mixed>  $data
     */
    public static function fromArray(array $data): self
    {
        $submenu = [];
        if (isset($data['submenu']) && is_array($data['submenu'])) {
            foreach ($data['submenu'] as $item) {
                $submenu[] = $item instanceof self ? $item : self::fromArray($item);
            }
        }

        return new self(
            name: $data['name'] ?? '',
            url: $data['url'] ?? null,
            icon: $data['icon'] ?? null,
            slug: $data['slug'] ?? null,
            addon: $data['addon'] ?? null,
            roles: $data['roles'] ?? [],
            permission: $data['permission'] ?? null,
            badge: $data['badge'] ?? null,
            submenu: $submenu,
            priority: $data['priority'] ?? 100,
            menuHeader: $data['menuHeader'] ?? null,
            target: $data['target'] ?? null,
            menuKey: $data['menuKey'] ?? null,
            parentKey: $data['parentKey'] ?? null,
        );
    }

    /**
     * Convert the DTO to an array format compatible with existing menu rendering.
     *
     * @return array<string, mixed>
     */
    public function toArray(): array
    {
        $result = [];

        if ($this->menuHeader !== null) {
            $result['menuHeader'] = $this->menuHeader;

            return $result;
        }

        $result['name'] = $this->name;

        if ($this->url !== null) {
            $result['url'] = $this->url;
        }

        if ($this->icon !== null) {
            $result['icon'] = $this->icon;
        }

        if ($this->slug !== null) {
            $result['slug'] = $this->slug;
        }

        if ($this->addon !== null) {
            $result['addon'] = $this->addon;
        }

        if (! empty($this->roles)) {
            $result['roles'] = $this->roles;
        }

        if ($this->permission !== null) {
            $result['permission'] = $this->permission;
        }

        if ($this->badge !== null) {
            $result['badge'] = $this->badge;
        }

        if ($this->target !== null) {
            $result['target'] = $this->target;
        }

        if ($this->menuKey !== null) {
            $result['menuKey'] = $this->menuKey;
        }

        if ($this->parentKey !== null) {
            $result['parentKey'] = $this->parentKey;
        }

        if (! empty($this->submenu)) {
            $result['submenu'] = array_map(
                fn ($item) => $item instanceof self ? $item->toArray() : $item,
                $this->submenu
            );
        }

        return $result;
    }

    /**
     * Check if this menu item is a header.
     */
    public function isHeader(): bool
    {
        return $this->menuHeader !== null;
    }

    /**
     * Check if this menu item has a submenu.
     */
    public function hasSubmenu(): bool
    {
        return ! empty($this->submenu);
    }

    /**
     * Check if this menu item is visible for the given roles.
     *
     * @param  array<string>  $userRoles
     */
    public function isVisibleForRoles(array $userRoles): bool
    {
        // If no roles specified, visible to all
        if (empty($this->roles)) {
            return true;
        }

        // Check if any user role matches
        return ! empty(array_intersect($this->roles, $userRoles));
    }
}
