const FSWrapper = require('@sisense-ps/fs-wrapper/index');

const { ExecWrapper, WindowsServiceTypes, WindowsService } = require('@sisense-ps/shell-execute/index');
const { CreateParameters, QueryParameters, DeleteParameters, StartParameters, StopParameters, DescriptionParameters, QueryConfigParameters } = WindowsServiceTypes;

const MESSAGES = require('../constants/Messages');
const PSLogger = require('@sisense-ps/ps-logger/index');
const Utils = require('../Utils');

class WindowsServiceHelper {

    /**
     * Delete windows service which should be stopped.
     * After what sleep for certain amount of time.
     * @param {Object} microserviceMember 
     * @returns {Promise<{
     * isSuccess: boolean,
     * data: any?
     * error?: Object
     * }>}
     */
    async deleteService(microserviceMember) {
        const { serviceName } = microserviceMember;

        const prms = new DeleteParameters(
            serviceName
        );

        return this._execServiceCommand(prms, 'delete', 1000);
    }

    /**
     * Search windows service by name.
     * @param {Object} microserviceMember 
     * @returns {Promise<{
     * isSuccess: boolean,
     * data: any?
     * error?: Object
     * }>}
     */
    queryServiceByName(microserviceMember) {
        const { serviceName } = microserviceMember;

        const prms = new QueryParameters(serviceName);

        return this._execServiceCommand(prms, 'queryByName', 1000);
    }

    /**
    * Search windows service by name.
    * @param {Object} microserviceMember 
    * @returns {Promise<{
     * isSuccess: boolean,
     * data: any?
     * error?: Object
     * }>}
     */
    queryServiceConfigurationByName(microserviceMember) {
        const { serviceName } = microserviceMember;

        const prms = new QueryConfigParameters(serviceName);

        return this._execServiceCommand(prms, 'queryConfigurationByName', 1000);
    }

    /**
     * Registers windows service after what sleep for certain amount of time.
     * @param {Object} microserviceMember 
     * @returns {Promise<{
     * isSuccess: boolean,
     * data: any?
     * error?: Object
     * }>}
     */
    registerService(microserviceMember) {
        const { serviceName, destination } = microserviceMember;

        const prms = new CreateParameters(
            serviceName,
            'auto',
            `"${FSWrapper.combinePath([destination, 'Sisense.Service.exe'])}"`,
            serviceName
        );

        return this._execServiceCommand(prms, 'create', 1000);
    }

    /**
     * Starts windows service after what sleep for certain amount of time.
     * @param {Object} microserviceMember 
     * @returns {Promise<{
     * isSuccess: boolean,
     * data: any?
     * error?: Object
     * }>}
     */
    startService(microserviceMember) {
        const { serviceName } = microserviceMember;

        const prms = new StartParameters(
            serviceName
        );

        return this._execServiceCommand(prms, 'start', 1000);
    }

    /**
     * Stops windows service after what sleep for certain amount of time.
     * @param {Object} microserviceMember 
     * @returns {Promise<{
     * isSuccess: boolean,
     * data: any?
     * error?: Object
     * }>}
     */
    async stopService(microserviceMember) {
        const { serviceName } = microserviceMember;

        const prms = new StopParameters(
            serviceName
        );
        return this._execServiceCommand(prms, 'stop', 10000);
    }

    changeServiceDescription(microserviceMember) {
        const { serviceName } = microserviceMember;

        const prms = new DescriptionParameters(
            serviceName,
            serviceName
        );

        return this._execServiceCommand(prms, 'description', 1000);
    }

    async restartService(microserviceMember) {
        await this.stopService(microserviceMember);
        return this.startService(microserviceMember);
    }

    async _execServiceCommand(prms, funcName, delay) {
        let result = { isSuccess: true, data: null };

        const command = WindowsService[funcName](prms);

        try {
            result = await ExecWrapper.exec(command, WindowsService.responseParser);
        } catch (err) {
            result.isSuccess = false;
            result.error = err.message;
            result.status = err.status ? err.status : err.code;
        }

        const statusPrefix = result.isSuccess ? 'SUCCESS' : 'ERROR';
        const msgProp = `WINDOWS_SERVICE_${funcName.toUpperCase()}_${statusPrefix}`;

        if (MESSAGES.messageMap[msgProp]) {
            const placeholders = { "service_name": prms.servicename };
            if (!result.isSuccess) {
                placeholders["error_msg"] = result.error.message;
            }
            PSLogger.log(MESSAGES.messageMap[msgProp], placeholders);
        }

        await Utils.sleep(delay);
        return result;
    }
}

module.exports = new WindowsServiceHelper();
