"use strict";

var pluginId = process.argv[2];
var entry    = process.argv[3];
var pending  = {};
var seq      = 0;
var api;

function post(envelope){ process.parentPort.postMessage(envelope); }

// Виклики, відповідь на які дає користувач, а не хост: модальний діалог живе
// стільки, скільки його не закрили. 15-секундний таймер реджектив би їх рівно
// тоді, коли вікно ще на екрані й відповідь попереду.
var USER_DRIVEN = [ 'alert', 'client.reload' ];

function requestHost(type, payload){
    return new Promise(function(resolve, reject){
        var reqId = pluginId + ':' + (++seq);
        var timer = USER_DRIVEN.indexOf(type) !== -1 ? null : setTimeout(function(){
            delete pending[reqId];
            reject(new Error('Host API timeout: ' + type));
        }, 15000);

        pending[reqId] = { resolve: resolve, reject: reject, timer: timer };
        post({ pluginId: pluginId, src: 'bg', dst: 'host', type: type, payload: payload, reqId: reqId });
    });
}

function hostApi(){
    return {
        composer: { insert: function(text, opts){ return requestHost('composer.insert', { text: text, opts: opts || {} }); } },
        storage : {
            get: function(key){ return requestHost('storage.get', { key: key }); },
            set: function(key, value){ return requestHost('storage.set', { key: key, value: value }); }
        },
        context: {
            get       : function(){ return requestHost('context.get', {}); },
            ensureFile: function(ref){ return requestHost('context.ensureFile', { fileRef: ref }); },
            // Опт-ін на context.changed. Підписка живе рівно стільки, скільки цей процес:
            // після рестарту BG треба підписатись знову і добрати стан через get().
            subscribe  : function(){ return requestHost('context.subscribe', {}); },
            unsubscribe: function(){ return requestHost('context.unsubscribe', {}); }
        },
        notify: function(level, text){ return requestHost('notify', { level: level, text: text }); },
        // Блокуючий діалог. Резолвиться, коли користувач його закриє — на відміну
        // від notify, який лише кидає тост і повертається одразу.
        alert : function(text, opts){ return requestHost('alert', { text: text, ok: (opts || {}).ok }); },
        client: {
            // Питає користувача про м'яке перезавантаження клієнта. Резолвиться false
            // лише при відмові: на згоду сторінка перезавантажується, і ack не доїде.
            reload: function(){ return requestHost('client.reload', {}); }
        },
        panel: {
            open : function(name){ return requestHost('panel.open', { name: name }); },
            close: function(name){ return requestHost('panel.close', { name: name }); }
        },
        contribution: {
            setState: function(id, state){ return requestHost('contribution.setState', { id: id, state: state }); }
        },
        diagnostics: {
            // Проактивний self-report: штовхнути structured-деталь при помилці, не чекаючи health-check.
            // Host ловить health за типом (незалежно від dst) → setHealth.
            report: function(details){
                post({ pluginId: pluginId, src: 'bg', dst: 'ui', type: 'health', payload: { state: 'error', details: details } });
            }
        }
    };
}

process.parentPort.on('message', function(event){
    var envelope = event && event.data ? event.data : event;

    if (!envelope || typeof envelope.type !== 'string') return;

    if (envelope.type === 'ack' && pending[envelope.reqId]){
        var item = pending[envelope.reqId];

        clearTimeout(item.timer);
        delete pending[envelope.reqId];
        return envelope.error ? item.reject(new Error(envelope.error)) : item.resolve(envelope.payload);
    }

    if (envelope.type === 'shutdown'){
        return Promise.resolve(api && api.shutdown ? api.shutdown() : null)
            .finally(function(){ process.exit(0); });
    }

    // On-demand збір діагностики: host просить bg зібрати важчий звіт (спека 2.2).
    // Автодиспетч у api.collectDiagnostics; нема методу → порожній звіт (не помилка).
    if (envelope.type === 'diagnostics.collect'){
        return Promise.resolve(api && api.collectDiagnostics ? api.collectDiagnostics() : { report: null })
            .then(function(payload){
                post({ pluginId: pluginId, src: 'bg', dst: 'host', type: 'ack', reqId: envelope.reqId, payload: payload });
            })
            .catch(function(error){
                post({ pluginId: pluginId, src: 'bg', dst: 'host', type: 'ack', reqId: envelope.reqId, payload: null, error: error.message });
            });
    }

    if (api && typeof api.onMessage === 'function') api.onMessage(envelope);
});

api = require(entry).start({
    pluginId: pluginId,
    host    : hostApi(),
    send    : function(type, payload){
        post({ pluginId: pluginId, src: 'bg', dst: 'ui', type: type, payload: payload });
    },
    lifecycle: function(state){
        post({ pluginId: pluginId, src: 'bg', dst: 'host', type: 'lifecycle', payload: state });
    }
}) || {};
