import qs from 'qs';
import { assign, each, isArray, isArrayLike, isFunction, merge } from 'lodash';
import { Collection } from '~/classes/base/Collection';
import ActionResponse from './ActionResponse.mjs';
import ActionsResponses from './ActionsResponses.mjs';
export class Action
{
    route = null;
    parameters = null;
    files = [];
    handler = null;

    constructor(data) {
        let index;

        merge(this, assign({}, data));

        if (FileList && data.files instanceof FileList) {
            for (index = 0; index < data.files.length; index++)
                this.files.push(data.files[index]);
        } else if (isArrayLike(data.files)) {
            this.files = data.files;
        }
    }
    hasHandler() {
        return isFunction(this.handler)
    }
    handle(context, data) {
        if (this.hasHandler())
            return this.handler.call(context, data);

        return data;
    }
    run() {
        const actions = new Actions([this]);

        return new Promise(function (resolve, reject) {
            actions.run().then(function (actions) {
                resolve(actions[0]);
            }, function (reason) {
                if (reason instanceof ActionsResponses) {
                    reject(reason[0]);
                } else {
                    reject(reason);
                }
            });
        });
    }
}
export class Actions extends Collection
{
    run = function () {
        if (this.length === 0)
            return Promise.resolve([]);

        const actions = [];

        each(this, function (action) {
            actions.push(action);
        });

        const url = application.options.template.directory + 'request.php?' + qs.stringify({
            siteId: application.options.site.id,
            templateId: application.options.template.id
        });

        return new Promise(function (resolve, reject) {
            const requests = [];
            const results = [];
            let data;

            each(actions, action => {
                if (action instanceof Action) {
                    requests.push({
                        route: action.route,
                        parameters: JSON.stringify(action.parameters)
                    });
                } else {
                    requests.push({
                        route: null,
                        parameters: null
                    });
                }
            });

            if (window.FormData) {
                data = new FormData();

                if (typeof BX !== 'undefined' && BX.bitrix_sessid)
                    data.append('sessid', BX.bitrix_sessid());

                each(requests, function (request, index) {
                    const action = actions[index];

                    data.append('actions[' + index + '][route]', request.route);
                    data.append('actions[' + index + '][parameters]', request.parameters);

                    if (window.File)
                        each(action.files, function (file) {
                            if (file instanceof window.File)
                                data.append('actions[' + index + '][files][]', file);
                        });
                });
            } else {
                const body = { actions: requests };

                if (typeof BX !== 'undefined' && BX.bitrix_sessid)
                    body.sessid = BX.bitrix_sessid();

                data = qs.stringify(body);
            }

            application.request('post', url, data, {
                headers: {
                    'X-Requested-With': 'XMLHttpRequest'
                }
            }).then(function (responses) {
                if (!isArray(responses.data) || actions.length !== responses.data.length) {
                    each(actions, function () {
                        results.push(new ActionResponse({
                            code: 'badResponse',
                            data: null,
                            message: 'Bad response',
                            status: 'error'
                        }));
                    });

                    reject(new ActionsResponses(results));
                } else {
                    each(actions, function (action, index) {
                        const response = new ActionResponse(responses.data[index]);

                        if (action instanceof Action) {
                            response.action = action;
                            response.data = action.handle(response, response.data);
                        }

                        results.push(response);
                    });

                    resolve(new ActionsResponses(results));
                }
            }, function (reason) {
                each(actions, function () {
                    results.push(new ActionResponse({
                        code: 'networkError',
                        data: reason,
                        message: 'Network error',
                        status: 'error'
                    }));
                });

                reject(new ActionsResponses(results));
            });
        }).then(function (responses) {
            if (!responses.isSuccess())
                throw responses;

            return responses;
        })
    }
    verify(item) {
        return item instanceof Action;
    }
}