import App from 'resource:///com/github/Aylur/ags/app.js';
import Bluetooth from 'resource:///com/github/Aylur/ags/service/bluetooth.js';
import Network from 'resource:///com/github/Aylur/ags/service/network.js';
import Variable from 'resource:///com/github/Aylur/ags/variable.js';

import { Box, Icon, Label, Revealer } from 'resource:///com/github/Aylur/ags/widget.js';
import { execAsync } from 'resource:///com/github/Aylur/ags/utils.js';

import { SpeakerIcon, MicIcon } from '../misc/audio-icons.js';
import CursorBox from '../misc/cursorbox.js';
import Separator from '../misc/separator.js';

import { NetworkMenu } from './network.js';
import { BluetoothMenu } from './bluetooth.js';

const SPACING = 28;
const ButtonStates = [];

/**
 * @typedef {import('types/widgets/widget').default} Widget
 * @typedef {import('types/widgets/box').default} Box
 * @typedef {import('types/widgets/icon').default} Icon
 * @typedef {import('types/widgets/label').default} Label
 * @typedef {import('types/widgets/revealer').default} Revealer
 * @typedef {[any, function, (string|undefined)?]} BindTuple
 */


/**
 * @param {{
 *      command?: function
 *      secondary_command?: function
 *      on_open?: function(Revealer):void
 *      icon: string|BindTuple
 *      indicator?: BindTuple
 *      menu?: any
 * }} o
 */
const GridButton = ({
    command = () => {/**/},
    secondary_command = () => {/**/},
    on_open = () => {/**/},
    icon,
    indicator,
    menu,
}) => {
    const Activated = Variable(false);

    ButtonStates.push(Activated);
    let iconWidget;
    /** @type Label */
    let indicatorWidget = Label();

    // Allow setting icon dynamically or statically
    if (typeof icon === 'string') {
        iconWidget = Icon({
            class_name: 'grid-label',
            icon,
            setup: (self) => {
                self.hook(Activated, () => {
                    self.setCss(`color: ${Activated.value ?
                        'rgba(189, 147, 249, 0.8)' :
                        'unset'};`);
                });
            },
        });
    }
    else if (Array.isArray(icon)) {
        iconWidget = Icon({
            class_name: 'grid-label',
            setup: (self) => {
                self
                    // @ts-expect-error
                    .hook(...icon)
                    .hook(Activated, () => {
                        self.setCss(`color: ${Activated.value ?
                            'rgba(189, 147, 249, 0.8)' :
                            'unset'};`);
                    });
            },
        });
    }

    if (indicator) {
        indicatorWidget = Label({
            class_name: 'sub-label',
            justification: 'left',
            truncate: 'end',
            max_width_chars: 12,
            setup: (self) => {
                // @ts-expect-error
                self.hook(...indicator);
            },
        });
    }

    if (menu) {
        menu = Revealer({
            transition: 'slide_down',
            child: menu,
            reveal_child: Activated.bind(),
        });
    }

    const widget = Box({
        vertical: true,
        children: [
            Box({
                class_name: 'grid-button',
                children: [

                    CursorBox({
                        class_name: 'left-part',

                        on_primary_click_release: () => {
                            if (Activated.value) {
                                secondary_command();
                            }
                            else {
                                command();
                            }
                        },

                        child: iconWidget,
                    }),

                    CursorBox({
                        class_name: 'right-part',

                        on_primary_click_release: () => {
                            ButtonStates.forEach((state) => {
                                if (state !== Activated) {
                                    state.value = false;
                                }
                            });
                            Activated.value = !Activated.value;
                        },

                        on_hover: (self) => {
                            if (menu) {
                                const rowMenu =
                                    self.get_parent()
                                        ?.get_parent()
                                        ?.get_parent()
                                        ?.get_parent()
                                        // @ts-expect-error
                                        ?.children[1];

                                const isSetup = rowMenu.get_children().find(
                                    /** @param {Box} ch */
                                    (ch) => ch === menu,
                                );

                                if (!isSetup) {
                                    rowMenu.add(menu);
                                    rowMenu.show_all();
                                }
                            }
                        },

                        child: Icon({
                            icon: `${App.configDir }/icons/down-large.svg`,
                            class_name: 'grid-chev',

                            setup: (self) => {
                                self.hook(Activated, () => {
                                    let deg = 270;

                                    if (Activated.value) {
                                        deg = menu ? 360 : 450;
                                        on_open(menu);
                                    }
                                    self.setCss(`
                                        -gtk-icon-transform: rotate(${deg}deg);
                                    `);
                                });
                            },
                        }),
                    }),

                ],
            }),
            indicatorWidget,
        ],
    });

    return widget;
};

