/*
 * Copyright 2017 Palantir Technologies, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import type { CreateNewItem } from "./listItemsUtils";

/**
 * An object describing how to render the list of items.
 * An `itemListRenderer` receives this object as its sole argument.
 */
export interface ItemListRendererProps<T> {
    /**
     * The currently focused item (for keyboard interactions), or `null` to
     * indicate that no item is active.
     */
    activeItem: T | CreateNewItem | null;

    /**
     * Array of items filtered by `itemListPredicate` or `itemPredicate`.
     * See `items` for the full list of items.
     *
     * Use `renderFilteredItems()` utility function from this library to
     * map each item in this array through `renderItem`, with support for
     * optional `noResults` and `initialContent` states.
     */
    filteredItems: T[];

    /**
     * Array of all items in the list.
     * See `filteredItems` for a filtered array based on `query` and predicate props.
     */
    items: T[];

    /**
     * The current query string.
     */
    query: string;

    /**
     * A ref handler that should be attached to the parent HTML element of the menu items.
     * This is required for the active item to scroll into view automatically.
     */
    itemsParentRef: React.Ref<HTMLUListElement>;

    /**
     * Props to apply to the `Menu` created within the `itemListRenderer`
     */
    menuProps?: React.HTMLAttributes<HTMLUListElement>;

    /**
     * Call this function to render an item.
     * This retrieves the modifiers for the item and delegates actual rendering
     * to the owner component's `itemRenderer` prop.
     */
    renderItem: (item: T, index: number) => React.JSX.Element | null;

    /**
     * Call this function to render the "create new item" view component.
     *
     * @returns null when creating a new item is not available, and undefined if the createNewItemRenderer returns undefined
     */
    renderCreateItem: () => React.JSX.Element | null | undefined;
}

/** Type alias for a function that renders the list of items. */
export type ItemListRenderer<T> = (itemListProps: ItemListRendererProps<T>) => React.JSX.Element | null;

/**
 * Helper method for rendering each item in `filteredItems`, with optional support for
 * `noResults` (when filtered items is empty) and `initialContent` (when query is empty).
 *
 * This utility is useful when creating a custom `itemListRenderer`. It handles the
 * logic for rendering `initialContent`, `noResults`, or the actual list of filtered items.
 *
 * @param props Props passed to the item list renderer.
 * @param noResults Optional element to render when the filtered list is empty.
 * @param initialContent Optional element to render when the query is empty.
 * @returns The rendered list of items or the appropriate placeholder content.
 */

export function renderFilteredItems(
    props: ItemListRendererProps<any>,
    noResults?: React.ReactNode,
    initialContent?: React.ReactNode | null,
): React.ReactNode {
    if (props.query.length === 0 && initialContent !== undefined) {
        return initialContent;
    }
    const items = props.filteredItems.map(props.renderItem).filter(item => item != null);
    return items.length > 0 ? items : noResults;
}
