package com.clx.performance.utils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalUnit;
import java.util.Calendar;
import java.util.Date;

/**
 * @ClassName LocalDateTimeUtils
 * @Description
 * @Author kavin
 * @Date 2023/9/18 13:18
 * @Version 1.0
 */
public class LocalDateTimeUtils {

        public static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        public static final DateTimeFormatter DATETIME_YYYY_MM_DD_HH_MM = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
        public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        public static final DateTimeFormatter DATETIME_FORMATTERS = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        public static final DateTimeFormatter DATETIME_FORMAT_NO_TIME = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
        public static final DateTimeFormatter DATETIME_YYYYMMDD = DateTimeFormatter.ofPattern("yyyyMMdd");
        public static final String STR_YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
        public static final String STR_YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
        public static final String STR_YYYY_MM_DD_HH = "yyyy-MM-dd HH";
        public static final String STR_YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
        public static final String STR_SSMMHHDDMMYYYY = "ssmmHHddMMyyyy";
        public static final String STR_SSMMHHDDMM = "ssmmHHddMM";
        public static final String STR_YYYY_MM_DD = "yyyy-MM-dd";
        public static final String STR_MM_DD_HH_MM = "MM-dd HH:mm";
        public static final String STR_YYYYMM = "yyyyMM";
        public static final String STR_YYYYMMDD = "yyyyMMdd";
        public static final String STR_YYYY = "yyyy";
        public static final String STR_MM_DD = "MM-dd";
        public static final String STR_HH_MM_SS = "HH:mm:ss";
        public static final String STR_HH_MM = "HH:mm";
        public static final String STR_HH = "HH";

    public LocalDateTimeUtils() {
    }

        public static void main(String[] args) {
        System.out.println(formatTimeNo());
    }

        public static String formatTime(LocalDateTime time) {
        return time.format(DATETIME_FORMATTER);
    }

        public static String formatTimes(LocalDateTime time) {
        return time.format(DATETIME_FORMATTERS);
    }

        public static String formatTimeNo() {
        return LocalDateTime.now().format(DATETIME_FORMAT_NO_TIME);
    }

        public static String formatTime() {
        return LocalDateTime.now().format(DATETIME_FORMATTER);
    }

        public static LocalDateTime parseTime(String dateTimeStr, String pattern) {
        return LocalDateTime.parse(dateTimeStr, DateTimeFormatter.ofPattern(pattern));
    }