const Row = ({ buttons }) => {
    const widget = Box({
        vertical: true,

        children: [
            Box({
                class_name: 'button-row',
                hpack: 'center',
            }),

            Box({ vertical: true }),
        ],
    });

    for (let i = 0; i < buttons.length; ++i) {
        if (i === buttons.length - 1) {
            // @ts-expect-error
            widget.children[0].add(buttons[i]);
        }
        else {
            // @ts-expect-error
            widget.children[0].add(buttons[i]);
            // @ts-expect-error
            widget.children[0].add(Separator(SPACING));
        }
    }

    return widget;
};

const FirstRow = () => Row({
    buttons: [

        GridButton({
            command: () => Network.toggleWifi(),

            secondary_command: () => {
                // TODO: connection editor
            },

            icon: [Network,
                /** @param {Icon} self */
                (self) => {
                    self.icon = Network.wifi?.icon_name;
                }],

            indicator: [Network,
                /** @param {Label} self */
                (self) => {
                    self.label = Network.wifi?.ssid || Network.wired?.internet;
                }],

            menu: NetworkMenu(),
            on_open: () => Network.wifi.scan(),
        }),

        // TODO: do vpn
        GridButton({
            command: () => {
                //
            },

            secondary_command: () => {
                //
            },

            icon: 'airplane-mode-disabled-symbolic',
        }),

        GridButton({
            command: () => Bluetooth.toggle(),

            secondary_command: () => {
                // TODO: bluetooth connection editor
            },

            icon: [Bluetooth,
                /** @param {Icon} self */
                (self) => {
                    if (Bluetooth.enabled) {
                        self.icon = Bluetooth.connected_devices[0] ?
                            Bluetooth.connected_devices[0].icon_name :
                            'bluetooth-active-symbolic';
                    }
                    else {
                        self.icon = 'bluetooth-disabled-symbolic';
                    }
                }],

            indicator: [Bluetooth,
                /** @param {Label} self */
                (self) => {
                    self.label = Bluetooth.connected_devices[0] ?
                        `${Bluetooth.connected_devices[0]}` :
                        'Disconnected';
                }, 'notify::connected-devices'],

            menu: BluetoothMenu(),
            on_open: (menu) => {
                execAsync(`bluetoothctl scan ${menu.reveal_child ?
                    'on' :
                    'off'}`).catch(print);
            },
        }),

    ],
});

const SecondRow = () => Row({
    buttons: [
        GridButton({
            command: () => {
                execAsync(['pactl', 'set-sink-mute',
                    '@DEFAULT_SINK@', 'toggle']).catch(print);
            },

            secondary_command: () => {
                execAsync(['bash', '-c', 'pavucontrol'])
                    .catch(print);
            },

            icon: [SpeakerIcon,
                /** @param {Icon} self */
                (self) => {
                    self.icon = SpeakerIcon.value;
                }],
        }),

        GridButton({
            command: () => {
                execAsync(['pactl', 'set-source-mute',
                    '@DEFAULT_SOURCE@', 'toggle']).catch(print);
            },

            secondary_command: () => {
                execAsync(['bash', '-c', 'pavucontrol'])
                    .catch(print);
            },

            icon: [MicIcon,
                /** @param {Icon} self */
                (self) => {
                    self.icon = MicIcon.value;
                }],
        }),

        GridButton({
            command: () => {
                execAsync(['lock']).catch(print);
            },
            secondary_command: () => App.openWindow('powermenu'),
            icon: 'system-lock-screen-symbolic',
        }),
    ],
});

export default () => Box({
    class_name: 'button-grid',
    vertical: true,
    hpack: 'center',
    children: [
        FirstRow(),
        Separator(10, { vertical: true }),
        SecondRow(),
    ],
});