/* global CloudCmd, DOM */
import exec from 'execon';
import wrap from 'wraptile';
import createElement from '@cloudcmd/create-element';
import {getIdBySrc} from '#dom/load';
import * as RESTful from '#dom/rest';
import {FS} from '#common/cloudfunc';

const {config, Key} = CloudCmd;

const {
    Buffer,
    Events,
    Dialog,
    Images,
} = DOM;

const Info = DOM.CurrentInfo;
const alertNoFiles = Dialog.alert.noFiles;
const uploadTo = wrap(_uploadTo);

let MenuShowedName;
let MenuContext;
let MenuContextFile;

export const ENABLED = false;

CloudCmd.Menu = {
    init,
    show,
    hide,
};

export async function init() {
    const {isAuth, menuDataFile} = getFileMenuData();
    
    const fm = DOM.getFM();
    const menuData = getMenuData(isAuth);
    
    const options = getOptions({
        type: 'context',
    });
    
    const optionsFile = getOptions({
        type: 'file',
    });
    
    const {createCloudMenu} = await import('./cloudmenu.js');
    
    const {name} = fm.dataset;
    
    MenuContext = await createCloudMenu(name, options, menuData);
    MenuContextFile = await createCloudMenu(name, optionsFile, menuDataFile);
    
    MenuContext.addContextMenuListener();
    MenuContextFile.addContextMenuListener();
    
    Events.addKey(listener);
}

export function hide() {
    MenuContext.hide();
    MenuContextFile.hide();
}

export function show(position) {
    const {x, y} = getPosition(position);
    
    MenuContext.show(x, y);
    MenuContextFile.show(x, y);
    
    Images.hide();
}

function getPosition(position) {
    if (position)
        return {
            x: position.x,
            y: position.y,
        };
    
    return getCurrentPosition();
}

function getMenuNameByEl(el) {
    if (!el)
        return 'context';
    
    const name = DOM.getCurrentName(el);
    
    if (name === '..')
        return 'context';
    
    return 'contextFile';
}

function getOptions({type}) {
    let name;
    let func;
    
    if (type === 'context') {
        name = 'context';
        func = Key.unsetBind;
    } else if (type === 'file') {
        name = 'contextFile';
    }
    
    const options = {
        icon: true,
        infiniteScroll: false,
        beforeClose: Key.setBind,
        beforeHide: Key.setBind,
        beforeShow: exec.with(beforeShow, func),
        beforeClick,
        name,
    };
    
    return options;
}

function getMenuData(isAuth) {
    const menu = {
        'Paste': Buffer.paste,
        'New': {
            File: DOM.promptNewFile,
            Directory: DOM.promptNewDir,
        },
        'Upload': () => {
            CloudCmd.Upload.show();
        },
        'Upload From Cloud': uploadFromCloud,
        'Toggle File Selection': DOM.toggleSelectedFile,
        '(Un)Select All': DOM.toggleAllSelectedFiles,
    };
    
    if (isAuth)
        menu['Log Out'] = CloudCmd.logOut;
    
    return menu;
}

function getFileMenuData() {
    const isAuth = CloudCmd.config('auth');
    
    const menuBottom = getMenuData(isAuth);
    const menuTop = {
        'View': () => {
            CloudCmd.View.show();
        },
        'Edit': () => {
            const name = config('vim') ? 'EditFileVim' : 'EditFile';
            CloudCmd[name].show();
        },
        'Rename': () => {
            setTimeout(DOM.renameCurrent, 100);
        },
        'Delete': () => {
            CloudCmd.Operation.show('delete');
        },
        'Pack': () => {
            CloudCmd.Operation.show('pack');
        },
        'Extract': () => {
            CloudCmd.Operation.show('extract');
        },
        'Download': preDownload,
        'Upload To Cloud': uploadTo('Cloud'),
        'Cut': () => {
            isCurrent(Buffer.cut, alertNoFiles);
        },
        'Copy': () => {
            isCurrent(Buffer.copy, alertNoFiles);
        },
    };
    
    const menuDataFile = {
        ...menuTop,
        ...menuBottom,
    };
    
    return {
        isAuth,
        menuDataFile,
    };
}

