# printers/ContextMenuList.py

from typing import Callable, TypeVar, List
from functools import partial
from .printers import (
    cut_items_to_window,
    get_is_focused,
    make_context_menu,
    print_highlighted_line,
    print_line
)

T = TypeVar("T")

def _make_context_menu_item_list(item_renderer: Callable[[T, any], List[str]], screen, context, remaining_height):
    _, num_cols = screen.getmaxyx()
    items = list(context.get("items", []))
    selected_item = context.get("selected_item", None)
    lines = []
    line_ids = []
    for item in items:
        rendered = item_renderer(item, screen)
        lines.extend(rendered)
        line_ids.extend([item] * len(rendered))
    context["line_ids"] = line_ids
    context["lines"] = lines
    selected_index = int(context.get("selected_index", 0))
    is_focused = get_is_focused(context)
    if selected_item:
        remaining_height = max(0, remaining_height - 2)
    start, stop, visible = cut_items_to_window(selected_index, lines, remaining_height)
    out = []
    idx = start
    for text in visible:
        s = str(text)[:num_cols]
        if idx == selected_index and is_focused:
            out.append(partial(print_highlighted_line, 0, s))
            if selected_item:
                out.extend(make_context_menu(context.get("menu", {}), remaining_height))
        else:
            out.append(partial(print_line, 0, s))
        idx += 1
    return out

class ContextMenuList:
    @staticmethod
    def layout(min_height=5, flex=1, max_height=None):
        cfg = {"flex": flex, "min_height": min_height}
        if max_height is not None:
            cfg["max_height"] = max_height
        return cfg

    @staticmethod
    def display_state(screen, items=None, item_renderer=None, menu=None, selected_index=0, focused=False, min_height=5, flex=1, max_height=None):
        return {
            "items": list(items or []),
            "selected_item": None,
            "menu": dict(menu or {"selected_index": 0, "items": []}),
            "selected_index": int(selected_index),
            "focused": bool(focused),
            "layout": ContextMenuList.layout(min_height, flex, max_height),
            "line_generator": partial(_make_context_menu_item_list, item_renderer, screen)
        }
