package com.sonic.common;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.Properties;
import java.util.Spliterators;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import com.sonic.common.enums.AppEnv;
import org.springframework.boot.info.GitProperties;
import org.springframework.boot.info.InfoProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.base.Supplier;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Data;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

/**
 * @author code
 */
@Data
@Slf4j
public class AppRuntime {
    private static final DateTimeFormatter DAY_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
    private static final DateTimeFormatter DAY_HOUR_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHH");

    String appId;
    String appName;
    AppEnv env;
    /**
     * 服务启动时间，单位毫秒
     */
    Long startTime;
    GitProperties gitProperties;
    String hostIP;
    JSONObject ext;

    /**
     * 唯一标示当前的app实例. 实例重启后会重新
     */
    @Setter(value = AccessLevel.NONE)
    String instanceId;

    public String getInstanceId() {
        if (instanceId == null) {
            instanceId = UUID.randomUUID().toString();
        }
        return instanceId;
    }

    @Builder
    public AppRuntime(String appId, String appName, AppEnv env, ApplicationContext applicationContext) {
        Preconditions.checkArgument(env != null || applicationContext != null, "env和applicationContext不能都为空");
        this.appId = appId;
        this.appName = appName;
        this.env = env;
        // 默认构建一个空的gitProperties
        this.gitProperties = new GitProperties(new Properties());
        this.startTime = System.currentTimeMillis();
        this.hostIP = "unknown";
        this.ext = new JSONObject();
        try {
            this.hostIP = InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            log.error("failed to get host ip", e);
        }

        // 获取applicationContext中保存的信息
        if (applicationContext != null) {
            Environment environment = applicationContext.getEnvironment();
            this.env = AppEnv.valueOf(environment.getActiveProfiles()[0]);
            if (applicationContext.containsBean("gitProperties")) {
                this.gitProperties = applicationContext.getBean("gitProperties", GitProperties.class);
            }
        }
    }

    private String doBuildPrefixKey(Supplier<String> prefixSupplier, Object... keys) {
        StringBuilder sb = new StringBuilder(appId).append(":");
        if (env != AppEnv.product) {
            sb.append(env.name()).append(":");
        }
        if (prefixSupplier != null) {
            sb.append(prefixSupplier.get()).append(":");
        }
        sb.append(Joiner.on(":").skipNulls().join(keys));
        return sb.toString();
    }

    /**
     * @param keys
     * @return appid:env:key1:key2
     */
    public String buildPrefixKey(Object... keys) {
        return doBuildPrefixKey(null, keys);
    }

    /**
     * 返回key: appid:env:20190101:key1:key2
     *
     * @param keys
     * @return appid:env:20190101:key1:key2
     */
    public String buildPrefixDayKey(Object... keys) {
        return doBuildPrefixKey(() -> LocalDateTime.now().format(DAY_FORMATTER), keys);
    }

    /**
     * 返回key: appid:env:2019010105:key1:key2
     *
     * @param keys
     * @return key: appid:env:2019010105:key1:key2
     */
    public String buildPrefixDayHourKey(Object... keys) {
        return doBuildPrefixKey(() -> LocalDateTime.now().format(DAY_HOUR_FORMATTER), keys);
    }

    public JSONObject toJson() {
        JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(this));

        // 获取gitProperties中详细的信息，因直接对gitProperties序列化得到的信息不完整，所以需要单独处理
        Map<String, String> gitPropsMap = StreamSupport.stream(
                gitProperties != null ? gitProperties.spliterator() : Spliterators.emptySpliterator(), false)
                .collect(Collectors.toMap(InfoProperties.Entry::getKey, InfoProperties.Entry::getValue));
        jsonObject.put("gitProperties", JSONObject.parseObject(JSONObject.toJSONString(gitPropsMap)));

        return jsonObject;
    }
}
