package com.brilliance.mda.runtime.mda.util;

import com.brilliance.mda.runtime.mda.Constants;
import com.brilliance.mda.runtime.mda.OpType;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

public class Dates {

    public static Date defaultNullDate;
    public static Date defaultNullDateTime;

    static {
        Calendar nullDateCal = GregorianCalendar.getInstance();
        nullDateCal.set(Calendar.MILLISECOND, 0);
        nullDateCal.set(1899, Calendar.DECEMBER, 30, 0, 0, 0);
        defaultNullDate = nullDateCal.getTime();
        Calendar nullDateTimeCal = GregorianCalendar.getInstance();
        nullDateTimeCal.set(Calendar.MILLISECOND, 0);
        nullDateTimeCal.set(1899, Calendar.DECEMBER, 30, 0, 0, 0);
        defaultNullDateTime = nullDateTimeCal.getTime();
    }

    private static Date handleNullDate(Date date) {
        return date == null ? defaultNullDate : date;
    }

    public static Date add(Date date, int days) {
        return add(date, 5, days);
    }

    public static Date add(Date date, Long days) {
        return add(date, 5, days.intValue());
    }

    public static Date add(Date date, int type, int value) {
        Calendar c = Calendar.getInstance();
        if (date == null) {
            date = defaultNullDate;
        }
        c.setTime(date);
        c.add(type, value);
        return c.getTime();
    }

    public static Date today() {
        Calendar c = Calendar.getInstance();
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();

    }

    public static Date today(TimeZone timeZone) {
        return today();
    }

    public static Date today(String timeZone) {
        return today();
    }

    public static Date sqlDate(Date date) {
        return sqlDate(date, null);
    }

    public static Date sqlDate(Date date, OpType type) {
        if (date == null)
            return null;
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        switch (type) {
            case LT:
            case LE:
                c.set(Calendar.HOUR_OF_DAY, 23);
                c.set(Calendar.MINUTE, 59);
                c.set(Calendar.SECOND, 59);
                c.set(Calendar.MILLISECOND, 999);
                if (type == OpType.LT)
                    return new Timestamp(c.getTime().getTime());
                return new java.util.Date(c.getTime().getTime());
            case GT:
            case GE:
                c.set(Calendar.HOUR_OF_DAY, 0);
                c.set(Calendar.MINUTE, 0);
                c.set(Calendar.SECOND, 0);
                c.set(Calendar.MILLISECOND, 0);
                if (type == OpType.GT)
                    return new Timestamp(c.getTime().getTime());
                return new java.util.Date(c.getTime().getTime());
            default:
                return date;
        }
    }

    public static Date dateTimeMake(Date inidatfro, int hour, String timezone) {
        return dateTimeMake(inidatfro, hour);
    }

    public static Date dateTimeMake(Date inidatfro, int hour) {
        Calendar c = Calendar.getInstance();
        c.setTime(inidatfro);
        c.set(Calendar.HOUR_OF_DAY, hour);
        return c.getTime();
    }

    public static Date dateTimeMake(Date inidatfro, BigDecimal hour_min, String timezone) {
        return dateTimeMake(inidatfro, hour_min);
    }

    public static Date dateTimeMake(Date inidatfro, BigDecimal hour_min) {
        Calendar c = Calendar.getInstance();
        c.setTime(inidatfro);
        c.set(Calendar.HOUR_OF_DAY, hour_min.intValue());
        int min = Float.valueOf(hour_min.floatValue() * 100).intValue();
        c.set(Calendar.MINUTE, min);
        return c.getTime();
    }

    public static LocalDate toLocalDate(Date date) {
        date = handleNullDate(date);
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }

    public static int getDay(Date date) {
        return toLocalDate(date).getDayOfMonth();
    }

    public static int getYear(Date date) {
        return toLocalDate(date).getYear();
    }

    public static int getMonth(Date date) {
        return toLocalDate(date).getMonthValue();
    }

    public static Timestamp now() {
        return Timestamp.valueOf(LocalDateTime.now());
    }

    public static long dateTimeDiff(Date begin, Date end) {
        return Math.abs(begin.getTime() - end.getTime());
//        int diff = (int)(Math.abs(begin.getTime() - end.getTime()) / 1000 % (60 * 60 * 24));
//        int h = diff / (60 * 60);
//        int m = (diff - h * 60 * 60) / 60;
//        int s = (diff - h * 60 * 60) % 60;
//        return h + m / 100 + s / 100000;
    }

