const UserError = require('vn-loopback/util/user-error');
const base64url = require('base64url');

module.exports = Self => {
    Self.remoteMethod('confirm', {
        description: 'Confirms electronic payment transaction',
        accessType: 'WRITE',
        accepts: [
            {
                arg: 'Ds_SignatureVersion',
                type: 'string',
                required: false,
            }, {
                arg: 'Ds_MerchantParameters',
                type: 'string',
                required: true,
            }, {
                arg: 'Ds_Signature',
                type: 'string',
                required: true,
            }
        ],
        returns: {
            type: 'Boolean',
            root: true
        },
        http: {
            path: `/confirm`,
            verb: 'POST'
        }
    });

    Self.confirm = async(signatureVersion, merchantParameters, signature) => {
        const $ = Self.app.models;
        let transaction;

        try {
            const decodedParams = JSON.parse(
                base64url.decode(merchantParameters, 'utf8'));
            const params = {};

            for (const param in decodedParams)
                params[param] = decodeURIComponent(decodedParams[param]);

            const orderId = params['Ds_Order'];
            if (!orderId)
                throw new UserError('Order id not provided');

            transaction = await Self.findById(orderId, {fields: ['id']});
            if (!transaction)
                throw new UserError('Order not found');

            await transaction.updateAttributes({
                merchantParameters,
                signature,
                signatureVersion,
            });

            const merchantId = parseInt(params['Ds_MerchantCode']);
            if (!merchantId)
                throw new UserError('Merchant id not provided');

            const merchant = await $.TpvMerchant.findById(merchantId, {
                fields: ['id', 'secretKey']
            });
            if (!merchant)
                throw new UserError('Merchant not found');

            const base64hmac = Self.createSignature(
                orderId,
                merchant.secretKey,
                merchantParameters
            );

            if (base64hmac !== base64url.toBase64(signature))
                throw new UserError('Invalid signature');

            await Self.rawSql(
                'CALL hedera.tpvTransaction_confirm(?, ?, ?, ?, ?, ?)', [
                    params['Ds_Amount'],
                    orderId,
                    merchantId,
                    params['Ds_Currency'],
                    params['Ds_Response'],
                    params['Ds_ErrorCode']
                ]);

            return true;
        } catch (err) {
            if (transaction)
                await transaction.updateAttribute('responseError', err.message);
            else
                console.error(err);
            throw err;
        }
    };
};