<?php

namespace App\Http\Controllers\Admin;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Response;
use App\Models\Menu;
use App\Models\MenuItem;
use App\Models\Page;

class MenuController extends Controller
{
    /**
     * Show menu overview with all menus and their items.
     * GET /admin/menus
     */
    public function index(Request $request, array $params = []): void
    {
        $menus = Menu::all('id', 'ASC');

        $itemsByMenu = [];
        $itemTreeByMenu = [];
        foreach ($menus as $menu) {
            $itemsByMenu[$menu['id']] = MenuItem::getByMenuId($menu['id']);
            $itemTreeByMenu[$menu['id']] = MenuItem::getTreeByMenuId($menu['id']);
        }

        // All pages for the "link to page" selector
        $pages = Page::all('sort_order', 'ASC');

        $this->renderAdmin('menus/index', [
            'pageTitle'      => __('admin.menus.title'),
            'menus'          => $menus,
            'itemsByMenu'    => $itemsByMenu,
            'itemTreeByMenu' => $itemTreeByMenu,
            'pages'          => $pages,
            'auth'           => $this->auth(),
            'csrf'           => $this->csrf(),
        ]);
    }

    /**
     * Add a new item to a menu.
     * POST /admin/menus/items/store
     */
    public function storeItem(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $menuId = (int) $request->input('menu_id', 0);
        $label  = trim($request->input('label', ''));
        $url    = trim($request->input('url', ''));

        if (!$menuId || $label === '' || $url === '') {
            set_flash('error', __('messages.all_required'));
            Response::redirect(admin_url('menus'));
            return;
        }

        $menu = Menu::find($menuId);
        if (!$menu) {
            set_flash('error', __('messages.not_found', ['item' => 'Menu']));
            Response::redirect(admin_url('menus'));
            return;
        }

        $pageId   = $request->input('page_id', '');
        $parentId = (int) $request->input('parent_id', 0);

        // Validate parent_id: must belong to same menu and max 3 levels
        $validParentId = null;
        if ($parentId > 0) {
            $parent = MenuItem::find($parentId);
            if ($parent && (int) $parent['menu_id'] === $menuId) {
                // Check nesting depth (max 3 levels = parent can be at depth 0 or 1)
                $depth = MenuItem::depthOf($parentId);
                if ($depth < 2) {
                    $validParentId = $parentId;
                }
            }
        }

        MenuItem::create([
            'menu_id'    => $menuId,
            'parent_id'  => $validParentId,
            'label'      => $label,
            'url'        => $url,
            'page_id'    => $pageId !== '' ? (int) $pageId : null,
            'target'     => in_array($request->input('target', '_self'), ['_self', '_blank']) ? $request->input('target') : '_self',
            'sort_order' => MenuItem::nextSortOrder($menuId, $validParentId),
            'is_visible' => (int) $request->input('is_visible', 1),
        ]);

        $this->clearPageCache();
        set_flash('success', __('messages.menu_item_added'));
        Response::redirect(admin_url('menus') . '#menu-' . $menuId);
    }

