<?php

namespace App\Modules\Navigation\Services;

use App\Models\User;
use App\Modules\Navigation\Support\NavigationLabelResolver;
use Illuminate\Support\Facades\Route;

class NavigationMenuBuilder
{
    /**
     * @param  list<array<string, mixed>>  $groups
     * @param  list<string>  $moduleSlugs
     * @return list<array{label: string, icon: string, items: list<array<string, mixed>>}>
     */
    public function build(array $groups, User $user, bool $isAdmin, array $moduleSlugs): array
    {
        $out = [];
        foreach ($groups as $group) {
            if (! $this->groupVisible($group, $user, $isAdmin, $moduleSlugs)) {
                continue;
            }
            $items = [];
            foreach ($group['items'] ?? [] as $item) {
                if (! $this->itemVisible($item, $user, $isAdmin, $moduleSlugs)) {
                    continue;
                }
                if (! $this->routeResolvable($item)) {
                    continue;
                }
                $items[] = $this->normalizeItem($item);
            }
            if ($items === []) {
                continue;
            }
            $out[] = $this->normalizeGroup($group, $items);
        }

        return $out;
    }

    /**
     * @param  array<string, mixed>  $group
     * @param  list<string>  $moduleSlugs
     */
    private function groupVisible(array $group, User $user, bool $isAdmin, array $moduleSlugs): bool
    {
        if (! empty($group['gate']) && ! $user->can((string) $group['gate'])) {
            return false;
        }
        if ($isAdmin) {
            return true;
        }
        if (! empty($group['module']) && ! in_array((string) $group['module'], $moduleSlugs, true)) {
            return false;
        }

        return true;
    }

    /**
     * @param  array<string, mixed>  $item
     * @param  list<string>  $moduleSlugs
     */
    private function itemVisible(array $item, User $user, bool $isAdmin, array $moduleSlugs): bool
    {
        if (! empty($item['gate']) && ! $user->can((string) $item['gate'])) {
            return false;
        }
        if ($isAdmin) {
            return true;
        }
        if (! empty($item['permission']) && ! $user->can((string) $item['permission'])) {
            return false;
        }
        if (! empty($item['permissions_all']) && is_array($item['permissions_all'])) {
            foreach ($item['permissions_all'] as $permission) {
                if (! $user->can((string) $permission)) {
                    return false;
                }
            }
        }
        if (! $isAdmin && ! empty($item['permissions_any']) && is_array($item['permissions_any'])) {
            $any = false;
            foreach ($item['permissions_any'] as $perm) {
                if ($user->can((string) $perm)) {
                    $any = true;
                    break;
                }
            }
            if (! $any) {
                return false;
            }
        }
        if (! empty($item['module']) && ! in_array((string) $item['module'], $moduleSlugs, true)) {
            return false;
        }

        return true;
    }

    /**
     * @param  array<string, mixed>  $item
     */
    private function routeResolvable(array $item): bool
    {
        if (! empty($item['route'])) {
            return Route::has((string) $item['route']);
        }

        $href = $item['href'] ?? null;

        return $href !== null && $href !== '';
    }

    /**
     * @param  array<string, mixed>  $item
     * @return array<string, mixed>
     */
    private function normalizeItem(array $item): array
    {
        return [
            'label' => NavigationLabelResolver::label($item),
            'route' => $item['route'] ?? null,
            'route_params' => $item['route_params'] ?? [],
            'href' => $item['href'] ?? null,
            'active_routes' => $item['active_routes'] ?? null,
            'active_query' => $item['active_query'] ?? null,
            'nav_active_rule' => $item['nav_active_rule'] ?? null,
            'section' => $item['section'] ?? null,
        ];
    }

    /**
     * @param  array<string, mixed>  $group
     * @param  list<array<string, mixed>>  $items
     * @return array{label: string, icon: string, items: list<array<string, mixed>>}
     */
    private function normalizeGroup(array $group, array $items): array
    {
        return [
            'key' => (string) ($group['key'] ?? $group['label_key'] ?? 'group'),
            'label' => NavigationLabelResolver::label($group),
            'icon' => (string) ($group['icon'] ?? 'fe fe-grid'),
            'items' => $items,
        ];
    }
}
