/**
 * Copyright 2016 the WHATAP project authors. All rights reserved.
 * Use of this source code is governed by a license that
 * can be found in the LICENSE file.
 */

const TraceContextManager = require('../trace/trace-context-manager');
const conf = require('../conf/configure');
const AsyncSender = require('../udp/async_sender');
const DataOuputX = require('../io/data-outputx');
const SecurityMaster = require('../net/security-master');
const LogSinkPack = require('../pack/log-sink-pack');

let logsink_enabled = conf.getProperty('logsink_enabled', false);

conf.on('logsink_enabled', function(newProperty) {
    logsink_enabled = newProperty;
});

const ProcessObserver = function (agent) {
    this.agent = agent;
    this.packages = ['process'];
};

ProcessObserver.prototype.inject = function (mod, moduleName) {
    this._hookNextTick(mod);
    this._hookStdOutWrite();
    this._hookStdErrWrite();
};

ProcessObserver.prototype._hookNextTick = function (mod) {
    this.agent.aop.before(mod, 'nextTick', (obj, args) => {
        const cached_id = TraceContextManager.getCurrentId();
        this.agent.aop.functionHook(args, -1, (obj, args) => {
            if (cached_id != null) {
                TraceContextManager.resume(cached_id);
            }
        });
    });
};

ProcessObserver.prototype._sendLogPack = function (content, category) {
    const ctx = TraceContextManager.getCurrentContext();
    const tags = ctx && ctx.id ? {'@txid': ctx.id.toString()} : {};

    const fields = {"filename": null};

    const p = new LogSinkPack();
    p.Category = category;
    p.time = Date.now();
    p.line = Date.now();
    p.content = content;

    p.pcode = SecurityMaster.PCODE;
    const bout = new DataOuputX();
    bout.writePack(p, null);
    const packbytes = bout.toByteArray();

    AsyncSender.send_relaypack(packbytes);
};

ProcessObserver.prototype._hookStdOutWrite = function () {
    this.agent.aop.after(process.stdout, 'write', (obj, args) => {
        if (conf.getProperty('logsink_enabled', false) && args[0]) {
            let content = typeof args[0] === 'string' ? args[0] : (args[0].message || '');
            try {
                const parsedContent = JSON.parse(content);
                content = parsedContent.message ? parsedContent.message : JSON.stringify(parsedContent);
            } catch (e) {
                // JSON 파싱 실패 시 원본 content 사용
            }

            if (content && content.trim()) {
                const category = conf.getProperty('logsink_category_stdout', 'AppStdOut');
                this._sendLogPack(content, category);
            }
        }
    });
};

ProcessObserver.prototype._hookStdErrWrite = function () {
    this.agent.aop.after(process.stderr, 'write', (obj, args) => {
        if (conf.getProperty('logsink_enabled', false) && args[0]) {
            let content = typeof args[0] === 'string' ? args[0] : (args[0].message || '');
            try {
                const parsedContent = JSON.parse(content);
                content = parsedContent.message ? parsedContent.message : JSON.stringify(parsedContent);
            } catch (e) {
                // JSON 파싱 실패 시 원본 content 사용
            }

            if (content && content.trim()) {
                const category = conf.getProperty('logsink_category_stderr', 'AppStdErr');
                this._sendLogPack(content, category);
            }
        }
    });
};

module.exports.ProcessObserver = ProcessObserver;