    public static Date dateSub(Date date, int i) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.DAY_OF_MONTH, -i);
        return c.getTime();
    }

    public static Date dateAdd(Date date, int i) {
        if (i > 9999 || i < -9999) {
            return date;
        }
        Date temp = Dates.add(date, i);
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
        String dateString = formatter.format(temp);
        //如果 D + N 个日历日 > 31.12.9999，则设置错误代码 36
        if (Integer.parseInt(dateString) > Constants.maxDate) {
            return date;
        }
        return temp;
    }

    public static Date dateAddW(Date date, int i, String lang) {
        if (i > 9999 || i < -9999) {
            return date;
        }
        if (i == 0) {
            return date;
        }
        Date temp = date;
        if (i > 0) {
            while (i > 0) {
                temp = getTomorrowOrYesterday(temp, 1);
                if (!isWeekend(temp, lang) && !isHoliday(temp, lang)) {
                    i--;
                }
            }
        } else {
            while (i < 0) {
                temp = getTomorrowOrYesterday(temp, -1);
                if (!isWeekend(temp, lang) && !isHoliday(temp, lang)) {
                    i++;
                }
            }
        }
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
        String dateString = formatter.format(temp);
        //如果 D + N 个日历日 > 31.12.9999，则设置错误代码 36
        if (Integer.parseInt(dateString) > Constants.maxDate) {
            return date;
        }
        return temp;
    }

    public static Date getTomorrowOrYesterday(Date date, int i) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.DAY_OF_MONTH, i);
        return c.getTime();
    }

    public static Boolean isWeekend(Date date, String lang) {
        Calendar c = Calendar.getInstance(TimeZone.getTimeZone(lang));
        c.setTime(date);
        return c.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || c.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY;
    }

    public static Boolean isHoliday(Date date, String lang) {
        return false;
    }

    public static int dayOfWeek(Date datint) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(datint);
        return calendar.get(Calendar.DAY_OF_WEEK);
    }

    public static Date dateTimeAdd(Date sysmod, int i, int tim) {
        Calendar c = Calendar.getInstance();
        c.setTime(sysmod);
        long addTime = tim * (60 * 60 * 1000);
        c.setTimeInMillis(c.getTimeInMillis() + addTime);
        return c.getTime();
    }

    public static Date dateTimeAdd(Date sysmod, int i, BigDecimal tim) {
        return dateTimeAdd(sysmod, i, tim.intValue());
    }

    public static Date dateTimeGetDate(Date sysmod) {
        if (sysmod.equals(defaultNullDateTime)) {
            return defaultNullDate;
        }
        Calendar c = Calendar.getInstance();
        c.setTime(sysmod);
        c.setTimeInMillis(c.getTimeInMillis() - c.getTimeInMillis() % (24 * 60 * 60 * 1000));
        return c.getTime();
    }

    public static Date dateTimeGetDate(Date sysmod, String TIME_ZONE) {
        return dateTimeGetDate(sysmod);
    }

    public static int dateTimeGetTime(Date date) {
        if (date.equals(defaultNullDateTime)) {
            return 0;
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        Long n = c.getTimeInMillis() % (24 * 60 * 60);
        return n.intValue();
    }

    /**
     * Mgrtsk中的返回为h+min。参数i和attr的作用尚不明确
     */
    public static double dateTimeGetTime(Date date, int i, String attr) {
        if (date.equals(defaultNullDateTime)) {
            return 0;
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(Calendar.HOUR_OF_DAY) + c.get(Calendar.MINUTE) / 100d;
    }

    public static long MILLISECOND_TO_DAY = 1000 * 60 * 60 * 24;

    public static int diff(Date date1, Date date2) {
        if (date1 == null || date2 == null) {
            return 0;
        }
        long t1 = date1.getTime(), t2 = date2.getTime();
        return (int) ((t1 - t2) / MILLISECOND_TO_DAY);
    }

    public static void dateTimeSetTime(Date dattim, double i, String tdContextTZSYSTEM) {
        Calendar c = Calendar.getInstance();
        c.setTime(dattim);
        if (i == 12) {
            c.set(Calendar.AM_PM, Calendar.AM);
        }
        c.setTimeZone(TimeZone.getTimeZone(tdContextTZSYSTEM));
        dattim = c.getTime();
    }
}