function isCurrent(yesFn, noFn) {
    if (Info.name !== '..')
        return yesFn();
    
    noFn();
}

function isPath(x, y) {
    const {panel} = Info;
    const isEmptyRoot = !panel;
    
    if (isEmptyRoot)
        return false;
    
    const el = document.elementFromPoint(x, y);
    const elements = panel.querySelectorAll('[data-name="js-path"] *');
    
    return !~[].indexOf.call(elements, el);
}

function beforeShow(callback, params) {
    Key.unsetBind();
    
    const {
        name,
        position = {
            x: params.x,
            y: params.y,
        },
    } = params;
    
    const {x, y} = position;
    
    const el = DOM.getCurrentByPosition({
        x,
        y,
    });
    
    const menuName = getMenuNameByEl(el);
    
    let isShow = menuName !== 'contextFile';
    
    if (params.name === 'contextFile')
        isShow = !isShow;
    
    if (isShow)
        MenuShowedName = name;
    
    exec(callback);
    
    if (isShow)
        isShow = isPath(x, y);
    
    return isShow;
}

const beforeClick = (name) => MenuShowedName !== name;

async function _uploadTo(nameModule) {
    const [error, data] = await Info.getData();
    
    if (error)
        return;
    
    const {name} = Info;
    
    CloudCmd.execFromModule(nameModule, 'uploadFile', name, data);
    CloudCmd.log(`Uploading to ${name}...`);
}

function uploadFromCloud() {
    Images.show.load('top');
    
    CloudCmd.execFromModule('Cloud', 'saveFile', async (currentName, data) => {
        const path = DOM.getCurrentDirPath() + currentName;
        const [e] = await RESTful.write(path, data);
        
        if (e)
            return;
        
        await CloudCmd.refresh({
            currentName,
        });
    });
}

function preDownload() {
    download(config('packer'));
}

function download(type) {
    const TIME = 30 * 1000;
    const {prefixURL} = CloudCmd;
    const PACK = '/pack';
    const date = Date.now();
    const files = DOM.getActiveFiles();
    
    if (!files.length)
        return alertNoFiles();
    
    for (const file of files) {
        const selected = DOM.isSelected(file);
        const isDir = DOM.isCurrentIsDir(file);
        const path = DOM.getCurrentPath(file);
        
        CloudCmd.log(`downloading file ${path}...`);
        
        /*
          * if we send ajax request -
          * no need in hash so we escape #
          * and all other characters, like "%"
          */
        const encodedPath = encodeURI(path).replace(/#/g, '#');
        const id = getIdBySrc(path);
        
        let src;
        
        if (isDir)
            src = prefixURL + PACK + encodedPath + DOM.getPackerExt(type);
        else
            src = prefixURL + FS + encodedPath + '?download';
        
        const element = createElement('iframe', {
            id: id + '-' + date,
            async: false,
            className: 'hidden',
            src,
        });
        
        const {body} = document;
        const removeChild = body.removeChild.bind(body, element);
        
        setTimeout(removeChild, TIME);
        
        if (selected)
            DOM.toggleSelectedFile(file);
    }
}

function getCurrentPosition() {
    const current = Info.element;
    const rect = current.getBoundingClientRect();
    
    const position = {
        x: Math.round(rect.left + rect.width / 3),
        y: Math.round(rect.top),
    };
    
    return position;
}

function listener(event) {
    const {F9, ESC} = Key;
    
    const key = event.keyCode;
    const isBind = Key.isBind();
    
    if (key === ESC) {
        Key.setBind();
        return hide();
    }
    
    if (isBind && key === F9) {
        const position = getCurrentPosition();
        MenuContext.show(position.x, position.y);
        
        event.preventDefault();
    }
}
