const fs = require('fs');
const _ = require('lodash');
const formidable = require('formidable');
const logger = require('../../lib/logger');
const sendHandledRequest = require('../../lib/sendHandledRequest');
const userApi = require('./user');

const INITIAL_PROGRESS = [
    { stage: 'accounts-creating', state: 'in-progress' },
];

const DEFAULT_SETTINGS = {
    enable_pop: false,
    enable_imap: false,
    custom_theme: 'light',
    sign_text: '',
    show_todo: false,
    from_name: '',
};

function getDefaultUid(req) {
    const orgId = _.get(req.context, 'headers.x-org-id');

    return sendHandledRequest({
        method: 'get',
        url: `${req.config.api.directory}/v10/organizations/${orgId}/`,
        query: {
            fields: 'default_uid',
        },
        source: req,
        label: 'read_default_uid',
    })
        .then(data => data && data.default_uid);
}

function getSettings(req, res, next) {
    const orgId = _.get(req.context, 'headers.x-org-id');
    const serviceTicket = _.get(req.context, 'tvm_tickets.setter');

    const originalQuery = _.clone(req.query);

    return Promise.all([
        getDefaultUid(req)
            .catch(() => Promise.resolve(undefined)),
        sendHandledRequest({
            method: 'get',
            url: `${req.config.api.setter}/settings/${orgId}`,
            headers: {
                'X-Ya-Service-Ticket': serviceTicket,
            },
            source: req,
            label: 'read_mail_settings',
            noTrailingSlash: true,
        })
            .catch(() => ({ response: DEFAULT_SETTINGS })),
    ])
        .then(([defaultUid, settingsData]) => {
            req.context.mail_settings = Object.assign(
                settingsData.response,
                { default_uid: defaultUid }
            );

            if (defaultUid && !_.find(req.context.users, user => user.id === defaultUid)) {
                req.query = {
                    id: defaultUid,
                };

                return userApi.read(req)
                    // ошибка в этом запросе не должна мешать отдать остальные данные
                    .catch(() => {
                        logger.error(`Failed to load default_uid user data, default_uid: ${defaultUid}`);
                    });
            }
        })
        .then(() => {
            req.query = originalQuery;

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

function updateDefaultUid(req, defaultUid) {
    return sendHandledRequest({
        method: 'patch',
        url: `${req.config.api.directory}/v10/organization/`,
        body: {
            default_uid: defaultUid,
        },
        source: req,
        label: 'update_default_uid',
    });
}

function updateSettings(req, res, next) {
    const orgId = _.get(req.context, 'headers.x-org-id');
    const serviceTicket = _.get(req.context, 'tvm_tickets.setter');
    const defaultUid = _.get(req.body, 'default_uid');
    let updateDefaultUidAction = Promise.resolve();

    if (defaultUid !== undefined) {
        updateDefaultUidAction = updateDefaultUid(req, defaultUid);
    }

    return updateDefaultUidAction
        .then(() => sendHandledRequest({
            method: 'post',
            url: `${req.config.api.setter}/settings/${orgId}`,
            headers: {
                'X-Ya-Service-Ticket': serviceTicket,
            },
            body: Object.assign({}, DEFAULT_SETTINGS, _.omit(req.body, 'default_uid')),
            source: req,
            label: 'update_mail_settings',
            noTrailingSlash: true,
        }))
        .then(() => next ? next() : req)
        .catch(next);
}

function fetchDkimStatus(req, domain) {
    const serviceTicket = _.get(req.context, 'tvm_tickets.fouras');

    return sendHandledRequest({
        method: 'get',
        url: `${req.config.api.fouras}/domain/status`,
        headers: {
            'X-Ya-Service-Ticket': serviceTicket,
        },
        query: {
            domain,
        },
        source: req,
        label: 'read_dkim_status',
        noTrailingSlash: true,
    });
}

function getDkimStatus(req, res, next) {
    let domains;

    if (req.query.domain) {
        domains = [req.query.domain];
    } else {
        let currentOrgId = Number(_.get(req.context, 'state.organization'));
        let currentOrg = _.find(req.context.organizations, org => org.id === currentOrgId);

        if (currentOrg) {
            domains = _.get(currentOrg, 'domains.owned', []);
        }
    }

    return Promise.all(
        (domains || []).map(domain => fetchDkimStatus(req, domain)
            .catch(() => ({
                response: {
                    domain,
                    pending: true,
                },
            }))
        )
    )
        .then(data => {
            let domainData = {};

            data
                .filter(item => item && item.response && item.response.domain)
                .forEach(item => {
                    domainData[item.response.domain] = item.response;
                });

            req.context.dkim = domainData;

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

function enableDkim(req, res, next) {
    const serviceTicket = _.get(req.context, 'tvm_tickets.fouras');

    return Promise.all(
        req.body.domains.map(domain => sendHandledRequest({
            method: 'post',
            url: `${req.config.api.fouras}/domain/enable`,
            headers: {
                'X-Ya-Service-Ticket': serviceTicket,
            },
            body: {
                domain,
            },
            source: req,
            label: 'enable_dkim',
            noTrailingSlash: true,
        }))
    )
        .then(() => next ? next() : req)
        .catch(next);
}

function checkImportServer(req, res, next) {
    return sendHandledRequest({
        method: 'get',
        url: `${req.config.api.directory}/v8/mail-migration/check-server/`,
        source: req,
        label: 'check_mail_import_server',
    })
        .then(response => {
            req.context.mail_import = _.extend(
                req.context.mail_import || {},
                response
            );

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

function getImportStatus(req, res, next) {
    return sendHandledRequest({
        method: 'get',
        url: `${req.config.api.directory}/v8/mail-migration/`,
        source: req,
        label: 'check_mail_import_status',
    })
        .then(response => {
        // в начале процесса импорта все этапы прогресса некоторое время
        // находятся в статусе ожидания 'pending'; чтобы не попадать в эту
        // мёртвую зону, сразу переводим первый этап в статус 'in-progress'
            if (response && response.length && _.every(response, ['state', 'pending'])) {
                response[0].state = 'in-progress';
            }
            req.context.mail_import = _.extend(
                req.context.mail_import || {},
                { progress: response }
            );

            return next ? next() : response;
        })
        .catch(() => {
            req.context.mail_import = _.extend(
                req.context.mail_import || {},
                { status: 'failed' }
            );

            if (next) {
                next();
            }
        });
}

const MAX_FILE_SIZE = 100 * 1024 * 1024;

function getInitialImportProgress(req, response) {
    return _.extend(
        req.context.mail_import || {},
        // имитируем начало прогресса импорта, если задан id миграции
        req.query.mail_migration_id ? { progress: INITIAL_PROGRESS } : null,
        response
    );
}

function startFileImport(req, res, next) {
    const form = new formidable.IncomingForm();

    form.maxFieldsSize = MAX_FILE_SIZE;

    const receive = new Promise((resolve, reject) => {
        const receivedData = {};

        form.on('file', (name, file) => {
            if (name === 'migration_file') {
                receivedData[name] = file;
            }
        });

        form.on('field', (name, value) => {
            receivedData[name] = value;
        });

        form.on('end', () => {
            if (_.isEmpty(receivedData)) {
                reject();
            } else {
                resolve(receivedData);
            }
        });
    });

    const send = data => {
        const file = data.migration_file;

        if (file) {
            const suffix = String(Math.floor(1e8 * Math.random()));
            const extension = (file.type.match(/^[^\/]+\/([^\/]+)$/) || [])[1];

            data.migration_file = {
                value: fs.createReadStream(file.path),
                options: {
                    filename: `mail-import-${suffix}.${extension}`,
                    contentType: file.type,
                },
            };
        }

        return sendHandledRequest({
            method: 'post',
            url: `${req.config.api.directory}/v8/mail-migration/`,
            formData: data,
            body: null,
            source: req,
            label: 'start_mail_import_from_file',
        })
        // после отправки файла удаляем локальную копию
            .then(response => {
                if (file && fs.existsSync(file.path)) {
                    fs.unlinkSync(file.path);
                }

                return response;
            });
    };

    form.parse(req);

    return receive.then(send)
        .then(response => {
            req.context.mail_import = getInitialImportProgress(req, response);

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

function startImport(req, res, next) {
    if (!req.body || !req.body.accounts_list) {
        return startFileImport(req, res, next);
    }

    return sendHandledRequest({
        method: 'post',
        url: `${req.config.api.directory}/v8/mail-migration/`,
        source: req,
        label: 'start_mail_import_from_list',
    })
        .then(response => {
            req.context.mail_import = getInitialImportProgress(req, response);

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

module.exports = {
    getSettings,
    updateSettings,
    getDkimStatus,
    enableDkim,
    checkImportServer,
    startImport,
    getImportStatus,
};
