const _ = require('lodash');
const responseContext = require('../../lib/responseContext');
const sendHandledRequest = require('../../lib/sendHandledRequest');
const stackResponse = require('../../lib/stackResponse');

const BASIC_FIELDS = [
    'id', 'label', 'name', 'admin_id',
];
const BASIC_FIELDS_WITH_DOMAINS = [
    'id', 'label', 'name', 'admin_id', 'domains',
];
const EXTENDED_FIELDS = [
    'id', 'label', 'name', 'organization_type', 'vip',
    'admin_id', 'language', 'country', 'head_id',
    'domains', 'services', 'has_owned_domains', 'can_users_change_password',
    'subscription_plan', 'subscription_plan_expires_at', 'partner_id',
    'logo', 'header', 'email', 'phone_number', 'fax',
    'root_departments.name', 'is_blocked',
];

const UNCHANGED_SERVICES = [
    {
        user_limit: null,
        enabled: true,
        expires_at: null,
        trial: {
            status: 'inapplicable',
            expiration_date: null,
            days_till_expiration: null,
        },
        ready: true,
        slug: 'webmaster',
    },
];

function readList(req, res, next) {
    const fields = _.get(req, 'query.domain') ? BASIC_FIELDS_WITH_DOMAINS : BASIC_FIELDS;

    return sendHandledRequest({
        method: 'get',
        url: [req.config.api.directory, 'v8', 'organizations'],
        query: {
            fields: fields.join(','),
        },
        source: req,
        label: 'read_organization_list',
    })
        .then(response => {
            req.context = req.context || {};
            req.context.organizations = _.get(response, 'result', response);

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

function readDetails(req, res, next) {
    const url = [req.config.api.directory, 'v8', 'organizations'];
    const orgId = req.query.id;

    if (orgId) {
        url.push({ value: orgId, type: 'number' });
    }

    return sendHandledRequest({
        method: 'get',
        url,
        query: {
            fields: req.query.org_fields || EXTENDED_FIELDS.join(','),
        },
        source: req,
        label: 'read_organization_services',
    })
        .then(response => {
            req.context = req.context || {};

            response.services = _.get(response, 'result', response).services.concat(UNCHANGED_SERVICES);

            if (orgId) {
                const currentOrg = _.find(
                    req.context.organizations,
                    org => String(org.id) === String(orgId)
                );

                if (!currentOrg) {
                    req.context.organizations = req.context.organizations || [];
                    req.context.organizations.push(response);
                } else {
                    _.merge(currentOrg, response);
                }
            } else {
                req.context.organizations = _.merge(
                    req.context.organizations,
                    _.get(response, 'result', response)
                );
            }

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

function read(req, res, next) {
    const currentOrgId = String(req.context.headers['x-org-id']);

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

            if (currentOrg && !currentOrg.services) {
                const originalQuery = _.clone(req.query);

                req.query = { id: currentOrgId };

                // дозапрашиваем сервисы для текущей организации;
                // для остальных организаций сервисы не запрашиваем
                return readDetails(req, res)
                    .then(() => {
                        req.query = originalQuery;
                    });
            }
        })
        .then(() => next ? next() : req)
        .catch(next);
}

function update(req, res, next) {
    return sendHandledRequest({
        method: 'patch',
        url: [req.config.api.directory, 'organization'],
        source: req,
        label: 'update_organization',
    })
        .then(() => read(req, res, next))
        .catch(next);
}

function create(req, res, next) {
    return sendHandledRequest({
        method: 'post',
        url: [req.config.api.directory, 'organization'],
        source: req,
        label: 'create_organization',
        timeout: 15000, // увеличиваем таймаут до 15с чтобы точно проходили все дорегистрации
    })
        .then(organization => {
            stackResponse(req.context, 'organizations', organization);

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

function createOrganizationWithoutDomain(req, res, next) {
    const { uid } = req.body;
    const body = _.omit(req.body, ['uid']);

    if (!responseContext.hasSession(req, uid)) {
        return res.sendStatus(403);
    }

    const headers = _.extend({}, _.omit(req.context.headers, ['x-org-id']), { 'x-uid': uid });

    return sendHandledRequest({
        method: 'post',
        url: [req.config.api.directory, 'v8', 'organization', 'without-domain'],
        body,
        headers,
        source: req,
        timeout: 15000,
        label: 'create_organization_without_domain',
    })
        .then(organization => {
            req.context.added_organization = organization;

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

function bindOrganizationWithResource(req, res, next) {
    const headers = _.extend({}, _.omit(req.context.headers, ['x-org-id']));

    return sendHandledRequest({
        method: 'post',
        url: [req.config.api.directory, 'v9', 'bind'],
        body: req.body,
        query: {
            'dry-run': req.query['dry-run'],
        },
        headers,
        source: req,
        timeout: 15000,
        label: 'bind_organization_with_resource',
    })
        .then(bind => {
            req.context.bind_organization = bind;

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

function readOrganizationsToBind(req, res, next) {
    const headers = _.extend({}, _.omit(req.context.headers, ['x-org-id']));

    return sendHandledRequest({
        method: 'post',
        url: [req.config.api.directory, 'v11', 'bind', 'organizations'],
        body: req.body,
        headers,
        source: req,
        timeout: 15000,
        label: 'read_organizations_to_bind',
    })
        .then(bind => {
            req.context.organizations_to_bind = bind;

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

function addDomain(req, res, next) {
    return sendHandledRequest({
        method: 'post',
        url: [req.config.api.directory, 'v8', 'organization', 'with-domain'],
        source: req,
        timeout: 30000,
        label: 'add_domain',
    })
        .then(organization => {
            req.context.added_organization = organization;

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

function updateDefaultUid(req, res, next) {
    const defaultUid = _.get(req.body, 'default_uid');

    return sendHandledRequest({
        method: 'patch',
        url: [req.config.api.directory, 'v10', 'organization'],
        source: req,
        label: 'change_default_email',
    })
        .then(response => {
            req.context.organizationSettings = {
                default_uid: defaultUid,
            };

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

function remove(req, res, next) {
    const orgId = req.query.id || _.get(req.context.headers, 'x-org-id');

    return sendHandledRequest({
        method: 'delete',
        url: [req.config.api.directory, 'v8', 'organizations', orgId],
        source: req,
        timeout: 15000,
        label: 'delete_organization',
    })
        .then(() => next ? next() : req)
        .catch(next);
}

module.exports = {
    read,
    readList,
    readDetails,
    update,
    create,
    createOrganizationWithoutDomain,
    bindOrganizationWithResource,
    readOrganizationsToBind,
    updateDefaultUid,
    addDomain,
    remove,
};
