const { Gdk, Gtk } = imports.gi;
import App from 'resource:///com/github/Aylur/ags/app.js';
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';

import Applications from 'resource:///com/github/Aylur/ags/service/applications.js';
const { execAsync, exec } = Utils;
import { execAndClose, expandTilde, hasUnterminatedBackslash, couldBeMath, launchCustomCommand, ls } from './miscfunctions.js';
import {
    CalculationResultButton, CustomCommandButton, DirectoryButton,
    DesktopEntryButton, ExecuteCommandButton, SearchButton
} from './searchbuttons.js';
import { checkKeybind } from '../.widgetutils/keybind.js';

// Add math funcs
const { abs, sin, cos, tan, cot, asin, acos, atan, acot } = Math;
const pi = Math.PI;
// trigonometric funcs for deg
const sind = x => sin(x * pi / 180);
const cosd = x => cos(x * pi / 180);
const tand = x => tan(x * pi / 180);
const cotd = x => cot(x * pi / 180);
const asind = x => asin(x) * 180 / pi;
const acosd = x => acos(x) * 180 / pi;
const atand = x => atan(x) * 180 / pi;
const acotd = x => acot(x) * 180 / pi;

const MAX_RESULTS = 10;
const OVERVIEW_SCALE = 0.18; // = overview workspace box / screen size
const OVERVIEW_WS_NUM_SCALE = 0.0;
const OVERVIEW_WS_NUM_MARGIN_SCALE = 0.07;
const TARGET = [Gtk.TargetEntry.new('text/plain', Gtk.TargetFlags.SAME_APP, 0)];

function iconExists(iconName) {
    let iconTheme = Gtk.IconTheme.get_default();
    return iconTheme.has_icon(iconName);
}

const OptionalOverview = async () => {
    try {
        return (await import('./overview_hyprland.js')).default();
    } catch {
        return Widget.Box({});
        // return (await import('./overview_hyprland.js')).default();
    }
};

const overviewContent = await OptionalOverview();

