import { generateModmaskMap, hideWindow, limit, skip } from "@lib/utils";

import { App, Astal, Gtk } from "astal/gtk4";
import { Variable, bind } from "astal";

import Hyprland from "gi://AstalHyprland";

const modmasks = generateModmaskMap();

// Incomplete Astal types?
type Bind = Hyprland.Bind & { description: string };

function ShortcutEntry({ entry }: { entry: Bind }) {
    return <box cssClasses={["entry"]} spacing={4}>
        {entry.modmask !== 0 && <label
            cssClasses={["kbd"]}
            label={modmasks[entry.modmask]?.toString()} />
        }
        <label cssClasses={["kbd"]} label={entry.key.toString()} />
        <label label={entry.description} />
    </box>
}

export default async function Shortcuts(_monitor_id: number) {
    const { TOP, BOTTOM, LEFT, RIGHT } = Astal.WindowAnchor;
    const hypr = Hyprland.get_default();

    const shortcuts: Variable<Bind[]> = Variable([]);
    const toSkip = Variable(0);

    const list = Variable.derive([
        bind(shortcuts),
        bind(toSkip)
    ], (page, count) => limit(
        skip(page, count),
        10
    ));

    const isEmpty = bind(list).as(list => list.length === 0);
    const onScroll = (dy: number) => {
        const value = toSkip.get();

        if (dy < 0) {
            if ((value - 10) < 0) return;
            toSkip.set(value - 10)
        } else {
            if ((value + 10) > shortcuts.get().length) return;
            toSkip.set(value + 10)
        }
    };

    const setup = (self: Gtk.Window) => self.connect('notify::visible', async () => {
        if (self.is_visible()) shortcuts.set(hypr.get_binds() as Bind[])
    })

    return <window
        visible={false}
        monitor={bind(hypr, "focusedMonitor").as(monitor => monitor.id)}
        name={"shortcuts"}
        cssClasses={["shortcuts"]}
        keymode={Astal.Keymode.EXCLUSIVE}
        anchor={TOP | BOTTOM | LEFT | RIGHT}
        onKeyPressed={hideWindow}
        application={App}
        setup={setup}>
        <box hexpand={false} cssClasses={["shortcuts"]} vertical halign={Gtk.Align.CENTER} valign={Gtk.Align.CENTER}>
            <box spacing={6} vertical onScroll={(_, __, dy) => onScroll(dy)}>
                {bind(list).as(list => list.map(entry => (
                    <ShortcutEntry entry={entry} />
                )))}
            </box>
            <box
                halign={Gtk.Align.CENTER}
                cssClasses={["not-found"]}
                vertical
                visible={isEmpty}>
                <image iconName="system-search-symbolic" />
                <label label="No match found" />
            </box>
        </box>
    </window>
}
