const jsdom = require('jsdom');
const mysql = require('mysql');
const FormData = require('form-data');

module.exports = Self => {
    Self.remoteMethodCtx('closeTicket', {
        description: 'Close tickets without response from the user',
        accessType: 'READ',
        returns: {
            type: 'object',
            root: true
        },
        http: {
            path: `/closeTicket`,
            verb: 'POST'
        }
    });

    Self.closeTicket = async ctx => {
        const models = Self.app.models;
        const config = await models.OsTicketConfig.findOne();
        const ostUri = `${config.host}/login.php`;

        if (!config.user || !config.password || !config.userDb || !config.passwordDb)
            return false;

        const con = mysql.createConnection({
            host: config.hostDb,
            user: config.userDb,
            password: config.passwordDb,
            port: config.portDb
        });

        const sql = `SELECT ot.ticket_id, ot.number
                        FROM osticket.ost_ticket ot
                            JOIN osticket.ost_ticket_status ots ON ots.id = ot.status_id
                            JOIN osticket.ost_thread ot2 ON ot2.object_id = ot.ticket_id AND ot2.object_type = 'T'
                            JOIN (
                                SELECT sub2.thread_id, sub2.type, sub2.updated, sub2.created
                                    FROM (
                                        SELECT ote.thread_id, ote.created, ote.updated, ote.type
                                            FROM osticket.ost_thread_entry ote
                                            WHERE ote.staff_id
                                            ORDER BY ote.id DESC
                                            LIMIT 10000000000000000000) sub2
                                    GROUP BY sub2.thread_id
                            ) sub ON sub.thread_id = ot2.id
                        WHERE ot.isanswered
                            AND ots.id IN (?)
                            AND sub.type = 'R'
                            AND IF(sub.updated > sub.created, sub.updated, sub.created) < DATE_SUB(CURDATE(), INTERVAL ? DAY);`;

        const ticketsId = [];
        const statusIdToClose = config.oldStatus.split(',');

        con.connect(err => {
            if (err) throw err;
            con.query(sql, [statusIdToClose, config.day],
                (err, results) => {
                    if (err) throw err;
                    for (const result of results)
                        ticketsId.push(result.ticket_id);
                });
        });
        await getRequestToken();

        async function getRequestToken() {
            const response = await fetch(ostUri);

            const result = response.headers.get('set-cookie');
            const [firtHeader] = result.split(' ');
            const cookie = firtHeader.substring(0, firtHeader.length - 1);
            const body = await response.text();
            const dom = new jsdom.JSDOM(body);
            const token = dom.window.document.querySelector('[name="__CSRFToken__"]').value;

            await login(token, cookie);
        }

        async function login(token, cookie) {
            const data = {
                __CSRFToken__: token,
                do: 'scplogin',
                userid: config.user,
                passwd: config.password,
                ajax: 1
            };
            const params = {
                method: 'POST',
                body: new URLSearchParams(data),
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
                    'Cookie': cookie
                }
            };
            await fetch(ostUri, params);

            await close(token, cookie);
        }

        async function close(token, cookie) {
            for (const ticketId of ticketsId) {
                try {
                    const lock = await getLockCode(token, cookie, ticketId);
                    if (!lock.code) {
                        let error = `Can't get lock code`;
                        if (lock.msg) error += `: ${lock.msg}`;
                        throw new Error(error);
                    }
                    let form = new FormData();
                    form.append('__CSRFToken__', token);
                    form.append('id', ticketId);
                    form.append('a', config.responseType);
                    form.append('lockCode', lock.code);
                    form.append('from_email_id', config.fromEmailId);
                    form.append('reply-to', config.replyTo);
                    form.append('cannedResp', 0);
                    form.append('response', config.comment);
                    form.append('signature', 'none');
                    form.append('reply_status_id', config.newStatusId);

                    const ostUri = `${config.host}/tickets.php?id=${ticketId}`;
                    const params = {
                        method: 'POST',
                        body: form,
                        headers: {
                            'Cookie': cookie
                        }
                    };
                    await fetch(ostUri, params);
                } catch (e) {
                    const err = new Error(`${ticketId} Ticket close failed: ${e.message}`);
                    err.stack += e.stack;
                    console.error(err);
                }
            }
        }

        async function getLockCode(token, cookie, ticketId) {
            const ostUri = `${config.host}/ajax.php/lock/ticket/${ticketId}`;
            const params = {
                method: 'POST',
                headers: {
                    'X-CSRFToken': token,
                    'Cookie': cookie
                }
            };
            const response = await fetch(ostUri, params);
            const body = await response.text();
            const json = JSON.parse(body);

            return json;
        }
    };
};