    /**
     * Update an existing menu item.
     * POST /admin/menus/items/update/{id}
     */
    public function updateItem(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $id   = (int) ($params['id'] ?? 0);
        $item = MenuItem::find($id);

        if (!$item) {
            set_flash('error', __('messages.not_found', ['item' => 'Menu item']));
            Response::redirect(admin_url('menus'));
            return;
        }

        $label = trim($request->input('label', ''));
        $url   = trim($request->input('url', ''));

        if ($label === '' || $url === '') {
            set_flash('error', __('messages.all_required'));
            Response::redirect(admin_url('menus') . '#menu-' . $item['menu_id']);
            return;
        }

        $pageId   = $request->input('page_id', '');
        $parentId = $request->input('parent_id', '');

        $updateData = [
            'label'      => $label,
            'url'        => $url,
            'page_id'    => $pageId !== '' ? (int) $pageId : null,
            'target'     => in_array($request->input('target', '_self'), ['_self', '_blank']) ? $request->input('target') : '_self',
            'sort_order' => (int) $request->input('sort_order', $item['sort_order']),
            'is_visible' => (int) $request->input('is_visible', 1),
        ];

        // Update parent_id if provided (empty string = no change, "0" = make top-level)
        if ($parentId !== '') {
            $pid = (int) $parentId;
            if ($pid === 0) {
                $updateData['parent_id'] = null;
            } elseif ($pid !== $id) { // prevent self-referencing
                $parent = MenuItem::find($pid);
                if ($parent && (int) $parent['menu_id'] === (int) $item['menu_id']) {
                    $depth = MenuItem::depthOf($pid);
                    // Prevent circular references (A→B→A) and respect max depth
                    if ($depth < 2 && !MenuItem::isAncestorOf($id, $pid)) {
                        $updateData['parent_id'] = $pid;
                    }
                }
            }
        }

        MenuItem::updateById($id, $updateData);
        $this->clearPageCache();

        set_flash('success', 'Menu item updated.');
        Response::redirect(admin_url('menus') . '#menu-' . $item['menu_id']);
    }

    /**
     * Delete a menu item.
     * POST /admin/menus/items/delete/{id}
     */
    public function deleteItem(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $id   = (int) ($params['id'] ?? 0);
        $item = MenuItem::find($id);

        if ($item) {
            // Also delete all children (cascade)
            MenuItem::deleteChildren($id);
            MenuItem::deleteById($id);
            $this->clearPageCache();
            set_flash('success', 'Menu item deleted.');
            Response::redirect(admin_url('menus') . '#menu-' . $item['menu_id']);
            return;
        }

        set_flash('error', __('messages.not_found', ['item' => 'Menu item']));
        Response::redirect(admin_url('menus'));
    }

    /**
     * Reorder items via JSON POST (used by drag & drop JS).
     * POST /admin/menus/items/reorder
     * Expects: csrf_token + order = JSON-encoded array of item IDs in new sequence.
     */
    /**
     * Reorder items via JSON POST (used by drag & drop JS).
     * POST /admin/menus/items/reorder
     *
     * Supports two formats:
     *   - Flat: order = [id1, id2, id3] (simple reorder, parent_id unchanged)
     *   - Nested: order = [{id:1, parent_id:null, children:[{id:2, parent_id:1},...]}]
     */
    public function reorder(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $order = json_decode($request->input('order', '[]'), true);
        if (!is_array($order)) {
            http_response_code(400);
            echo json_encode(['success' => false, 'error' => 'Invalid order data.']);
            return;
        }

        // Detect format: nested (objects with id+children) or flat (plain IDs)
        if (!empty($order) && is_array($order[0] ?? null) && isset($order[0]['id'])) {
            // Nested format: update sort_order AND parent_id
            $this->applyNestedOrder($order, null, 0);
        } else {
            // Flat format: update sort_order only
            foreach ($order as $sortOrder => $itemId) {
                MenuItem::updateById((int) $itemId, ['sort_order' => (int) $sortOrder]);
            }
        }

        echo json_encode(['success' => true]);
    }

    /**
     * Recursively apply nested order (sort_order + parent_id).
     */
    private function applyNestedOrder(array $items, ?int $parentId, int $startOrder): int
    {
        $order = $startOrder;
        foreach ($items as $item) {
            $id = (int) ($item['id'] ?? 0);
            if ($id <= 0) continue;

            MenuItem::updateById($id, [
                'parent_id'  => $parentId,
                'sort_order' => $order,
            ]);
            $order++;

            if (!empty($item['children']) && is_array($item['children'])) {
                $order = $this->applyNestedOrder($item['children'], $id, $order);
            }
        }
        return $order;
    }

    /**
     * Legacy stub redirect – kept for route compatibility.
     * POST /admin/menus/save
     */
    public function save(Request $request, array $params = []): void
    {
        Response::redirect(admin_url('menus'));
    }
}
