<?php

namespace App\Models;

use App\Core\Model;

class MenuItem extends Model
{
    protected static string $table = 'iw_menu_items';

    /**
     * Get all items for a given menu (incl. hidden), sorted by sort_order.
     * Used in the admin backend where visibility should not be filtered.
     */
    public static function getByMenuId(int $menuId): array
    {
        return static::db()->fetchAll(
            "SELECT * FROM iw_menu_items WHERE menu_id = :menu_id ORDER BY sort_order ASC",
            ['menu_id' => $menuId]
        );
    }

    /**
     * Get the next sort_order value for a given menu (optionally scoped to parent).
     */
    public static function nextSortOrder(int $menuId, ?int $parentId = null): int
    {
        if ($parentId !== null) {
            $max = static::db()->fetchColumn(
                "SELECT COALESCE(MAX(sort_order), -1) FROM iw_menu_items WHERE menu_id = :menu_id AND parent_id = :pid",
                ['menu_id' => $menuId, 'pid' => $parentId]
            );
        } else {
            $max = static::db()->fetchColumn(
                "SELECT COALESCE(MAX(sort_order), -1) FROM iw_menu_items WHERE menu_id = :menu_id",
                ['menu_id' => $menuId]
            );
        }
        return (int) $max + 1;
    }

    /**
     * Calculate the nesting depth of an item (0 = top-level, 1 = child, 2 = grandchild).
     * Accepts optional pre-fetched items array to avoid N+1 queries.
     */
    public static function depthOf(int $itemId, int $maxDepth = 3, ?array $allItems = null): int
    {
        // Build lookup map from pre-fetched items to avoid N+1 queries
        if ($allItems !== null) {
            $map = [];
            foreach ($allItems as $item) {
                $map[(int) $item['id']] = $item;
            }

            $depth = 0;
            $currentId = $itemId;
            while (isset($map[$currentId]) && $map[$currentId]['parent_id'] !== null && $depth < $maxDepth) {
                $depth++;
                $currentId = (int) $map[$currentId]['parent_id'];
            }
            return $depth;
        }

        // Fallback: individual queries (for single item lookups)
        $depth = 0;
        $current = static::find($itemId);

        while ($current && $current['parent_id'] !== null && $depth < $maxDepth) {
            $depth++;
            $current = static::find((int) $current['parent_id']);
        }

        return $depth;
    }

    /**
     * Check if $itemId is an ancestor of $potentialDescendantId (prevents circular parents).
     */
    public static function isAncestorOf(int $itemId, int $potentialDescendantId, int $maxDepth = 5): bool
    {
        $current = static::find($potentialDescendantId);
        $visited = 0;

        while ($current && $current['parent_id'] !== null && $visited < $maxDepth) {
            if ((int) $current['parent_id'] === $itemId) {
                return true;
            }
            $visited++;
            $current = static::find((int) $current['parent_id']);
        }

        return false;
    }

    /**
     * Delete all children (and grandchildren) of an item recursively.
     */
    public static function deleteChildren(int $parentId): void
    {
        $children = static::db()->fetchAll(
            "SELECT id FROM iw_menu_items WHERE parent_id = :pid",
            ['pid' => $parentId]
        );

        foreach ($children as $child) {
            static::deleteChildren((int) $child['id']);
            static::deleteById((int) $child['id']);
        }
    }

    /**
     * Get all items for a menu as a hierarchical tree (admin view).
     * Includes hidden items.
     */
    public static function getTreeByMenuId(int $menuId): array
    {
        $items = static::getByMenuId($menuId);
        return self::buildAdminTree($items, null);
    }

    private static function buildAdminTree(array $items, ?int $parentId): array
    {
        $branch = [];
        foreach ($items as $item) {
            $itemParent = $item['parent_id'] !== null ? (int) $item['parent_id'] : null;
            if ($itemParent === $parentId) {
                $item['children'] = self::buildAdminTree($items, (int) $item['id']);
                $item['depth'] = self::depthOf((int) $item['id'], 3, $items);
                $branch[] = $item;
            }
        }
        return $branch;
    }
}
