const UserError = require('vn-loopback/util/user-error');
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;

module.exports = Self => {
    Self.remoteMethodCtx('negativeBases', {
        description: 'Find all negative bases',
        accessType: 'READ',
        accepts: [
            {
                arg: 'from',
                type: 'date',
                description: 'From date'
            },
            {
                arg: 'to',
                type: 'date',
                description: 'To date'
            },
            {
                arg: 'filter',
                type: 'object',
                description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string'
            },
        ],
        returns: {
            type: ['object'],
            root: true
        },
        http: {
            path: `/negativeBases`,
            verb: 'GET'
        }
    });

    Self.negativeBases = async(ctx, options) => {
        const conn = Self.dataSource.connector;
        const args = ctx.args;

        if (!args.from || !args.to)
            throw new UserError(`Insert a date range`);

        const myOptions = {};

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

        const stmts = [];
        let stmt;
        stmts.push(`DROP TEMPORARY TABLE IF EXISTS tmp.ticket`);

        stmts.push(new ParameterizedSQL(
            `CREATE TEMPORARY TABLE tmp.ticket
                (KEY (ticketFk))
                ENGINE = MEMORY
                SELECT id ticketFk
                    FROM ticket t
                    WHERE shipped BETWEEN ? AND ?
                        AND refFk IS NULL`, [args.from, args.to]));
        stmts.push(`CALL vn.ticket_getTax(NULL)`);
        stmts.push(`DROP TEMPORARY TABLE IF EXISTS tmp.filter`);
        stmts.push(new ParameterizedSQL(
            `CREATE TEMPORARY TABLE tmp.filter
                ENGINE = MEMORY
                SELECT
                        co.code company,
                        cou.country,
                        c.id clientId,
                        c.socialName clientSocialName,
                        SUM(s.quantity * s.price * ( 100 - s.discount ) / 100) amount,
                        negativeBase.taxableBase,
                        negativeBase.ticketFk,
                        c.isActive,
                        c.hasToInvoice,
                        c.isTaxDataChecked,
                        w.id comercialId,
                        CONCAT(w.firstName, ' ', w.lastName) comercialName
                        FROM vn.ticket t
                            JOIN vn.company co ON co.id = t.companyFk
                            JOIN vn.sale s ON s.ticketFk = t.id
                            JOIN vn.client c ON c.id = t.clientFk
                            JOIN vn.country cou ON cou.id = c.countryFk
                            LEFT JOIN vn.worker w ON w.id = c.salesPersonFk
                            LEFT JOIN (
                                SELECT ticketFk, taxableBase
                                    FROM tmp.ticketAmount
                                    GROUP BY ticketFk
                                    HAVING taxableBase < 0
                            ) negativeBase ON negativeBase.ticketFk = t.id
                        WHERE t.shipped BETWEEN ? AND ?
                            AND t.refFk IS NULL
                            AND c.typeFk IN ('normal','trust')
                        GROUP BY t.clientFk, negativeBase.taxableBase
                        HAVING amount <> 0`, [args.from, args.to]));

        stmt = new ParameterizedSQL(`
            SELECT f.*
            FROM tmp.filter f`);

        stmt.merge(conn.makeWhere(args.filter.where));
        stmt.merge(conn.makeOrderBy(args.filter.order));

        const negativeBasesIndex = stmts.push(stmt) - 1;

        stmts.push(`DROP TEMPORARY TABLE tmp.filter, tmp.ticket, tmp.ticketTax, tmp.ticketAmount`);

        const sql = ParameterizedSQL.join(stmts, ';');
        const result = await conn.executeStmt(sql, myOptions);

        return negativeBasesIndex === 0 ? result : result[negativeBasesIndex];
    };
};