package org.skywalking.apm.toolkit.activation.opentracing.span.interceptor;

import io.opentracing.tag.Tags;
import org.skywalking.apm.agent.core.context.ContextManager;
import org.skywalking.apm.agent.core.plugin.interceptor.EnhancedClassInstanceContext;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodInvokeContext;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.skywalking.apm.toolkit.opentracing.SkyWalkingSpan;

/**
 * Intercept these following methods:
 * {@link SkyWalkingSpan#setTag(String, boolean)}
 * {@link SkyWalkingSpan#setTag(String, Number)}
 * {@link SkyWalkingSpan#setTag(String, String)}
 */
public class SpanSetTagInterceptor implements InstanceMethodsAroundInterceptor {

    /**
     * key of {@link org.skywalking.apm.trace.tag.Tags#PEER_HOST}
     */
    private static final String KEY_OF_PEER_HOST_TAG = "peer.host";

    @Override
    public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
                             MethodInterceptResult result) {
        String key = adaptTag((String) interceptorContext.allArguments()[0]);
        Object value = interceptorContext.allArguments()[1];
        if (value instanceof String)
            ContextManager.activeSpan().setTag(key, (String) value);
        else if (value instanceof Boolean)
            ContextManager.activeSpan().setTag(key, (Boolean) value);
        else if (value instanceof Integer)
            ContextManager.activeSpan().setTag(key, (Integer) value);
        else if (value instanceof Short)
            ContextManager.activeSpan().setTag(key, ((Short) value).intValue());
        else
            ContextManager.activeSpan().setTag(key, value.toString());
    }

    /**
     * Adapt {@link Tags} of open tracing.
     *
     * @return tag key
     */
    private String adaptTag(String tagKey) {
        String key = tagKey;

        if (isPeerTag(key)) {
            key = KEY_OF_PEER_HOST_TAG;
        }

        return key;
    }

    /**
     * Check whether current tag is one of {@link Tags#PEER_HOSTNAME}, {@link Tags#PEER_HOST_IPV4} and {@link Tags#PEER_HOST_IPV6}.
     * If yes, will use the {@link org.skywalking.apm.trace.tag.Tags#PEER_HOST} as the key, instead of original key,
     * in {@link #adaptTag(String)}.
     *
     * @param key of current tag
     * @return true if this tag is host related.
     */
    private boolean isPeerTag(String key) {
        return Tags.PEER_HOST_IPV4.equals(key) || Tags.PEER_HOST_IPV6.equals(key) || Tags.PEER_HOSTNAME.equals(key);
    }

    @Override
    public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
                              Object ret) {
        return ret;
    }

    @Override
    public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
                                      InstanceMethodInvokeContext interceptorContext) {

    }
}
