<?php

namespace App\Services\Navigation;

use App\Models\NavItem;
use App\Models\RoleNavItem;
use Illuminate\Support\Facades\Cache;

class NavbarService
{
    public function getMenuForRoles(array $roles): array
    {
        $roles = array_values(array_filter(array_map(fn ($r) => strtolower(trim((string) $r)), $roles)));
        $cacheKey = 'navbar_' . md5(json_encode($roles));

        return Cache::remember($cacheKey, 300, function () use ($roles) {
            $allowedIds = RoleNavItem::getNavItemIdsForRoles($roles);
            if (empty($allowedIds)) {
                return [];
            }

            $rows = NavItem::query()
                ->where('is_enabled', 1)
                ->orderBy('menu_parent_id', 'asc')
                ->orderBy('label', 'asc')
                ->orderBy('id', 'asc')
                ->get()
                ->toArray();

            $byId = [];
            foreach ($rows as $row) {
                if (in_array((int) $row['id'], $allowedIds, true)) {
                    $row['children'] = [];
                    $byId[$row['id']] = $row;
                }
            }

            $tree = [];
            foreach ($byId as $id => &$node) {
                $pid = $node['menu_parent_id'] ?? null;
                if ($pid && isset($byId[$pid])) {
                    $byId[$pid]['children'][] = &$node;
                } else {
                    $tree[] = &$node;
                }
            }
            unset($node);

            $this->sortTreeAlpha($tree);

            return $tree;
        });
    }

    public function clearCache(): void
    {
        Cache::flush();
    }

    private function labelKey(string $s): string
    {
        $s = trim(preg_replace('/\s+/', ' ', $s));
        $s = preg_replace('/^[^[:alnum:]]+/u', '', $s);
        $s = preg_replace('/^(?i)(the|an|a)\s+/', '', $s);

        return mb_strtolower($s, 'UTF-8');
    }

    private function sortTreeAlpha(array &$nodes): void
    {
        usort($nodes, function ($a, $b) {
            $result = strnatcasecmp($this->labelKey($a['label'] ?? ''), $this->labelKey($b['label'] ?? ''));

            return $result !== 0 ? $result : ((int) ($a['id'] ?? 0) <=> (int) ($b['id'] ?? 0));
        });

        foreach ($nodes as &$node) {
            if (!empty($node['children'])) {
                $this->sortTreeAlpha($node['children']);
            }
        }
        unset($node);
    }
}
