package com.thinkbiganalytics.metadata.sla.alerts;

/*-
 * #%L
 * thinkbig-sla-core
 * %%
 * Copyright (C) 2017 ThinkBig Analytics
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.thinkbiganalytics.metadata.sla.api.ServiceLevelAgreementAction;
import com.thinkbiganalytics.metadata.sla.api.ServiceLevelAgreementActionValidation;
import com.thinkbiganalytics.spring.SpringApplicationContext;

import org.apache.commons.lang3.reflect.ConstructorUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;

/**
 */
public class ServiceLevelAgreementActionUtil {


    public static Map<Class<? extends ServiceLevelAgreementAction>, Boolean> validActionCache = new ConcurrentHashMap<>();
    Timer invalidActionConfigurationCacheTimer = new Timer();

    public ServiceLevelAgreementActionUtil() {
        scheduleCacheCheck();
    }

    public static boolean isValidConfiguration(List<Class<? extends ServiceLevelAgreementAction>> actionClasses) {

        List<ServiceLevelAgreementActionValidation> validation = validateActionConfiguration(actionClasses);
        return Iterables.any(validation, new Predicate<ServiceLevelAgreementActionValidation>() {
            @Override
            public boolean apply(ServiceLevelAgreementActionValidation serviceLevelAgreementActionValidation) {
                return !serviceLevelAgreementActionValidation.isValid();
            }
        });

    }

    public static ServiceLevelAgreementActionValidation validateConfiguration(ServiceLevelAgreementAction action) {

        if (validActionCache.containsKey(action.getClass()) && validActionCache.get(action.getClass()) == true) {
            return ServiceLevelAgreementActionValidation.VALID;
        }
        if (action != null) {
            ServiceLevelAgreementActionValidation validAction = action.validateConfiguration();
            validAction.setActionClass(action.getClass().getName());
            validActionCache.put(action.getClass(), validAction.isValid());
            return validAction;
        }
        return new ServiceLevelAgreementActionValidation(false, "Unable to find SLA Action ");

    }

    public static List<ServiceLevelAgreementActionValidation> validateActionConfiguration(List<Class<? extends ServiceLevelAgreementAction>> actionClasses) {

        List<ServiceLevelAgreementActionValidation> validation = new ArrayList<>();

        if (actionClasses != null) {
            for (Class<? extends ServiceLevelAgreementAction> actionClass : actionClasses) {
                if (validActionCache.containsKey(actionClass) && validActionCache.get(actionClass) == true) {
                    validation.add(ServiceLevelAgreementActionValidation.valid(actionClass));
                }
                ServiceLevelAgreementAction action = ServiceLevelAgreementActionUtil.instantiate(actionClass);
                if (action != null) {
                    validation.add(validateConfiguration(action));
                }
            }

        }
        return validation;

    }
    //re-evaluate invalid actions ever 1 hr

    public static ServiceLevelAgreementAction instantiate(Class<? extends ServiceLevelAgreementAction> clazz) {
        ServiceLevelAgreementAction action = null;
        try {
            action = SpringApplicationContext.getBean(clazz);
        } catch (NoSuchBeanDefinitionException e) {
            //this is ok
        }

        //if not spring bound then construct the Responder
        if (action == null) {
            //construct and invoke
            try {
                action = ConstructorUtils.invokeConstructor(clazz, null);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
                //TODO LOG error
                e.printStackTrace();
            }
        }
        return action;
    }

    private void scheduleCacheCheck() {
        invalidActionConfigurationCacheTimer.schedule(new EvaluateInvalidActionsTimer(), (60 * 1000 * 5), (60 * 1000) * 60); // delay 5 min, 1 hr eval
    }

    private class EvaluateInvalidActionsTimer extends TimerTask {

        @Override
        public void run() {

            Iterator<Map.Entry<Class<? extends ServiceLevelAgreementAction>, Boolean>> iter = validActionCache.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry<Class<? extends ServiceLevelAgreementAction>, Boolean> entry = iter.next();
                if (entry.getValue() != null && entry.getValue().booleanValue() == false) {
                    iter.remove();
                }
            }

        }
    }

}
