package com.pcloud.common.core.tools;

import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics;
import io.micrometer.core.instrument.binder.system.ProcessorMetrics;
import io.micrometer.spring.autoconfigure.MeterRegistryConfigurer;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.threads.ThreadPoolExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//import org.springframework.cloud.netflix.hystrix.EnableHystrix;
//import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.core.env.Environment;
import org.springframework.web.client.RestTemplate;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

/**
 * Created by zengqiang on 17-11-16.
 */
//@EnableHystrix
//@EnableHystrixDashboard
@Configuration
public class CommonBeans {
    private static Logger LOGGER = LoggerFactory.getLogger(CommonBeans.class);

    @Autowired
    private Environment environment;

    private long timeout = 10;

    @Bean
    public ProcessorMetrics processorMetrics() {
        return new ProcessorMetrics();
    }

    @Bean
    public JvmGcMetrics jvmGcMetrics() {
        return new JvmGcMetrics();
    }

    @Bean
    public JvmThreadMetrics jvmThreadMetrics() {
        return new JvmThreadMetrics();
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    @Bean
    @Primary
    MeterRegistryConfigurer configurer() {
        try {
            InetAddress inetAddress = getLocalInetAddress();
            String host = null == inetAddress ? "unknown" : inetAddress.getHostName() + "/" + inetAddress.getHostAddress();
            return registry -> {
                registry.config().commonTags("host/ip", host);
            };
        } catch (Exception e) {
            LOGGER.error("create MeterRegistryConfigurer error", e);
            return null;
        }
    }

    /**
     * 取当前系统站点本地地址 linux下 和 window下可用
     *
     * @return
     */
    public InetAddress getLocalInetAddress() {
        InetAddress ia = null, inetAddress = null;
        try {
            for (Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); interfaces.hasMoreElements();) {
                NetworkInterface networkInterface = interfaces.nextElement();
                if (networkInterface.isLoopback() || networkInterface.isVirtual() || !networkInterface.isUp()) {
                    continue;
                }
                Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    ia = addresses.nextElement();
                    if (ia instanceof Inet4Address) {
                        inetAddress = ia;
                    }
                }
            }
        } catch (SocketException e) {
            return null;
        }
        return inetAddress;
    }

    @Bean
    public GracefulShutdownConnector gracefulShutdown() {
        return new GracefulShutdownConnector();
    }

    @Bean
    public EmbeddedServletContainerCustomizer tomcatCustomizer(@Autowired GracefulShutdownConnector connector) {
        return new EmbeddedServletContainerCustomizer() {

            @Override
            public void customize(ConfigurableEmbeddedServletContainer container) {
                if (container instanceof TomcatEmbeddedServletContainerFactory) {
                    ((TomcatEmbeddedServletContainerFactory) container)
                            .addConnectorCustomizers(connector);
                }

            }
        };
    }

    class GracefulShutdownConnector implements TomcatConnectorCustomizer,
            ApplicationListener<ContextClosedEvent> {

        private volatile Connector connector;

        @Override
        public void customize(Connector connector) {
            this.connector = connector;
        }

        @Override
        public void onApplicationEvent(ContextClosedEvent event) {
            if (environment.containsProperty("shutdownTimeout")) {
                timeout = environment.getProperty("shutdownTimeout", Long.class);
            }

            this.connector.pause();
            Executor executor = this.connector.getProtocolHandler().getExecutor();
            if (executor instanceof ThreadPoolExecutor) {
                try {
                    ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
                    threadPoolExecutor.shutdown();
                    if (!threadPoolExecutor.awaitTermination(timeout, TimeUnit.SECONDS)) {
                        LOGGER.warn("Tomcat thread pool did not shut down gracefully within "
                                + timeout + " seconds. Proceeding with forceful shutdown");
                    }
                }
                catch (InterruptedException ex) {
                    Thread.currentThread().interrupt();
                }
            }
        }

    }
}
