import { Container } from 'pixi.js';
import { Button } from './Button';
import { ListCursor } from './listCursor';
import { ListScroll } from './listScroll';

/**
 * Вертикальное меню: список кнопок с клавиатурным фокусом и навигацией.
 * Игра сама читает ввод и вызывает moveCursor/activate — движок не привязан к раскладке.
 * Недоступные пункты (disabled) приглушены: курсор их пропускает, клик игнорируется.
 * Длинные списки: visibleRows задаёт окно видимых строк (скролл — ListScroll);
 * hover мышью переставляет курсор; пункт может нести value (громкость, счётчик).
 */

/** Пункт меню. */
export interface MenuItem {
    label: string;
    onSelect?: () => void;
    /** Недоступный пункт: приглушён, курсор пропускает, активация игнорируется. */
    disabled?: boolean;
    /** Значение справа (громкость, счётчик) — обновляется через setValue. */
    value?: string;
}

export interface MenuListOptions {
    width: number;
    height: number;
    /** Отступ между кнопками (виртуальные пиксели). */
    gap?: number;
    size?: number;
    /** Видимых строк (скролл); нет/0 — окно = весь список, как раньше. */
    visibleRows?: number;
}

export class MenuList extends Container {
    private buttons: Button[] = [];
    private listCursor: ListCursor;
    private scroll: ListScroll | null = null;

    constructor(private options: MenuListOptions) {
        super();
        this.listCursor = new ListCursor(0);
    }

    /** Пересобрать список пунктов (старые кнопки уничтожаются); фокус сохраняется. */
    setItems(items: MenuItem[]): void {
        for (const b of this.buttons) b.destroy({ children: true });
        this.buttons = [];
        const rows = this.options.visibleRows ?? 0;
        this.scroll = rows > 0 ? new ListScroll(rows) : null;
        let y = 0;
        for (const item of items) {
            const btn = new Button({
                label: item.label,
                width: this.options.width,
                height: this.options.height,
                size: this.options.size,
                value: item.value,
                disabled: item.disabled,
                onSelect: item.onSelect
            });
            btn.position.set(0, y);
            // Hover мышью/тачем переставляет курсор (как выбор в DialogueBox).
            const index = this.buttons.length;
            btn.on('pointerover', () => {
                if (!item.disabled && index !== this.listCursor.index) {
                    this.listCursor.index = index;
                    this.applyFocus();
                }
            });
            this.addChild(btn);
            this.buttons.push(btn);
            y += this.step();
        }
        const keep = Math.min(this.listCursor.index, Math.max(0, items.length - 1));
        this.listCursor = new ListCursor(items.length, (i) => !items[i]?.disabled);
        this.listCursor.index = keep;
        if (items[keep]?.disabled) this.listCursor.move(1); // старт на выбираемом
        this.applyFocus();
    }

    /** Сдвинуть фокус (↑ = -1, ↓ = +1); недоступные пункты пропускаются. */
    moveCursor(delta: number): void {
        this.listCursor.move(delta);
        this.applyFocus();
    }

    /** Выбранный индекс. */
    get index(): number {
        return this.listCursor.index;
    }

    /** Активировать кнопку под фокусом (Enter). */
    activate(): void {
        this.buttons[this.listCursor.index]?.activate();
    }

    /** Обновить значение пункта справа (настройки — без пересборки списка). */
    setValue(index: number, value: string): void {
        const btn = this.buttons[index];
        if (btn) btn.value = value;
    }

    /** Окно видимых строк (или весь список, если скролла нет). */
    get window(): { first: number; last: number } | null {
        return this.scroll ? { first: this.scroll.first, last: this.scroll.last } : null;
    }

    private applyFocus(): void {
        this.buttons.forEach((b, i) => (b.focused = i === this.listCursor.index));
        if (this.scroll) {
            this.scroll.sync(this.listCursor.index, this.buttons.length);
            for (let i = 0; i < this.buttons.length; i++) {
                const visible = i >= this.scroll.first && i < this.scroll.last;
                this.buttons[i]!.visible = visible;
                this.buttons[i]!.position.y = (i - this.scroll.first) * this.step();
            }
        }
    }

    private step(): number {
        return this.options.height + (this.options.gap ?? 2);
    }
}