<?php

namespace Daylight\Core\Modules\MenuBuilder\Http\Controllers;

use Daylight\Core\Http\Controllers\Controller;
use Daylight\Core\Modules\MenuBuilder\Http\Requests\StoreMenuRequest;
use Daylight\Core\Modules\MenuBuilder\Http\Requests\UpdateMenuRequest;
use Daylight\Core\Modules\MenuBuilder\Models\Menu;
use Daylight\Core\Modules\MenuBuilder\Models\MenuItem;
use Daylight\Core\Modules\MenuBuilder\Models\MenuTranslation;
use Daylight\Core\Modules\Multilingualism\Multilingualism;
use Illuminate\Http\RedirectResponse;
use Illuminate\Routing\Controllers\HasMiddleware;
use Illuminate\Routing\Controllers\Middleware;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;

class MenuController extends Controller implements HasMiddleware
{
    public static function middleware(): array
    {
        return [
            new Middleware('can:create:menus', only: ['create', 'store']),
            new Middleware('can:read:menus', only: ['index', 'show']),
            new Middleware('can:update:menus', only: ['edit', 'update']),
            new Middleware('can:delete:menus', only: ['destroy']),
        ];
    }

    public function index(): View
    {
        return view('daylight::content.menus.index');
    }

    public function create(): View
    {
        return view('daylight::content.menus.create');
    }

    public function store(StoreMenuRequest $request): RedirectResponse
    {
        $menu = Menu::create([
            'name' => $request->get('name'),
        ]);

        Multilingualism::getAvailableLocales()->each(function ($locale) use ($menu) {
            $menu->translations()->create([
                'locale' => $locale,
            ]);
        });

        return redirect()
            ->route('daylight.content.menus.edit', $menu)
            ->with('success', __('Menu created'));
    }

    public function edit(Menu $menu)
    {
        $items = $menu->translations()->with('items')->whereLocale(request()->get('locale', app()->getLocale()))->first()?->items;

        $formattedItems = $items
            ? $items->where('parent_id', null)->map(function ($menuItem) {
                return [
                    'id' => $menuItem->id,
                    'name' => $menuItem->name,
                    'url' => $menuItem->url,
                    'children' => $this->recursiveMenuItems($menuItem->children),
                ];
            })->values()->toArray()
            : [];

        return view('daylight::content.menus.edit', [
            'menu' => $menu,
            'items' => $formattedItems,
        ]);
    }

    public function update(UpdateMenuRequest $request, Menu $menu)
    {
        DB::transaction(function () use ($menu, $request) {
            $menu->update([
                'name' => $request->get('name'),
            ]);

            $translation = $menu->translations()
                ->firstOrCreate([
                    'locale' => $request->get('locale', app()->getLocale()),
                ]);

            $translation->items()->delete();

            collect(json_decode($request->get('items')))->each(function ($item, $order) use ($translation) {
                $menuItem = $translation->items()->create([
                    'name' => $item->name,
                    'url' => $item->url,
                    'parent_id' => null,
                    'order' => $order,
                ]);

                if (isset($item->children) && is_array($item->children)) {
                    $this->updateChildren($translation, $menuItem, $item->children);
                }
            });
        });

        $menu->touch();

        return redirect()
            ->route('daylight.content.menus.index')
            ->with('success', __('Menu updated'));
    }

    public function destroy(Menu $menu): RedirectResponse
    {
        $menu->delete();

        return redirect()
            ->route('daylight.content.menus.index')
            ->with('success', __('Menu deleted'));
    }

    private function updateChildren(MenuTranslation $menu, MenuItem $menuItem, $children): void
    {
        collect($children)->each(function ($child, $childOrder) use ($menu, $menuItem) {
            $childMenuItem = $menu->items()->create([
                'parent_id' => $menuItem->id,
                'name' => $child->name,
                'url' => $child->url,
                'order' => $childOrder,
            ]);

            if (isset($child->children) && is_array($child->children) && count($child->children) > 0) {
                $this->updateChildren($menu, $childMenuItem, $child->children);
            }
        });
    }

    private function recursiveMenuItems($menuItems): array
    {
        return $menuItems->map(function ($menuItem) {
            return [
                'id' => $menuItem->id,
                'name' => $menuItem->name,
                'url' => $menuItem->url,
                'children' => $this->recursiveMenuItems($menuItem->children),
            ];
        })->toArray();
    }
}
