package com.qucheng.game.data.oldsystem.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;

@Slf4j
public class ObjectUtil {

    public static <T> boolean objEquals(T t1, T t2) {
        if (t1 == null && t2 == null) {
            return true;
        }
        if (t1 == null || t2 == null) {
            return false;
        }
        return t1.equals(t2);
    }

    public static Boolean objToBoolean(Object value) {
        return objToBoolean(value, null);
    }

    public static Boolean objToBoolean(Object value, Boolean defaultValue) {
        if (value == null) {
            return defaultValue;
        }
        try {
            if (value instanceof Boolean) {
                return (Boolean) value;
            } else if (value instanceof Integer) {
                return (Integer) value > 0;
            } else if (value instanceof Long) {
                return (Long) value > 0;
            } else if (value instanceof Short) {
                return (Short) value > 0;
            } else if (value instanceof String) {
                if ("true".equalsIgnoreCase((String) value)) {
                    return true;
                }
                if ("false".equalsIgnoreCase((String) value)) {
                    return false;
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        throw new RuntimeException("Unsupported data type[" + value.getClass().getName() + "(" + value + ")" + " --> Boolean]");
    }

    public static String objToString(Object value) {
        return objToString(value, null);
    }

    public static String objToString(Object value, String defaultValue) {
        if (value == null) {
            return defaultValue;
        }
        if (value instanceof String) {
            return (String) value;
        }
        if (value instanceof Double) {
            String result = BigDecimal.valueOf((Double) value).toString();
            if (result.endsWith(".0")) {
                result = result.substring(0, result.length() - 2);
            }
            return result;
        }
        if (value instanceof Date) {
            return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format((Date) value);
        }
        if (value instanceof LocalDate) {
            return DateUtil.formatLocalDate((LocalDate) value);
        }
        if (value instanceof LocalDateTime) {
            return DateUtil.formatLocalDateTime((LocalDateTime) value);
        }
        return value.toString();
    }

    public static Double objToDouble(Object value) {
        return objToDouble(value, null);
    }

    public static Double objToDouble(Object value, Double defaultValue) {
        if (value == null) {
            return defaultValue;
        }
        try {
            if (value instanceof Integer) {
                return Double.valueOf((Integer) value);
            }
            if (value instanceof BigDecimal) {
                return ((BigDecimal) value).doubleValue();
            }
            if (value instanceof Double) {
                return (Double) value;
            }
            if (value instanceof String) {
                return Double.parseDouble((String) value);
            }
            if (value instanceof Long) {
                return Double.valueOf((Long) value);
            }
            if (value instanceof Float) {
                return Double.valueOf((Float) value);
            }
            if (value instanceof Byte) {
                return Double.valueOf((Byte) value);
            }
            if (value instanceof Short) {
                return Double.valueOf((Short) value);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        throw new RuntimeException("Unsupported data type[" + value.getClass().getName() + "(" + value + ")" + " --> Double]");
    }

    public static Integer objToInteger(Object value) {
        return objToInteger(value, null);
    }

    public static Integer objToInteger(Object value, Integer defaultValue) {
        if (value == null) {
            return defaultValue;
        }
        try {
            if (value instanceof Integer) {
                return (Integer) value;
            }
            if (value instanceof BigDecimal) {
                return ((BigDecimal) value).intValue();
            }
            if (value instanceof Double) {
                return ((Double) value).intValue();
            }
            if (value instanceof String) {
                return Integer.parseInt((String) value);
            }
            if (value instanceof Long) {
                return ((Long) value).intValue();
            }
            if (value instanceof Short) {
                return ((Short) value).intValue();
            }
            if (value instanceof Float) {
                return ((Float) value).intValue();
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        throw new RuntimeException("Unsupported data type[" + value.getClass().getName() + "(" + value + ")" + " --> Integer]");
    }

    public static Long objToLong(Object value) {
        return objToLong(value, null);
    }

    public static Long objToLongNull(Object value) {
        return objToLong(value, 0L);
    }

    public static Long objToLong(Object value, Long defaultValue) {
        if (value == null) {
            return defaultValue;
        }
        try {
            if (value instanceof Integer) {
                return ((Integer) value).longValue();
            }
            if (value instanceof BigDecimal) {
                return ((BigDecimal) value).longValue();
            }
            if (value instanceof Double) {
                return ((Double) value).longValue();
            }
            if (value instanceof String) {
                return Long.parseLong((String) value);
            }
            if (value instanceof Long) {
                return (Long) value;
            }
            if (value instanceof Float) {
                return ((Float) value).longValue();
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        throw new RuntimeException("Unsupported data type[" + value.getClass().getName() + "(" + value + ")" + " --> Long]");
    }

    public static Float objToFloat(Object value) {
        return objToFloat(value, null);
    }

    public static Float objToFloat(Object value, Float defaultValue) {
        if (value == null) {
            return defaultValue;
        }
        try {
            if (value instanceof Float) {
                return (Float) value;
            }
            if (value instanceof Integer) {
                return ((Integer) value).floatValue();
            }
            if (value instanceof BigDecimal) {
                return ((BigDecimal) value).floatValue();
            }
            if (value instanceof Double) {
                return ((Double) value).floatValue();
            }
            if (value instanceof String) {
                return Float.parseFloat((String) value);
            }
            if (value instanceof Long) {
                return ((Long) value).floatValue();
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        throw new RuntimeException("Unsupported data type[" + value.getClass().getName() + "(" + value + ")" + " --> Float]");
    }

    public static BigDecimal objToBigDecimal(Object value) {
        return objToBigDecimal(value, null);
    }

    public static BigDecimal objToBigDecimal(Object value, BigDecimal defaultValue) {
        if (value == null) {
            return defaultValue;
        }
        try {
            if (value instanceof BigDecimal) {
                return (BigDecimal) value;
            }
            if (value instanceof Float) {
                return BigDecimal.valueOf((Float) value);
            }
            if (value instanceof Integer) {
                return BigDecimal.valueOf((Integer) value);
            }
            if (value instanceof Double) {
                return BigDecimal.valueOf((Double) value);
            }
            if (value instanceof String) {
                return new BigDecimal((String) value);
            }
            if (value instanceof Long) {
                return BigDecimal.valueOf((Long) value);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        throw new RuntimeException("Unsupported data type[" + value.getClass().getName() + "(" + value + ")" + " --> BigDecimal]");
    }

    public static Date objToDate(Object value) {
        return objToDate(value, null, "yyyy-MM-dd hh:mm:ss");
    }

    public static Date objToDate(Object value, String dateFormat) {
        return objToDate(value, null, dateFormat);
    }

    public static Date objToDate(Object value, Date defaultValue) {
        return objToDate(value, defaultValue, "yyyy-MM-dd hh:mm:ss");
    }

    public static Date objToDate(Object value, Date defaultValue, String dateFormat) {
        if (value == null) {
            return defaultValue;
        }
        try {
            if (value instanceof Date) {
                return (Date) value;
            }
            if (value instanceof Calendar) {
                return ((Calendar) value).getTime();
            }
            if (value instanceof String && dateFormat != null) {
                return new SimpleDateFormat(dateFormat).parse((String) value);
            }
            if (value instanceof Number) {
                String temp = value.toString();
                if (temp.length() == 13) {
                    return new Date(((Number) value).longValue());
                } else {
                    return new Date(((Number) value).longValue() * 1000);
                }
            }
            if (value instanceof LocalDateTime) {
                return Date.from(((LocalDateTime) value).atZone(ZoneOffset.ofHours(8)).toInstant());
            }
            if (value instanceof LocalDate) {
                return Date.from(((LocalDate) value).atStartOfDay(ZoneOffset.ofHours(8)).toInstant());
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        throw new RuntimeException("Unsupported data type[" + value.getClass().getName() + "(" + value + ")" + " --> Date]");
    }

    public static LocalDate objToLocalDate(Object value) {
        return objToLocalDate(value, null, null);
    }

    public static LocalDate objToLocalDate(Object value, LocalDate defaultValue) {
        return objToLocalDate(value, defaultValue, null);
    }

    public static LocalDate objToLocalDate(Object value, String dateFormat) {
        return objToLocalDate(value, null, dateFormat);
    }

    public static LocalDate objToLocalDate(Object value, LocalDate defaultValue, String dateFormat) {
        if (value == null) {
            return defaultValue;
        }
        if (value instanceof LocalDate) {
            return (LocalDate) value;
        }
        if (value instanceof LocalDateTime) {
            return ((LocalDateTime) value).toLocalDate();
        }
        if (value instanceof String) {
            if (StringUtils.isBlank(dateFormat)) {
                return DateUtil.parseLocalDate((String) value);
            }
            return LocalDate.parse((String) value, DateTimeFormatter.ofPattern(dateFormat));
        }
        if (value instanceof Number) {
            String temp = value.toString();
            if (temp.length() == 13) {
                return DateUtil.milliToLocalDate(((Number) value).longValue());
            } else {
                return DateUtil.secondToLocalDate(((Number) value).intValue());
            }
        }
        if (value instanceof Date) {
            return ((Date) value).toInstant().atZone(ZoneOffset.ofHours(8)).toLocalDate();
        }
        throw new RuntimeException("Unsupported data type[" + value.getClass().getName() + "(" + value + ")" + " --> LocalDate]");
    }

    public static LocalDateTime objToLocalDateTime(Object value) {
        return objToLocalDateTime(value, null, null);
    }

    public static LocalDateTime objToLocalDateTime(Object value, LocalDateTime defaultValue) {
        return objToLocalDateTime(value, defaultValue, null);
    }

    public static LocalDateTime objToLocalDateTime(Object value, String dateFormat) {
        return objToLocalDateTime(value, null, dateFormat);
    }

    public static LocalDateTime objToLocalDateTime(Object value, LocalDateTime defaultValue, String dateFormat) {
        if (value == null) {
            return defaultValue;
        }
        if (value instanceof LocalDate) {
            return LocalDateTime.of((LocalDate) value, LocalTime.MIDNIGHT);
        }
        if (value instanceof LocalDateTime) {
            return (LocalDateTime) value;
        }
        if (value instanceof String) {
            if (StringUtils.isBlank(dateFormat)) {
                return DateUtil.parseLocalDateTime((String) value);
            }
            return LocalDateTime.parse((String) value, DateTimeFormatter.ofPattern(dateFormat));
        }
        if (value instanceof Number) {
            String temp = value.toString();
            if (temp.length() == 13) {
                return DateUtil.milliToLocalDateTime(((Number) value).longValue());
            } else {
                return DateUtil.secondToLocalDateTime(((Number) value).intValue());
            }
        }
        if (value instanceof Date) {
            return ((Date) value).toInstant().atZone(ZoneOffset.ofHours(8)).toLocalDateTime();
        }
        throw new RuntimeException("Unsupported data type[" + value.getClass().getName() + "(" + value + ")" + " --> LocalDateTime]");
    }
}