export const SearchAndWindows = () => {
    var _appSearchResults = [];

    const ClickToClose = ({ ...props }) => Widget.EventBox({
        ...props,
        onPrimaryClick: () => App.closeWindow('overview'),
        onSecondaryClick: () => App.closeWindow('overview'),
        onMiddleClick: () => App.closeWindow('overview'),
    });
    const resultsBox = Widget.Box({
        className: 'overview-search-results',
        vertical: true,
        vexpand: true,
    });
    const resultsRevealer = Widget.Revealer({
        transitionDuration: userOptions.animations.durationLarge,
        revealChild: false,
        transition: 'slide_down',
        // duration: 200,
        hpack: 'center',
        child: resultsBox,
    });
    const entryPromptRevealer = Widget.Revealer({
        transition: 'crossfade',
        transitionDuration: userOptions.animations.durationLarge,
        revealChild: true,
        hpack: 'center',
        child: Widget.Label({
            className: 'overview-search-prompt txt-small txt',
            label: 'Type to search'
        }),
    });

    const entryIconRevealer = Widget.Revealer({
        transition: 'crossfade',
        transitionDuration: userOptions.animations.durationLarge,
        revealChild: false,
        hpack: 'end',
        child: Widget.Label({
            className: 'txt txt-large icon-material overview-search-icon',
            label: ' ',
        }),
    });

    const entryIcon = Widget.Box({
        className: 'overview-search-prompt-box',
        setup: box => box.pack_start(entryIconRevealer, true, true, 0),
    });

    const entry = Widget.Entry({
        className: 'overview-search-box txt-small txt',
        hpack: 'center',
        onAccept: (self) => { // This is when you hit Enter
            const text = self.text;
            if (text.length == 0) return;
            const isAction = text.startsWith('>');
            const isDir = (['/', '~'].includes(entry.text[0]));

            if (couldBeMath(text)) { // Eval on typing is dangerous, this is a workaround
                try {
                    const fullResult = eval(text.replace(/\^/g, "**"));
                    // copy
                    execAsync(['wl-copy', `${fullResult}`]).catch(print);
                    App.closeWindow('overview');
                    return;
                } catch (e) {
                    // console.log(e);
                }
            }
            if (isDir) {
                App.closeWindow('overview');
                execAsync(['bash', '-c', `xdg-open "${expandTilde(text)}"`, `&`]).catch(print);
                return;
            }
            if (_appSearchResults.length > 0) {
                App.closeWindow('overview');
                _appSearchResults[0].launch();
                return;
            }
            else if (text[0] == '>') { // Custom commands
                App.closeWindow('overview');
                launchCustomCommand(text);
                return;
            }
            // Fallback: Execute command
            if (!isAction && exec(`bash -c "command -v ${text.split(' ')[0]}"`) != '') {
                if (text.startsWith('sudo'))
                    execAndClose(text, true);
                else
                    execAndClose(text, false);
            }

            else {
                App.closeWindow('overview');
                execAsync(['bash', '-c', `xdg-open '${userOptions.search.engineBaseUrl}${text} ${['', ...userOptions.search.excludedSites].join(' -site:')}' &`]).catch(print);
            }
        },
        onChange: (entry) => { // this is when you type
            const isAction = entry.text[0] == '>';
            const isDir = (['/', '~'].includes(entry.text[0]));
            resultsBox.get_children().forEach(ch => ch.destroy());

            // check empty if so then dont do stuff
            if (entry.text == '') {
                resultsRevealer.revealChild = false;
                overviewContent.revealChild = true;
                entryPromptRevealer.revealChild = true;
                entryIconRevealer.revealChild = false;
                entry.toggleClassName('overview-search-box-extended', false);
                return;
            }
            const text = entry.text;
            resultsRevealer.revealChild = true;
            overviewContent.revealChild = false;
            entryPromptRevealer.revealChild = false;
            entryIconRevealer.revealChild = true;
            entry.toggleClassName('overview-search-box-extended', true);
            _appSearchResults = Applications.query(text);

            // Calculate
            if (couldBeMath(text)) { // Eval on typing is dangerous; this is a small workaround.
                try {
                    const fullResult = eval(text.replace(/\^/g, "**"));
                    resultsBox.add(CalculationResultButton({ result: fullResult, text: text }));
                } catch (e) {
                    // console.log(e);
                }
            }
            if (isDir) {
                var contents = [];
                contents = ls({ path: text, silent: true });
                contents.forEach((item) => {
                    resultsBox.add(DirectoryButton(item));
                })
            }
            if (isAction) { // Eval on typing is dangerous, this is a workaround.
                resultsBox.add(CustomCommandButton({ text: entry.text }));
            }
            // Add application entries
            let appsToAdd = MAX_RESULTS;
            _appSearchResults.forEach(app => {
                if (appsToAdd == 0) return;
                resultsBox.add(DesktopEntryButton(app));
                appsToAdd--;
            });

            // Fallbacks
            // if the first word is an actual command
            if (!isAction && !hasUnterminatedBackslash(text) && exec(`bash -c "command -v ${text.split(' ')[0]}"`) != '') {
                resultsBox.add(ExecuteCommandButton({ command: entry.text, terminal: entry.text.startsWith('sudo') }));
            }

            // Add fallback: search
            resultsBox.add(SearchButton({ text: entry.text }));
            resultsBox.show_all();
        },
    });
    return Widget.Box({
        vertical: true,
        children: [
            ClickToClose({ // Top margin. Also works as a click-outside-to-close thing
                child: Widget.Box({
                    className: 'bar-height',
                })
            }),
            Widget.Box({
                hpack: 'center',
                children: [
                    entry,
                    Widget.Box({
                        className: 'overview-search-icon-box',
                        setup: (box) => {
                            box.pack_start(entryPromptRevealer, true, true, 0)
                        },
                    }),
                    entryIcon,
                ]
            }),
            overviewContent,
            resultsRevealer,
        ],
        setup: (self) => self
            .hook(App, (_b, name, visible) => {
                if (name == 'overview' && !visible) {
                    resultsBox.children = [];
                    entry.set_text('');
                }
            })
            .on('key-press-event', (widget, event) => { // Typing
                const keyval = event.get_keyval()[1];
                const modstate = event.get_state()[1];
                if (checkKeybind(event, userOptions.keybinds.overview.altMoveLeft))
                    entry.set_position(Math.max(entry.get_position() - 1, 0));
                else if (checkKeybind(event, userOptions.keybinds.overview.altMoveRight))
                    entry.set_position(Math.min(entry.get_position() + 1, entry.get_text().length));
                else if (checkKeybind(event, userOptions.keybinds.overview.deleteToEnd)) {
                    const text = entry.get_text();
                    const pos = entry.get_position();
                    const newText = text.slice(0, pos);
                    entry.set_text(newText);
                    entry.set_position(newText.length);
                }
                else if (!(modstate & Gdk.ModifierType.CONTROL_MASK)) { // Ctrl not held
                    if (keyval >= 32 && keyval <= 126 && widget != entry) {
                        Utils.timeout(1, () => entry.grab_focus());
                        entry.set_text(entry.text + String.fromCharCode(keyval));
                        entry.set_position(-1);
                    }
                }
            })
        ,
    });
}; 
