/*-
 * ~~~~~~licensing~~~~~~
 * platform-manager-core
 * ==========
 * Copyright (C) 2020 - 2025 EmDev LLC
 * ==========
 * You may not use this file except in accordance with the License Terms of the Copyright
 * Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
 * rights to the Software and any copies are the property of the Copyright Holder. Unless
 * it is explicitly allowed the Copyright Holder, the User is prohibited from using the
 * Software for commercial purposes to provide services to third parties.
 * 
 * The Copyright Holder hereby declares that the Software is provided on an "AS IS".
 * Under no circumstances does the Copyright Holder guarantee or promise that the
 * Software provided by him will be suitable or not suitable for the specific purposes
 * of the User, that the Software will meet all commercial and personal subjective
 * expectations of the User, that the Software will work properly, without technical
 * errors, quickly and uninterruptedly.
 * 
 * Under no circumstances shall the Copyright Holder or its Affiliates is not liable
 * to the User for any direct or indirect losses of the User, his expenses or actual
 * damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
 * or damage to data, property, etc.
 * ~~~~~~/licensing~~~~~~
 */
package ru.entaxy.platform.manager.impl;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.util.Collection;

import org.apache.felix.hc.api.execution.HealthCheckExecutionResult;
import org.apache.felix.hc.api.execution.HealthCheckExecutor;
import org.apache.felix.hc.api.execution.HealthCheckSelector;
import org.apache.karaf.shell.api.console.SessionFactory;
import org.apache.karaf.shell.support.ansi.SimpleAnsi;
import org.apache.karaf.shell.support.table.ShellTable;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.FrameworkEvent;
import org.osgi.framework.FrameworkListener;
import org.osgi.framework.startlevel.FrameworkStartLevel;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.component.annotations.ReferencePolicyOption;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.entaxy.platform.manager.EntaxyPlatformManager;
import ru.entaxy.platform.manager.shell.Utils;

@Component(service = EntaxyPlatformManager.class, immediate = true)
public class EntaxyPlatformManagerImpl implements EntaxyPlatformManager, FrameworkListener {

    private static final Logger log = LoggerFactory.getLogger(EntaxyPlatformManagerImpl.class);

    // @Reference(cardinality = ReferenceCardinality.MANDATORY, policyOption =
    // ReferencePolicyOption.GREEDY)
    // BootFinished bootFinished;

    @Reference(cardinality = ReferenceCardinality.MANDATORY, policy = ReferencePolicy.DYNAMIC,
            policyOption = ReferencePolicyOption.GREEDY)
    volatile HealthCheckExecutor healthCheckExecutor;

    @Reference(cardinality = ReferenceCardinality.MANDATORY, policy = ReferencePolicy.DYNAMIC,
            policyOption = ReferencePolicyOption.GREEDY)
    volatile SessionFactory sessionFactory;

    protected BundleContext bundleContext;

    protected static EntaxyPlatformManagerImpl registeredInstance;

    @Activate
    public void activate(ComponentContext componentContext) {
        this.bundleContext = componentContext.getBundleContext();
        if (registeredInstance != null)
            this.bundleContext.removeFrameworkListener(registeredInstance);
        registeredInstance = this;
        this.bundleContext.addFrameworkListener(registeredInstance);
        if (checkStartLevel())
            executeInitialHealthcheckPrinting();
    }

    @Override
    public void frameworkEvent(FrameworkEvent event) {

        // not fired, may be a bug
        if (event.getType() == FrameworkEvent.STARTED) {
            executeInitialHealthcheckPrinting();
        }

        // define startup event via startLevel change
        if (event.getType() == FrameworkEvent.STARTLEVEL_CHANGED) {
            if (checkStartLevel())
                executeInitialHealthcheckPrinting();
        }

    }

    protected boolean checkStartLevel() {
        int defStartLevel = Integer.parseInt(System
                .getProperty(Constants.FRAMEWORK_BEGINNING_STARTLEVEL));
        int startLevel = bundleContext.getBundle(0)
                .adapt(FrameworkStartLevel.class).getStartLevel();
        return startLevel >= defStartLevel;
    }

    protected void executeInitialHealthcheckPrinting() {
        Thread thread = new Thread(new Runnable() {

            @Override
            public void run() {

                doOutput();
            }
        });
        thread.setContextClassLoader(Thread.currentThread().getContextClassLoader());
        thread.run();
    }

    public void doOutput() {
        System.out.println("\n\t******************");
        System.out.println("\t* " + Utils.WLC + SimpleAnsi.INTENSITY_BOLD + "Entaxy started " + Utils.NOR
                + SimpleAnsi.INTENSITY_NORMAL + "*");
        System.out.println("\t******************\n\n");

        /*
         * 
         * try ( final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
         * final PrintStream printStream = new PrintStream(byteArrayOutputStream); ) { Session
         * session = sessionFactory.create(System.in, printStream, System.err);
         * session.execute("bundle:list"); System.out.println(byteArrayOutputStream.toString());
         * System.out.println("================"); } catch (Exception e) { e.printStackTrace();
         * log.error("ERROR:", e); } HealthCheckExecutionOptions options = new
         * HealthCheckExecutionOptions(); options.setCombineTagsWithOr(true);
         * options.setForceInstantExecution(true);
         */

        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            // NOOP;
        }

        HealthCheckSelector selector = HealthCheckSelector.tags(new String[] {""});

        Collection<HealthCheckExecutionResult> results = healthCheckExecutor.execute(selector);// ,
                                                                                               // options);

        printHealthCheckResults(results);

    }

    protected void printHealthCheckResults(Collection<HealthCheckExecutionResult> results) {

        System.out.println("Overall HealthCheck status: " + Utils.colored(Utils.getOverallStatus(results)));
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                PrintStream printStream = new PrintStream(outputStream)) {

            ShellTable table = Utils.createTable(results);

            table.print(printStream, StandardCharsets.ISO_8859_1, true);
            System.out.println(outputStream.toString());

            System.out.println("\n\t ***" + SimpleAnsi.INTENSITY_BOLD + "NOTICE" + SimpleAnsi.INTENSITY_NORMAL + "***");
            System.out.println("Some bundles may start slowly");
            System.out.println("\tUse " + SimpleAnsi.COLOR_BLUE + SimpleAnsi.INTENSITY_BOLD
                    + "entaxy:platform-health" + SimpleAnsi.RESET + SimpleAnsi.INTENSITY_NORMAL
                    + " command to check platform health");
            System.out.println("\tUse " + SimpleAnsi.COLOR_BLUE + SimpleAnsi.INTENSITY_BOLD
                    + "entaxy:inactive" + SimpleAnsi.RESET + SimpleAnsi.INTENSITY_NORMAL
                    + " command to view inactive bundles");
            System.out.println();
        } catch (IOException e) {
            // NOOP
        }


    }

}
