<?php
declare(strict_types=1);

namespace PpPhp\Core\Designer\Navigation;

final class DesignerNavigationMenu
{
    public function __construct(
        private readonly string $menuId,
        private readonly string $label,
        private readonly string $placement = 'sidebar',
        private readonly array $items = [],
        private readonly array $style = [],
        private readonly array $meta = []
    ) {}

    public static function create(string $menuId, string $label = '', string $placement = 'sidebar'): self
    {
        return new self(
            $menuId,
            $label !== '' ? $label : self::humanize($menuId),
            $placement,
            [],
            self::defaultStyle($placement),
            ['version' => '1.0.0']
        );
    }

    public static function fromArray(array $data): self
    {
        return new self(
            (string) ($data['menuId'] ?? $data['id'] ?? 'main_menu'),
            (string) ($data['label'] ?? 'Main Menu'),
            (string) ($data['placement'] ?? 'sidebar'),
            (array) ($data['items'] ?? []),
            (array) ($data['style'] ?? []),
            (array) ($data['meta'] ?? [])
        );
    }

    public function menuId(): string { return $this->menuId; }
    public function items(): array { return $this->items; }

    public function addItem(DesignerNavigationItem $item, ?string $parentId = null): self
    {
        $items = $this->items;

        if ($parentId === null || $parentId === '') {
            $items[] = $item->toArray();
        } else {
            $items = $this->addChildToItems($items, $parentId, $item);
        }

        return new self($this->menuId, $this->label, $this->placement, $items, $this->style, $this->meta);
    }

    public function removeItem(string $id): self
    {
        return new self($this->menuId, $this->label, $this->placement, $this->removeFromItems($this->items, $id), $this->style, $this->meta);
    }

    public function moveItem(string $id, int $newIndex): self
    {
        $items = $this->items;
        $found = null;
        foreach ($items as $index => $item) {
            if (($item['id'] ?? '') === $id) {
                $found = $item;
                array_splice($items, $index, 1);
                break;
            }
        }

        if ($found !== null) {
            $newIndex = max(0, min($newIndex, count($items)));
            array_splice($items, $newIndex, 0, [$found]);
        }

        return new self($this->menuId, $this->label, $this->placement, array_values($items), $this->style, $this->meta);
    }

    public function toComponent(): array
    {
        return [
            'id' => $this->menuId,
            'name' => $this->menuId,
            'type' => 'navigation_menu',
            'label' => $this->label,
            'props' => $this->toArray(),
            'children' => [],
            'events' => ['itemClick', 'expand', 'collapse'],
            'meta' => ['designerRuntime' => 'navigation', 'version' => '1.0.0'],
        ];
    }

    public function toArray(): array
    {
        return [
            'menuId' => $this->menuId,
            'id' => $this->menuId,
            'label' => $this->label,
            'placement' => $this->placement,
            'items' => $this->items,
            'style' => $this->style,
            'meta' => $this->meta,
            'itemCount' => $this->countItems($this->items),
        ];
    }

    private function addChildToItems(array $items, string $parentId, DesignerNavigationItem $item): array
    {
        foreach ($items as $index => $row) {
            if (($row['id'] ?? '') === $parentId) {
                $row['children'] = array_merge((array) ($row['children'] ?? []), [$item->toArray()]);
                $items[$index] = $row;
                return $items;
            }

            if (!empty($row['children'])) {
                $row['children'] = $this->addChildToItems((array) $row['children'], $parentId, $item);
                $items[$index] = $row;
            }
        }

        return $items;
    }

    private function removeFromItems(array $items, string $id): array
    {
        $rows = [];
        foreach ($items as $item) {
            if (($item['id'] ?? '') === $id) {
                continue;
            }

            if (!empty($item['children'])) {
                $item['children'] = $this->removeFromItems((array) $item['children'], $id);
            }

            $rows[] = $item;
        }

        return array_values($rows);
    }

    private function countItems(array $items): int
    {
        $count = count($items);
        foreach ($items as $item) {
            $count += $this->countItems((array) ($item['children'] ?? []));
        }
        return $count;
    }

    private static function defaultStyle(string $placement): array
    {
        return [
            'orientation' => $placement === 'topbar' ? 'horizontal' : 'vertical',
            'collapsible' => $placement === 'sidebar',
            'showIcons' => true,
            'showLabels' => true,
        ];
    }

    private static function humanize(string $value): string
    {
        return ucwords(str_replace(['_', '-'], ' ', $value));
    }
}
