<?php

namespace App\Services;

use App\Models\MenuItem;
use App\Models\User;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Route;

class MenuRenderer
{
    /**
     * Modules that stop making sense when the tenant runs in walk-in-only mode.
     *
     * Only the credit-note surface is suppressed. The customer directory stays
     * in the menu deliberately: a walk-in business still wants to look up past
     * contacts and history, it just never attaches one to a sale.
     */
    private const WALKIN_ONLY_HIDDEN_MODULES = [
        'isms_credit_notes',
    ];

    /**
     * @return array<int, array<string, mixed>>
     */
    public static function forUser(User $user): array
    {
        $tree = MenuItem::with('children.children.children')
            ->whereNull('parent_id')
            ->where('is_active', true)
            ->orderBy('order')
            ->get();

        $hidden = app(PosSettings::class)->walkinOnly()
            ? self::WALKIN_ONLY_HIDDEN_MODULES
            : [];

        return self::filterTree($tree, $user, $hidden)->values()->all();
    }

    /**
     * @param  Collection<int, MenuItem>  $items
     * @param  array<int, string>  $hidden
     * @return Collection<int, array<string, mixed>>
     */
    private static function filterTree(Collection $items, User $user, array $hidden): Collection
    {
        return $items
            ->filter(fn (MenuItem $item): bool => $item->is_active)
            ->map(function (MenuItem $item) use ($user, $hidden): ?array {
                $filteredChildren = self::filterTree($item->children, $user, $hidden);

                $isLeafVisible = $item->route_name !== null
                    && ($item->module_key === null
                        || (! in_array($item->module_key, $hidden, true)
                            && $user->hasPermissionTo("{$item->module_key}.access")));

                $isGroupVisible = $item->route_name === null
                    && $filteredChildren->isNotEmpty();

                if (! $isLeafVisible && ! $isGroupVisible) {
                    return null;
                }

                return [
                    'id' => $item->id,
                    'name' => $item->name,
                    'icon' => $item->icon,
                    'href' => $item->route_name && Route::has($item->route_name)
                        ? route($item->route_name)
                        : null,
                    'route' => $item->route_name,
                    'children' => $filteredChildren->values()->all(),
                ];
            })
            ->filter()
            ->values();
    }
}
