package cn.axzo.msg.center.message.service.todo.queryanalyze;

import com.google.common.base.CaseFormat;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.util.ReflectionUtils;

import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Date;

/**
 * @author yanglin
 */
@Slf4j
@RequiredArgsConstructor
class Record {

    private final Object value;

    Object getValue(String column, @Nullable Class<?> type) {
        if (value == null) return null;
        String fieldName = CaseFormat.LOWER_UNDERSCORE.to(
                CaseFormat.LOWER_CAMEL, column);
        Field field = ReflectionUtils.findField(value.getClass(), fieldName);
        if (field == null) return null;
        field.setAccessible(true);
        Object value = ReflectionUtils.getField(field, this.value);
        if (type == null) return value;
        if (type == String.class) return String.valueOf(value);
        if (type == Long.class && value instanceof Date)
            return ((Date) value).getTime();
        if (Number.class.isAssignableFrom(type)) {
            try {
                Object number = parseNumber(value, type);
                return number == null ? value : number;
            } catch (Exception e) {
                log.warn("fail to parse number. column={}, value={}", column, value);
                return value;
            }
        }
        return value;
    }

    @Nullable
    private static Object parseNumber(Object value, @NotNull Class<?> type) {
        String str = String.valueOf(value);
        if (type == Long.class)
            return value instanceof Long ? (Long) value : Long.parseLong(str);
        else if (type == Integer.class)
            return value instanceof Integer ? (Integer) value : Integer.parseInt(str);
        else if (type == Double.class)
            return value instanceof Double ? (Double) value : Double.parseDouble(str);
        else if (type == Float.class)
            return value instanceof Float ? (Float) value : Float.parseFloat(str);
        else if (type == Short.class)
            return value instanceof Short ? (Short) value : Short.parseShort(str);
        else if (type == Byte.class)
            return value instanceof Byte ? (Byte) value : Byte.parseByte(str);
        else if (type == BigDecimal.class)
            return value instanceof BigDecimal ? (BigDecimal) value : new BigDecimal(str);
        log.warn("Unsupported number value. expectedType={}, actualValue={}", type, value);
        return null;
    }

}