"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const models_1 = require("./models");
const fetch = require("node-fetch");
const sequelize_1 = require("sequelize");
const socket = require("./utils/socket");
const jsonUtils = require("./utils/json");
const helpers = require("./helpers");
const nodeinfo_1 = require("./utils/nodeinfo");
const lightning_1 = require("./utils/lightning");
const path = require("path");
const constants = require(path.join(__dirname, '../config/constants.json'));
const env = process.env.NODE_ENV || 'development';
const config = require(path.join(__dirname, '../config/app.json'))[env];
const checkInviteHub = (params = {}) => __awaiter(void 0, void 0, void 0, function* () {
    if (env != "production") {
        return;
    }
    const owner = yield models_1.models.Contact.findOne({ where: { isOwner: true } });
    //console.log('[hub] checking invites ping')
    const inviteStrings = yield models_1.models.Invite.findAll({ where: { status: { [sequelize_1.Op.notIn]: [constants.invite_statuses.complete, constants.invite_statuses.expired] } } }).map(invite => invite.inviteString);
    if (inviteStrings.length === 0) {
        return; // skip if no invites
    }
    fetch(config.hub_api_url + '/invites/check', {
        method: 'POST',
        body: JSON.stringify({ invite_strings: inviteStrings }),
        headers: { 'Content-Type': 'application/json' }
    })
        .then(res => res.json())
        .then(json => {
        if (json.object) {
            json.object.invites.map((object) => __awaiter(void 0, void 0, void 0, function* () {
                const invite = object.invite;
                const pubkey = object.pubkey;
                const price = object.price;
                const dbInvite = yield models_1.models.Invite.findOne({ where: { inviteString: invite.pin } });
                const contact = yield models_1.models.Contact.findOne({ where: { id: dbInvite.contactId } });
                if (dbInvite.status != invite.invite_status) {
                    const updateObj = { status: invite.invite_status, price: price };
                    if (invite.invoice)
                        updateObj.invoice = invite.invoice;
                    dbInvite.update(updateObj);
                    socket.sendJson({
                        type: 'invite',
                        response: jsonUtils.inviteToJson(dbInvite)
                    });
                    if (dbInvite.status == constants.invite_statuses.ready && contact) {
                        sendNotification(-1, contact.alias, 'invite');
                    }
                }
                if (pubkey && dbInvite.status == constants.invite_statuses.complete && contact) {
                    contact.update({ publicKey: pubkey, status: constants.contact_statuses.confirmed });
                    var contactJson = jsonUtils.contactToJson(contact);
                    contactJson.invite = jsonUtils.inviteToJson(dbInvite);
                    socket.sendJson({
                        type: 'contact',
                        response: contactJson
                    });
                    helpers.sendContactKeys({
                        contactIds: [contact.id],
                        sender: owner,
                        type: constants.message_types.contact_key,
                    });
                }
            }));
        }
    })
        .catch(error => {
        console.log('[hub error]', error);
    });
});
const pingHub = (params = {}) => __awaiter(void 0, void 0, void 0, function* () {
    if (env != "production") {
        return;
    }
    const node = yield nodeinfo_1.nodeinfo();
    sendHubCall(Object.assign(Object.assign({}, params), { node }));
});
const sendHubCall = (params) => {
    // console.log('[hub] sending ping')
    fetch(config.hub_api_url + '/ping', {
        method: 'POST',
        body: JSON.stringify(params),
        headers: { 'Content-Type': 'application/json' }
    })
        .catch(error => {
        console.log('[hub warning]: cannot reach hub');
    });
};
exports.sendHubCall = sendHubCall;
const pingHubInterval = (ms) => {
    setInterval(pingHub, ms);
};
exports.pingHubInterval = pingHubInterval;
const checkInvitesHubInterval = (ms) => {
    setInterval(checkInviteHub, ms);
};
exports.checkInvitesHubInterval = checkInvitesHubInterval;
function sendInvoice(payReq, amount) {
    console.log('[hub] sending invoice');
    fetch(config.hub_api_url + '/invoices', {
        method: 'POST',
        body: JSON.stringify({ invoice: payReq, amount }),
        headers: { 'Content-Type': 'application/json' }
    })
        .catch(error => {
        console.log('[hub error]: sendInvoice', error);
    });
}
exports.sendInvoice = sendInvoice;
const finishInviteInHub = (params, onSuccess, onFailure) => {
    fetch(config.hub_api_url + '/invites/finish', {
        method: 'POST',
        body: JSON.stringify(params),
        headers: { 'Content-Type': 'application/json' }
    })
        .then(res => res.json())
        .then(json => {
        console.log('[hub] finished invite to hub');
        onSuccess(json);
    })
        .catch(e => {
        console.log('[hub] fail to finish invite in hub');
        onFailure(e);
    });
};
exports.finishInviteInHub = finishInviteInHub;
const payInviteInHub = (invite_string, params, onSuccess, onFailure) => {
    fetch(config.hub_api_url + '/invites/' + invite_string + '/pay', {
        method: 'POST',
        body: JSON.stringify(params),
        headers: { 'Content-Type': 'application/json' }
    })
        .then(res => res.json())
        .then(json => {
        if (json.object) {
            console.log('[hub] finished pay to hub');
            onSuccess(json);
        }
        else {
            console.log('[hub] fail to pay invite in hub');
            onFailure(json);
        }
    });
};
exports.payInviteInHub = payInviteInHub;
function payInviteInvoice(invoice, onSuccess, onFailure) {
    return __awaiter(this, void 0, void 0, function* () {
        const lightning = yield lightning_1.loadLightning();
        var call = lightning.sendPayment({});
        call.on('data', (response) => __awaiter(this, void 0, void 0, function* () {
            onSuccess(response);
        }));
        call.on('error', (err) => __awaiter(this, void 0, void 0, function* () {
            onFailure(err);
        }));
        call.write({ payment_request: invoice });
    });
}
exports.payInviteInvoice = payInviteInvoice;
const createInviteInHub = (params, onSuccess, onFailure) => {
    fetch(config.hub_api_url + '/invites_new', {
        method: 'POST',
        body: JSON.stringify(params),
        headers: { 'Content-Type': 'application/json' }
    })
        .then(res => res.json())
        .then(json => {
        if (json.object) {
            console.log('[hub] sent invite to be created to hub');
            onSuccess(json);
        }
        else {
            console.log('[hub] fail to create invite in hub');
            onFailure(json);
        }
    });
};
exports.createInviteInHub = createInviteInHub;
const sendNotification = (chat, name, type) => __awaiter(void 0, void 0, void 0, function* () {
    let message = `You have a new message from ${name}`;
    if (type === 'invite') {
        message = `Your invite to ${name} is ready`;
    }
    if (type === 'group') {
        message = `You have been added to group ${name}`;
    }
    if (type === 'reject') {
        message = `The admin has declined your request to join "${name}"`;
    }
    if (type === 'message' && chat.type == constants.chat_types.group && chat.name && chat.name.length) {
        message += ` on ${chat.name}`;
    }
    const owner = yield models_1.models.Contact.findOne({ where: { isOwner: true } });
    if (!owner.deviceId) {
        console.log('[send notification] skipping. owner.deviceId not set.');
        return;
    }
    const device_id = owner.deviceId;
    const isIOS = device_id.length === 64;
    const isAndroid = !isIOS;
    const params = { device_id };
    const notification = {
        chat_id: chat.id,
        sound: ''
    };
    if (type !== 'badge' && !chat.isMuted) {
        notification.message = message;
        notification.sound = owner.notificationSound || 'default';
    }
    else {
        if (isAndroid)
            return; // skip on Android if no actual message
    }
    params.notification = notification;
    if (type === 'message' && chat.type == constants.chat_types.tribe) {
        debounce(() => {
            const count = tribeCounts[chat.id] ? tribeCounts[chat.id] + ' ' : '';
            params.notification.message = chat.isMuted ? '' : `You have ${count}new messages in ${chat.name}`;
            finalNotification(owner.id, params);
        }, chat.id, 30000);
    }
    else {
        finalNotification(owner.id, params);
    }
});
exports.sendNotification = sendNotification;
function finalNotification(ownerID, params) {
    return __awaiter(this, void 0, void 0, function* () {
        if (params.notification.message) {
            console.log('[send notification]', params.notification);
        }
        let unseenMessages = yield models_1.models.Message.count({ where: { sender: { [sequelize_1.Op.ne]: ownerID }, seen: false } });
        params.notification.badge = unseenMessages;
        triggerNotification(params);
    });
}
function triggerNotification(params) {
    fetch("https://hub.sphinx.chat/api/v1/nodes/notify", {
        method: 'POST',
        body: JSON.stringify(params),
        headers: { 'Content-Type': 'application/json' }
    })
        .catch(error => {
        console.log('[hub error]: triggerNotification', error);
    });
}
// let inDebounce
// function debounce(func, delay) {
//   const context = this
//   const args = arguments
//   clearTimeout(inDebounce)
//   inDebounce = setTimeout(() => func.apply(context, args), delay)
// }
const bounceTimeouts = {};
const tribeCounts = {};
function debounce(func, id, delay) {
    const context = this;
    const args = arguments;
    if (bounceTimeouts[id])
        clearTimeout(bounceTimeouts[id]);
    if (!tribeCounts[id])
        tribeCounts[id] = 0;
    tribeCounts[id] += 1;
    bounceTimeouts[id] = setTimeout(() => {
        func.apply(context, args);
        // setTimeout(()=> tribeCounts[id]=0, 15)
        tribeCounts[id] = 0;
    }, delay);
}
//# sourceMappingURL=hub.js.map