import { execAsync, idle } from 'astal';
import { Astal, Gtk } from 'astal/gtk3';

import Tablet from '../../services/tablet';
import { hyprMessage } from '../../lib';

import OskWindow from './osk-window';
import { Keys } from './keys';


const KEY_N = 249;
const KEYCODES = Array.from(Array(KEY_N).keys()).map((keycode) => `${keycode}:0`);

const ANIM_DURATION = 700;

const releaseAllKeys = () => {
    execAsync([
        'ydotool', 'key',
        ...KEYCODES,
    ]).catch(print);
};

export default (window: OskWindow) => {
    const tablet = Tablet.get_default();

    let signals = [] as number[];
    let calculatedHeight = 0;

    idle(() => {
        calculatedHeight = window.get_allocated_height();
        tablet.oskState = false;

        setTimeout(() => {
            window.get_grandchildren()[0].toggleClassName('hidden', false);
            window.set_exclusivity(Astal.Exclusivity.EXCLUSIVE);
        }, ANIM_DURATION * 3);
    });

    const gesture = Gtk.GestureDrag.new(window);

    window.hook(tablet, 'notify::osk-state', () => {
        if (tablet.oskState) {
            window.setSlideDown();

            window.get_child().set_css(`
                transition: margin-bottom ${ANIM_DURATION}ms cubic-bezier(0.36, 0, 0.66, -0.56);
                margin-bottom: 0px;
            `);
        }
        else {
            releaseAllKeys();

            window.setSlideUp();

            window.get_child().set_css(`
                transition: margin-bottom ${ANIM_DURATION}ms cubic-bezier(0.36, 0, 0.66, -0.56);
                margin-bottom: -${calculatedHeight}px;
            `);
        }
    });

    window.killGestureSigs = () => {
        signals.forEach((id) => {
            gesture.disconnect(id);
        });
        signals = [];
        window.startY = null;
    };

    window.setSlideUp = () => {
        window.killGestureSigs();

        // Begin drag
        signals.push(
            gesture.connect('drag-begin', () => {
                hyprMessage('j/cursorpos').then((out) => {
                    window.startY = JSON.parse(out).y;
                });
            }),
        );

        // Update drag
        signals.push(
            gesture.connect('drag-update', () => {
                hyprMessage('j/cursorpos').then((out) => {
                    if (!window.startY) {
                        return;
                    }

                    const currentY = JSON.parse(out).y;
                    const offset = window.startY - currentY;

                    if (offset < 0) {
                        window.get_child().set_css(`
                            transition: margin-bottom 0.5s ease-in-out;
                            margin-bottom: -${calculatedHeight}px;
                        `);

                        return;
                    }

                    if (offset > calculatedHeight) {
                        window.get_child().set_css(`
                            margin-bottom: 0px;
                        `);
                    }
                    else {
                        window.get_child().set_css(`
                            margin-bottom: ${offset - calculatedHeight}px;
                        `);
                    }
                });
            }),
        );

        // End drag
        signals.push(
            gesture.connect('drag-end', () => {
                hyprMessage('j/cursorpos').then((out) => {
                    if (!window.startY) {
                        return;
                    }

                    const currentY = JSON.parse(out).y;
                    const offset = window.startY - currentY;

                    if (offset > calculatedHeight) {
                        window.get_child().set_css(`
                            transition: margin-bottom 0.5s ease-in-out;
                            margin-bottom: 0px;
                        `);
                        tablet.oskState = true;
                    }
                    else {
                        window.get_child().set_css(`
                            transition: margin-bottom 0.5s ease-in-out;
                            margin-bottom: -${calculatedHeight}px;
                        `);
                    }

                    window.startY = null;
                });
            }),
        );
    };

    window.setSlideDown = () => {
        window.killGestureSigs();

        // Begin drag
        signals.push(
            gesture.connect('drag-begin', () => {
                hyprMessage('j/cursorpos').then((out) => {
                    const hasActiveKey = Keys.get().map((v) => v.get()).includes(true);

                    if (!hasActiveKey) {
                        window.startY = JSON.parse(out).y;
                    }
                });
            }),
        );

        // Update drag
        signals.push(
            gesture.connect('drag-update', () => {
                hyprMessage('j/cursorpos').then((out) => {
                    if (!window.startY) {
                        return;
                    }

                    const currentY = JSON.parse(out).y;
                    const offset = window.startY - currentY;

                    if (offset > 0) {
                        window.get_child().set_css(`
                            transition: margin-bottom 0.5s ease-in-out;
                            margin-bottom: 0px;
                        `);

                        return;
                    }

                    window.get_child().set_css(`
                        margin-bottom: ${offset}px;
                    `);
                });
            }),
        );

        // End drag
        signals.push(
            gesture.connect('drag-end', () => {
                hyprMessage('j/cursorpos').then((out) => {
                    if (!window.startY) {
                        return;
                    }

                    const currentY = JSON.parse(out).y;
                    const offset = window.startY - currentY;

                    if (offset < -(calculatedHeight * 2 / 3)) {
                        window.get_child().set_css(`
                            transition: margin-bottom 0.5s ease-in-out;
                            margin-bottom: -${calculatedHeight}px;
                        `);

                        tablet.oskState = false;
                    }
                    else {
                        window.get_child().set_css(`
                            transition: margin-bottom 0.5s ease-in-out;
                            margin-bottom: 0px;
                        `);
                    }

                    window.startY = null;
                });
            }),
        );
    };

    return window;
};