const _ = require('lodash');
const sendHandledRequest = require('../../lib/sendHandledRequest');
const user = require('./user');
const organization = require('./organization');
const rolesMock = require('./roles.mock');

const REQUEST_FIELDS = ['comment', 'user', 'user.name', 'user.position'];

function getResponsible(req, res, next) {
    const { service } = req.query;

    const originalQuery = _.clone(req.query);
    const currentOrgId = String(req.context.headers['x-org-id']);

    req.query = {
        id: currentOrgId,
        org_fields: 'services.responsible',
    };

    return organization.readDetails(req, res)
        .then(() => {
            const currentOrg = _.find(
                req.context.organizations,
                org => String(org.id) === currentOrgId
            );

            const responsibleId = _.get(
                _.find(_.get(currentOrg, 'services'), item => item.slug === service),
                ['responsible', 'id']
            );

            if (responsibleId) {
                _.set(req.context, ['resources', service, 'responsible'], String(responsibleId));

                const responsible = _.get(req.context, ['users', responsibleId]);

                if (!responsible) {
                    req.query = {
                        id: responsibleId,
                    };

                    return user.read(req, res);
                }
            }
        })
        .then(() => {
            req.query = originalQuery;

            if (next) {
                return next();
            }
        })
        .catch(next);
}

function read(req, res, next) {
    const { service } = req.query;

    return sendHandledRequest({
        method: 'get',
        url: [req.config.api.directory, 'v10', 'resources'],
        query: Object.assign({ per_page: 1000 }, req.query),
        source: req,
        label: 'read_resources',
    })
        .then(resources => {
            const resourceList = _.get(resources, 'result');
            const resourceMap = resourceList.reduce((map, item) => {
                map[item.id] = item;

                return map;
            }, {});

            _.set(req.context, ['resources', service, 'list'], resourceMap);

            if (!req.context.users) {
                req.context.users = {};
            }

            return getResponsible(req, res)
                .then(() => next ? next() : resources);
        })
        .catch(next);
}

function count(req, res, next) {
    return sendHandledRequest({
        method: 'get',
        url: [req.config.api.directory, 'v10', 'resources', 'count'],
        source: req,
        label: 'read_resources',
    })
        .then(response => {
            _.set(req.context, ['resources', req.query.service, 'count'], _.get(response, 'count'));

            return next ? next() : response;
        })
        .catch(next);
}

function roles(req, res, next) {
    const { service, resource_id: resourceId } = req.query;
    const { env } = req.config.app;

    let request = sendHandledRequest({
        method: 'get',
        url: [req.config.api.directory, 'v10', 'services', service, 'roles'],
        source: req,
        label: 'read_roles',
    });

    if (env === 'development' || env === 'testing') {
        request = Promise.resolve(rolesMock);
    }

    return request
        .then(response => {
            req.context.roles = {
                service,
                resourceId,
                items: response.data,
            };

            return next ? next() : response;
        })
        .catch(next);
}

function remove(req, res, next) {
    const { resource_id: resourceId } = req.query;

    return sendHandledRequest({
        method: 'delete',
        url: [req.config.api.directory, 'v10', 'resources', resourceId],
        source: req,
        label: 'remove_resource',
    })
        .then(response => next ? next() : response)
        .catch(next);
}

function readRelations(req, res, next) {
    const { service, resource_id: resourceId } = req.query;

    return sendHandledRequest({
        method: 'get',
        url: `${req.config.api.directory}/v10/resources/${encodeURIComponent(resourceId)}/relations/`,
        source: req,
        label: 'read_relations',
    })
        .then(response => {
            const info = {
                service,
                resourceId,
                items: response,
            };

            _.set(req.context, ['relations'], info);

            if (!req.context.users) {
                req.context.users = {};
            }

            for (let relation of response) {
                if (relation.object_type === 'user') {
                    const { id } = relation.object;

                    req.context.users[id] = _.merge(req.context.users[id], relation.object);
                }
            }

            return next ? next() : response;
        })
        .catch(next);
}

function createRelation(req, res, next) {
    return sendHandledRequest({
        method: 'post',
        url: [req.config.api.directory, 'v10', 'relations'],
        source: req,
        label: 'create_relation',
    })
        .then(response => {
            const originalQuery = _.clone(req.query);

            req.query = _.pick(req.body, 'service', 'resource_id');

            return readRelations(req, res)
                .then(() => {
                    req.query = originalQuery;

                    return next ? next() : response;
                });
        })
        .catch(next);
}

function removeRelation(req, res, next) {
    const { id, service } = req.body;

    return sendHandledRequest({
        method: 'delete',
        url: `${req.config.api.directory}/v10/relations/${encodeURIComponent(service)}/${encodeURIComponent(id)}/`,
        source: req,
        label: 'remove_relation',
    })
        .then(response => {
            const originalQuery = _.clone(req.query);

            req.query = _.pick(req.body, 'service', 'resource_id');

            return readRelations(req, res)
                .then(() => {
                    req.query = originalQuery;

                    return next ? next() : response;
                });
        })
        .catch(next);
}

function requests(req, res, next) {
    const { service, resource_id: resourceId } = req.query;

    req.query.per_page = 100;
    req.query.fields = REQUEST_FIELDS.join(',');

    return sendHandledRequest({
        method: 'get',
        url: [req.config.api.directory, 'v10', 'subscription',
            'services', service, 'licenses', 'request'],
        source: req,
        label: 'read_requests',
    })
        .then(response => {
            req.context.requests = { service, resourceId, items: response.result };

            return next ? next() : response;
        })
        .catch(next);
}

function confirmRequest(req, res, next) {
    const { service, resource_id: resourceId } = req.body;
    const originalQuery = _.clone(req.query);
    const originalBody = _.clone(req.body);

    req.query.resource_id = resourceId;
    req.body = [
        {
            type: 'user',
            id: req.body.user_id,
        },
    ];

    return sendHandledRequest({
        method: 'post',
        url: [req.config.api.directory, 'v10', 'subscription',
            'services', service, 'licenses', 'request', 'confirm'],
        source: req,
        label: 'confirm_request',
    })
        .then(response => {
            req.context.requests = { service, resourceId, items: response.result };
            req.body = originalBody;
            req.query = {
                service,
                resource_id: resourceId,
            };

            return readRelations(req, res)
                .then(() => {
                    req.query = originalQuery;

                    return next ? next() : response;
                });
        })
        .catch(next);
}

function denyRequest(req, res, next) {
    const { service, resource_id: resourceId } = req.body;

    req.query.resource_id = resourceId;
    req.body = [
        {
            type: 'user',
            id: req.body.user_id,
        },
    ];

    return sendHandledRequest({
        method: 'post',
        url: [req.config.api.directory, 'v10', 'subscription',
            'services', service, 'licenses', 'request', 'deny'],
        source: req,
        label: 'deny_request',
    })
        .then(response => {
            req.context.requests = { service, resourceId, items: response.result };

            return next ? next() : response;
        })
        .catch(next);
}

module.exports = {
    read,
    count,
    roles,
    remove,
    getResponsible,
    createRelation,
    removeRelation,
    readRelations,
    requests,
    confirmRequest,
    denyRequest,
};
