package com.usky.rule.util;

import com.usky.rule.constant.DateTimeConstants;
import com.usky.rule.constant.RegExpConstants;
import feign.Util;

import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Date;

public class DateTimeUtil {
    private DateTimeUtil() {
    }

    public static LocalDateTime dateToLocalDateTime(Date date) {
        return date != null ? LocalDateTime.ofInstant(date.toInstant(), getZoneId()) : null;
    }

    public static Date localDateTimeToDate(LocalDateTime dateTime) {
        return dateTime != null ? Date.from(dateTime.atZone(getZoneId()).toInstant()) : null;
    }

    public static LocalDateTime timestampToLocalDateTime(Timestamp timestamp) {
        return timestamp != null ? LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp.getTime()), getZoneId()) : null;
    }

    public static String format(LocalDateTime dateTime) {
        return dateTime != null ? dateTime.format(DateTimeConstants.DATE_TIME_FORMATTER) : null;
    }

    public static String format(LocalDateTime dateTime, DateTimeFormatter formatter) {
        return dateTime != null ? dateTime.format(formatter) : null;
    }

    public static LocalDateTime parse(String dateTime) {
        return parse(dateTime, DateTimeConstants.DATE_TIME_FORMATTER);
    }

    public static LocalDateTime parse(String dateTime, DateTimeFormatter formatter) {
        return Util.isNotBlank(dateTime) ? LocalDateTime.parse(dateTime, formatter) : null;
    }

    /**
     * 将 Unix 时间戳转为东八区 {@link LocalDateTime}。
     * 小于 1e12 的数值按「秒」理解，否则按「毫秒」（兼容 10 位秒级与 13 位毫秒级）。
     */
    public static LocalDateTime fromEpochMillisOrSeconds(long epoch) {
        long millis = epoch < 1_000_000_000_000L ? epoch * 1000L : epoch;
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), getZoneId());
    }

    /**
     * 解析 MQ/设备上报中的时间字段：支持 Number 或纯数字字符串（秒/毫秒时间戳），
     * 也兼容原有 {@link DateTimeConstants#SIMPLE_DATE_TIME_FORMATTER}、{@link DateTimeConstants#DATE_TIME_FORMATTER} 字符串。
     */
    public static LocalDateTime parseMessageTimestamp(Object raw) {
        if (raw == null) {
            return null;
        }
        if (raw instanceof Number) {
            return fromEpochMillisOrSeconds(((Number) raw).longValue());
        }
        String s = raw.toString().trim();
        if (!Util.isNotBlank(s)) {
            return null;
        }
        if (s.chars().allMatch(Character::isDigit)) {
            if (s.length() == 14 && RegExpConstants.SIMPLE_DATE_TIME_PATTERN.matcher(s).matches()) {
                return parse(s, DateTimeConstants.SIMPLE_DATE_TIME_FORMATTER);
            }
            return fromEpochMillisOrSeconds(Long.parseLong(s));
        }
        return parse(s, DateTimeConstants.DATE_TIME_FORMATTER);
    }

    public static long toEpochMilli(LocalDateTime dateTime) {
        if (dateTime == null) {
            throw new IllegalArgumentException("dateTime is null");
        } else {
            return dateTime.atZone(getZoneId()).toInstant().toEpochMilli();
        }
    }

    public static ZoneId getZoneId() {
        return ZoneOffset.of("+8");
    }

    public static boolean isValidDateTime(String dateTime) {
        int dataTimeStringLength = 14;
        return dateTime.length() != 14 ? false : RegExpConstants.SIMPLE_DATE_TIME_PATTERN.matcher(dateTime).matches();
    }

    public static String secondToTime(Long second) {
        if (second != null && second != 0L) {
            long days = second / 86400L;
            second = second % 86400L;
            long hours = second / 3600L;
            second = second % 3600L;
            long minutes = second / 60L;
            second = second % 60L;
            return days > 0L ? String.format("%d天%d小时%d分%d秒", days, hours, minutes, second) : String.format("%d小时%d分%d秒", hours, minutes, second);
        } else {
            return "";
        }
    }
}