        public static LocalDateTime parseTimeForDate(String dateTimeStr) {
        LocalDate localDate = LocalDate.parse(dateTimeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        return localDate.atStartOfDay();
    }

        public static LocalDate parseLocalDate(String date) {
        return LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }

        public static LocalDateTime parseTime(String dateTimeStr) {
        return LocalDateTime.parse(dateTimeStr, DATETIME_FORMATTER);
    }

        public static String formatTime(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
        return formatTime(localDateTime);
    }

        public static String formatDate(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
        return formatTime(localDateTime, "yyyy-MM-dd");
    }

        public static String formatDate(String time) {
        LocalDateTime localDateTime = LocalDateTime.parse(time, DATETIME_FORMATTER);
        return formatTime(localDateTime, "yyyy-MM-dd");
    }

        public static String formatDateHm(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
        return formatTime(localDateTime, "yyyy-MM-dd HH:mm");
    }

        public static LocalDateTime convertDateToLDT(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }

        public static Date convertLDTToDate(LocalDateTime time) {
        return Date.from(time.atZone(ZoneId.systemDefault()).toInstant());
    }

        public static Long getMilliByTime(LocalDateTime time) {
        return time.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

        public static Long getSecondsByTime(LocalDateTime time) {
        return time.atZone(ZoneId.systemDefault()).toInstant().getEpochSecond();
    }

        public static String formatTime(LocalDateTime time, String pattern) {
        return time.format(DateTimeFormatter.ofPattern(pattern));
    }

        public static String formatNow(String pattern) {
        return formatTime(LocalDateTime.now(), pattern);
    }

        public static LocalDateTime plus(LocalDateTime time, long number, TemporalUnit field) {
        return time.plus(number, field);
    }

        public static LocalDateTime minu(LocalDateTime time, long number, TemporalUnit field) {
        return time.minus(number, field);
    }

        public static long betweenTwoTime(LocalDateTime startTime, LocalDateTime endTime, ChronoUnit field) {
        Period period = Period.between(LocalDate.from(startTime), LocalDate.from(endTime));
        if (field == ChronoUnit.YEARS) {
            return (long)period.getYears();
        } else {
            return field == ChronoUnit.MONTHS ? (long)(period.getYears() * 12 + period.getMonths()) : field.between(startTime, endTime);
        }
    }

        public static String getStringDayStart() {
        return formatTime(parseTime(formatTime()).withHour(0).withMinute(0).withSecond(0).withNano(0));
    }

        public static LocalDateTime getLocalDateDayStart() {
        return parseTime(formatTime()).withHour(0).withMinute(0).withSecond(0).withNano(0);
    }

        public static String getStringDayStart(String time) {
        return formatTime(parseTime(time).withHour(0).withMinute(0).withSecond(0).withNano(0));
    }

    public static String getStringDayStart(LocalDateTime time) {
        return formatTime(time.withHour(0).withMinute(0).withSecond(0).withNano(0));
    }

        public static LocalDateTime getDayStart(String time) {
        return parseTime(time).withHour(0).withMinute(0).withSecond(0).withNano(0);
    }

        public static LocalDateTime getDayStart(LocalDateTime time) {
        return time.withHour(0).withMinute(0).withSecond(0).withNano(0);
    }

    public static LocalDateTime getDayStart() {
        return LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
    }
        public static String getStringDayEnd(String time) {
        return formatTime(parseTime(time).withHour(23).withMinute(59).withSecond(59).withNano(999999999));
    }

        public static String getStringDayEnd() {
        return formatTime(parseTime(formatTime()).withHour(23).withMinute(59).withSecond(59).withNano(999999999));
    }

        public static LocalDateTime getDayEnd(String time) {
        return parseTime(time).withHour(23).withMinute(59).withSecond(59).withNano(999999999);
    }

        public static LocalDateTime getDayEnd(LocalDateTime time) {
        return time.withHour(23).withMinute(59).withSecond(59).withNano(999999999);
    }

        public static String getStringDayHour(String time, int hour) {
        return formatTime(parseTime(time).withHour(hour).withMinute(0).withSecond(0).withNano(0));
    }

        public static LocalDateTime getDayHour(String time, int hour) {
        return parseTime(time).withHour(hour).withMinute(0).withSecond(0).withNano(0);
    }

        public static LocalDateTime getDayHour(LocalDateTime time, int hour) {
        return time.withHour(hour).withMinute(0).withSecond(0).withNano(0);
    }

        public static String getStringMonthStart() {
        return getStringMonthStart(LocalDateTime.now());
    }

        public static String getStringMonthStart(LocalDateTime time) {
        return getMonthStart(time).format(DATETIME_FORMATTER);
    }

        public static String getStringMonthStart(String time) {
        return getMonthStart(parseTime(time)).format(DATETIME_FORMATTER);
    }

        public static LocalDateTime getMonthStart() {
        return getMonthStart(LocalDateTime.now());
    }

        public static LocalDateTime getMonthStart(String time) {
        return getMonthStart(parseTime(time));
    }

        public static LocalDateTime getMonthStart(LocalDateTime time) {
        return getDayStart(time.with(TemporalAdjusters.firstDayOfMonth()));
    }

        public static String getStringMonthEnd() {
        return getStringMonthEnd(LocalDateTime.now());
    }

        public static String getStringMonthEnd(LocalDateTime time) {
        return getMonthEnd(time).format(DATETIME_FORMATTER);
    }

        public static String getStringMonthEnd(String time) {
        return getMonthEnd(parseTime(time)).format(DATETIME_FORMATTER);
    }

        public static LocalDateTime getMonthEnd() {
        return getMonthEnd(LocalDateTime.now());
    }

        public static LocalDateTime getMonthEnd(String time) {
        return getMonthEnd(parseTime(time));
    }

        public static LocalDateTime getMonthEnd(LocalDateTime time) {
        return getDayEnd(time.with(TemporalAdjusters.lastDayOfMonth()));
    }

        public static boolean isTimeInRange(LocalDateTime time, LocalDateTime startTime, LocalDateTime endTime) {
        return startTime.isBefore(time) && endTime.isAfter(time) || startTime.isEqual(time) || endTime.isEqual(time);
    }

        public static LocalDateTime getBeginMonthDate() {
        LocalDateTime datetime = LocalDateTime.now();
        LocalDateTime beginMonthDate = getMonthStart(datetime);
        return beginMonthDate;
    }

        public static LocalDateTime getEndDayMonthDate() {
        LocalDateTime datetime = LocalDateTime.now();
        LocalDateTime endDayMonthDate = getMonthEnd(datetime);
        return endDayMonthDate;
    }

        public static LocalDateTime getBeginMonthDate(LocalDateTime datetime) {
        LocalDateTime beginMonthDate = getMonthStart(datetime);
        return beginMonthDate;
    }

        public static LocalDateTime getEndDayMonthDate(LocalDateTime datetime) {
        LocalDateTime endDayMonthDate = getMonthEnd(datetime);
        return endDayMonthDate;
    }

        public static String getSomeDay(Date date, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(5, day);
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String sd = sdf1.format(calendar.getTime());
        return sd;
    }

        public static int getDaysBetween(Date early, Date late) {
        Calendar calst = Calendar.getInstance();
        Calendar caled = Calendar.getInstance();
        calst.setTime(early);
        caled.setTime(late);
        calst.set(11, 0);
        calst.set(12, 0);
        calst.set(13, 0);
        caled.set(11, 0);
        caled.set(12, 0);
        caled.set(13, 0);
        int days = ((int)(caled.getTime().getTime() / 1000L) - (int)(calst.getTime().getTime() / 1000L)) / 3600 / 24;
        return days;
    }

        public static String getYYYYMMDDTime(LocalDateTime datetime) {
        return DATETIME_YYYYMMDD.format(datetime);
    }

        public static LocalDateTime getStartDate(LocalDateTime datetime) {
        LocalDateTime endDayMonthDate = getDayStart(datetime);
        return endDayMonthDate;
    }

        public static String add(String beginTime, Integer field, Integer amount) throws ParseException {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar cal = Calendar.getInstance();
        Date begin = df.parse(beginTime);
        cal.setTime(begin);
        cal.add(field, amount);
        return df.format(cal.getTime());
    }

        public static LocalDateTime getTimeByLong(Long timestamp) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());
    }

