const axios = require('axios');
const {DOMParser} = require('xmldom');
const fs = require('fs');
const ejs = require('ejs');
const UserError = require('vn-loopback/util/user-error');

module.exports = Self => {
    Self.remoteMethod('createShipment', {
        description: 'Create an expedition and return a base64Binary label from de MRW WebService',
        accessType: 'WRITE',
        accepts: [{
            arg: 'expeditionFk',
            type: 'number',
            required: true
        }],
        returns: {
            type: ['object'],
            root: true
        },
        http: {
            path: `/createShipment`,
            verb: 'POST'
        }
    });

    Self.createShipment = async(expeditionFk, options) => {
        const myOptions = {};
        let tx;

        if (typeof options == 'object')
            Object.assign(myOptions, options);

        if (!myOptions.transaction) {
            tx = await Self.beginTransaction({});
            myOptions.transaction = tx;
        }

        const models = Self.app.models;
        const mrw = await models.MrwConfig.findOne(null, myOptions);

        if (!mrw)
            throw new UserError(`Some mrwConfig parameters are not set`);

        const query =
            `SELECT CASE co.code 
                    WHEN 'ES' THEN a.postalCode
                    WHEN 'PT' THEN LEFT(a.postalCode, 4)
                    WHEN 'AD' THEN REPLACE(a.postalCode, 'AD', '00')
                END postalCode,
                a.city,
                a.street,
                co.code countryCode,
                c.fi,
                c.name clientName,
                c.phone,
                DATE_FORMAT(t.shipped, '%d/%m/%Y') created,
                t.shipped,
                e.id expeditionId,
                LPAD(IF(mw.params IS NULL, ms.serviceType, mw.serviceType), 4 ,'0') serviceType,
                IF(mw.weekdays, 'S', 'N') weekDays
            FROM expedition e
                JOIN ticket t ON e.ticketFk = t.id
                JOIN agencyMode am ON am.id = t.agencyModeFk
                JOIN mrwService ms ON ms.agencyModeCodeFk = am.code
                LEFT JOIN mrwServiceWeekday mw ON mw.weekdays = DATE_FORMAT(t.shipped, '%a') 
                JOIN client c ON t.clientFk = c.id
                JOIN address a ON t.addressFk = a.id
                JOIN province p ON a.provinceFk = p.id
                JOIN country co ON co.id = p.countryFk
            WHERE e.id = ?
            LIMIT 1`;

        const [expeditionData] = await Self.rawSql(query, [expeditionFk], myOptions);

        if (!expeditionData)
            throw new UserError(`This expedition is not a MRW shipment`);

        const today = Date.vnNew();
        today.setHours(0, 0, 0, 0);
        if (expeditionData?.shipped.setHours(0, 0, 0, 0) < today)
            throw new UserError(`This ticket has a shipped date earlier than today`);

        const shipmentResponse = await sendXmlDoc('createShipment', {mrw, expeditionData}, 'application/soap+xml');
        const shipmentId = getTextByTag(shipmentResponse, 'NumeroEnvio');

        if (!shipmentId)
            throw new UserError(getTextByTag(shipmentResponse, 'Mensaje'));

        const getLabelResponse = await sendXmlDoc('getLabel', {mrw, shipmentId}, 'text/xml');
        const file = getTextByTag(getLabelResponse, 'EtiquetaFile');

        try {
            await models.Expedition.updateAll({id: expeditionFk}, {externalId: shipmentId}, myOptions);
            if (tx) await tx.commit();
        } catch (error) {
            if (tx) await tx.rollback();
            throw error;
        }
        return file;
    };

    function getTextByTag(xmlDoc, tag) {
        return xmlDoc?.getElementsByTagName(tag)[0]?.textContent;
    }

    async function sendXmlDoc(xmlDock, params, contentType) {
        const parser = new DOMParser();

        const xmlTemplate = fs.readFileSync(__dirname + `/${xmlDock}.ejs`, 'utf-8');
        const renderedTemplate = ejs.render(xmlTemplate, params);
        const data = await axios.post(params.mrw.url, renderedTemplate, {
            headers: {
                'Content-Type': `${contentType}; charset=utf-8`
            }
        });
        return parser.parseFromString(data.data, 'text/xml');
    }
};