/**
 * @module utils/functions
 */
import _ from 'lodash';
import React from 'react';
import ReactDOM from 'react-dom';
import {hashHistory} from 'react-router';
import {getConfig, translate} from '../../utils';
import {readCookie} from './cookie';

/**
 * Returns a hash history
 */
export function getSilentRouterHistory() {
    if (!hashHistory._pushStatePatched) {
        hashHistory._pushStatePatched = true;
        hashHistory.pushState = function pushState(state, url) {
            if (typeof console !== 'undefined') {
                // eslint-disable-next-line
                console.error(`Warning: pushState deprecated method for hashHistory`);
            }
            return this.push(url);
        };
    }
    return hashHistory;
}

/**
 * Changes document title
 * @TODO Replace with React Helmet
 * @param title
 */
export function setDocumentTitle(title) {
    let suffix = getConfig().headerAccountBlock || getConfig().brandDisplayName;
    document.title = title + ' - ' + suffix;
}

/**
 * @param val
 * @return {boolean}
 */
export function isReactComponent(val) {
    return val instanceof React.Component.constructor;
}

/**
 * @param val
 * @return {*|boolean}
 */
export function isReactElement(val) {
    return React.isValidElement(val);
}

/**
 * @param {React.Element} element
 * @param {constructor} type
 * @return {boolean}
 * @example isElementHasType(tabPanelChild, NavDropdown)
 */
export function isElementHasType(element, type) {
    return element.type === type || element.type.prototype instanceof type;
}

/**
 * Filters empty [null, undefined] children of React component
 * @param {ReactNode} children
 * @returns {React.ReactChild[]}
 */
export function cleanEmptyChildren(children) {
    return React.Children.toArray(children).filter(Boolean);
}

/**
 * @param Component
 * @param container
 * @param params
 */
export function mountComponent(Component, container, params) {
    let element;
    //FIXME React Router needs to be created from scratch otherwise a previous state is picked up
    //FIXME Replace all existing routers with router factory functions
    if (typeof Component === 'function' && Component.name === 'createRouter') {
        Component = Component();
    }
    if (isReactElement(Component)) {
        element = Component;
    } else if (isReactComponent(Component)) {
        element = React.createElement(Component, params);
    }

    if (!React.isValidElement(element)) {
        // eslint-disable-next-line
        console.error('Cannot render invalid React element', Component);
        throw new Error('Cannot render invalid React element');
    }

    // eslint-disable-next-line react/no-render-return-value
    return ReactDOM.render(element, container);
}

/**
 * @return {boolean}
 */
export function isAutomationTestActive() {
    return !!readCookie('automationFlow');
}

/**
 * @param value
 * @return {boolean}
 */
export function isSafeStringValue(value) {
    if (value.length > 0) {
        return (
            value.indexOf('"') === -1 &&
            value.indexOf('/') === -1 &&
            value.indexOf('<') === -1 &&
            value.indexOf('>') === -1 &&
            value.indexOf('&') === -1
        );
    } else {
        return true;
    }
}

//PC userAgent: "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36"
//MAC userAgent: ""
export let OS = {
    is: {
        mac: /mac\sos\sx/i.test(navigator.userAgent),
        win: /windows/i.test(navigator.userAgent)
    },
    name: 'others'
};
OS.is.others = !Object.keys(OS.is).some(o => {
    if (OS.is[o]) {
        OS.name = o;
        return true;
    }
});

/**
 * @param str
 * @return {*}
 */
export function fillBrandName(str) {
    return translate(str, {brandName: getConfig().shortBrandName});
}

/**
 * @param prevState
 * @param newState
 * @return {*}
 */
export function extendFormState(prevState, newState) {
    return _.merge(prevState, newState);
}

/**
 * @param prevState
 * @param removedIds
 * @return {*|{}}
 */
export function cleanFormState(prevState, removedIds) {
    return _.omit(prevState, removedIds);
}

export function wait(mileSeconds) {
    return new Promise(resolve => {
        setTimeout(resolve, mileSeconds);
    });
}

export function deprecation(Component, message) {
    const name = Component.displayName || Component.name || 'Component';

    class Deprecated extends React.Component {
        static displayName = `Deprecated(${name})`;

        componentDidMount() {
            // eslint-disable-next-line no-console
            console.warn(`Component ${name} is deprecated.`, message || '');
        }

        render() {
            return <Component {...this.props} />;
        }
    }

    return Deprecated;
}

const KEY_CODE_ENTER = 13;
const KEY_CODE_SPACE = 32;
const defaultKeyCodesFilter = [KEY_CODE_ENTER, KEY_CODE_SPACE];

export const filterKeyCodes = (callback, keyCodes = defaultKeyCodesFilter) => ({keyCode}) => {
    if (_.includes(keyCodes, keyCode)) {
        callback();
    }
};

export const scrollEelementIntoView = elementRef => {
    const $element = ReactDOM.findDOMNode(elementRef);

    if ($element && typeof $element.scrollIntoView === 'function') {
        $element.scrollIntoView({behavior: 'smooth'});
    }
};

export const stripTags = string => string.replace(/(<([^>]+)>)/gi, '');