        public static Long getLongByTime(LocalDateTime time) {
        if (time == null) {
            time = LocalDateTime.now();
        }

        return time.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

        public static String getFormatByLong(Long timestamp, String pattern) {
        DateTimeFormatter dateTimeFormatter = null;
        if (pattern != null && pattern.length() != 0) {
            dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        } else {
            dateTimeFormatter = DATETIME_FORMATTER;
        }

        return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault()).format(dateTimeFormatter);
    }

        public static Long getLongByFormat(String dateTimeStr, String pattern) {
        DateTimeFormatter dateTimeFormatter = null;
        if (pattern != null && pattern.length() != 0) {
            dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        } else {
            dateTimeFormatter = DATETIME_FORMATTER;
        }

        LocalDateTime parse = null;
        if (dateTimeStr != null && dateTimeStr.length() != 0) {
            parse = LocalDateTime.parse(dateTimeStr, dateTimeFormatter);
        } else {
            parse = LocalDateTime.now();
        }

        return parse.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

        public static String gasTimeToStr(String gasTime, LocalDateTime now) {
        String time = null;
        if (now != null && gasTime != null && gasTime.length() != 0 && gasTime.length() >= 12) {
            String gasSubstring = gasTime.substring(gasTime.length() - 2);
            String nowYear = formatTime(now, "yyyy");
            if (!gasSubstring.equals(nowYear.substring(2))) {
                nowYear = formatTime(now.minusYears(1L), "yyyy");
            }

            time = formatTime(parseTime(gasTime.substring(0, gasTime.length() - 2) + nowYear, "ssmmHHddMMyyyy"));
            return time;
        } else {
            return time;
        }
    }

        public static String getNowGasTime() {
        LocalDateTime now = LocalDateTime.now();
        String day = formatTime(now, "ssmmHHddMM");
        String year = formatTime(now, "yyyy");
        String time = day + year.substring(2);
        return time;
    }

        public static String changeMonths(LocalDateTime parse, int amount) {
        LocalDateTime localDateTime = parse.plusMonths((long)amount);
        return DATETIME_FORMATTER.format(localDateTime);
    }

        public static LocalDateTime getLocalDateTimechangeMonths(LocalDateTime parse, int amount) {
        LocalDateTime localDateTime = parse.plusMonths((long)amount);
        return localDateTime;
    }

    public static String getWeekStart() {
        return DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.of(LocalDate.now(), LocalTime.MIN).with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)));
    }
    public static String getWeekStart(String dateTime) {
        return DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.of(LocalDateTimeUtils.parseTime(dateTime).toLocalDate(), LocalTime.MIN).with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)));
    }
    public static LocalDateTime getStartWeek() {
        return LocalDateTime.of(LocalDate.now(), LocalTime.MIN).with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
    }
    public static LocalDateTime getStartWeek(String dateTime) {
        return LocalDateTime.of(parseLocalDate(dateTime), LocalTime.MIN).with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
    }
    public static LocalDateTime getStartWeek(LocalDateTime dateTime) {
        return LocalDateTime.of(dateTime.toLocalDate(), LocalTime.MIN).with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
    }

    public static long betweenSecond(LocalDateTime startTime, LocalDateTime endTime){
        Duration duration = Duration.between(startTime, endTime);
        return duration.getSeconds();
    }

    public static long betweenMin(LocalDateTime startTime, LocalDateTime endTime){
        Duration duration = Duration.between(startTime, endTime);
        return duration.toMinutes();
    }
}
