/*-
 * ~~~~~~licensing~~~~~~
 * events-handler
 * ==========
 * Copyright (C) 2020 - 2023 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.esb.system.core.events.handler;

import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.model.RouteDefinition;
import org.osgi.framework.FrameworkUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.entaxy.esb.system.common.osgi.OSGIUtils;
import ru.entaxy.esb.system.common.util.PropertiesHelper;
import ru.entaxy.esb.system.core.events.common.SubscriptionType;
import ru.entaxy.esb.system.core.events.handler.util.EventHandlerConstant;
import ru.entaxy.esb.system.core.events.handler.util.EventHelper;
import ru.entaxy.esb.system.core.events.jpa.entity.SystemSubscription;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class SubscriptionRouteGenerator extends RouteBuilder {

    private static final Logger LOG = LoggerFactory.getLogger(SubscriptionRouteGenerator.class);

    private static Map<String, RouteDefinition> routeMap = new HashMap<>();

    private List<SystemSubscription> subscriptions;
    private EventHelper eventHelper;
    private final PropertiesHelper propertiesHelper;

    public SubscriptionRouteGenerator(List<SystemSubscription> subscriptions, EventHelper eventHelper, PropertiesHelper propertiesHelper) {
        this.subscriptions = subscriptions;
        this.eventHelper = eventHelper;
        this.propertiesHelper = propertiesHelper;
    }

    @Override
    public void configure() throws Exception {
        LOG.debug("SubscriptionRouteGenerator: finded " + (subscriptions != null ? subscriptions.size() : "null") + " subscriptions");

        if (subscriptions != null && !subscriptions.isEmpty()) {
            for (SystemSubscription subscription : subscriptions) {
                LOG.debug("Handle subscription topic: " + subscription.getEventTopic().getName() + " system " + subscription.getSystem().getName());
                generateReceivingRoute(subscription);
            }
        }
    }

    private void generateReceivingRoute(SystemSubscription subscription) {
        if (SubscriptionType.PUSH.equals(subscription.getType())) {
            LOG.trace("Generate routes PUSH");
            RouteDefinition definition = from("jms:topic:" + subscription.getEventTopic().getName()
                    + "?subscriptionName=" + getEventHelper().getClientId(subscription) + "&subscriptionDurable=true&subscriptionShared=true")
                    .setProperty("topicName").constant(subscription.getEventTopic().getName())
                    .to("system:" + subscription.getSystem().getName())
                    .errorHandler(
                            defaultErrorHandler()
                                    .maximumRedeliveries(
                                            propertiesHelper.getInteger(EventHandlerConstant.REDELIVERY_MAXIMUMREDELIVERIES,
                                                    EventHandlerConstant.REDELIVERY_MAXIMUMREDELIVERIES_DEFAULT))
                                    .redeliveryDelay(
                                            propertiesHelper.getInteger(EventHandlerConstant.REDELIVERY_REDELIVERYDELAY,
                                                    EventHandlerConstant.REDELIVERY_REDELIVERYDELAY_DEFAULT))
                    );

            routeMap.put(getEventHelper().getClientId(subscription), definition);

        } else if (SubscriptionType.PULL.equals(subscription.getType())) {
            //TODO
        }
    }

    public void deleteRoutes(CamelContext context) throws Exception {
        List<String> subsNames = subscriptions.stream()
                .map(s -> getEventHelper().getClientId(s))
                .collect(Collectors.toList());

        LOG.debug("Delete " + subsNames.size() + " receving routes " + String.join(", ", subsNames));


        LOG.trace("Routes before delete " + routeMap.size());
        List<RouteDefinition> routeToDelete = routeMap.entrySet().stream()
                .filter(x -> subsNames.contains(x.getKey()))
                .map(x -> x.getValue())
                .collect(Collectors.toList());
        if (routeToDelete != null && routeToDelete.size() > 0) {
//			context.removeRouteDefinitions(routeToDelete);
            for (RouteDefinition routeDefinition : routeToDelete) {
                context.removeRoute(routeDefinition.getRouteId());
            }

            routeMap = routeMap.entrySet().stream()
                    .filter(x -> !subsNames.contains(x.getKey()))
                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
            LOG.trace("Routes after delete " + routeMap.size());
        }
    }

    public EventHelper getEventHelper() {
        if (eventHelper == null) {
            eventHelper = (EventHelper) OSGIUtils.getServiceReference(
                    FrameworkUtil.getBundle(EventHelper.class).getBundleContext(),
                    EventHelper.class.getName());
        }
        return eventHelper;
    }

    public List<SystemSubscription> getSubscriptions() {
        return subscriptions;
    }

    public void setSubscriptions(List<SystemSubscription> subscriptions) {
        this.subscriptions = subscriptions;
    }

}
