package de.ivu.elect.business;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Optional;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;


import static java.util.Objects.nonNull;

/**
 * TODO nach technical verschieben
 */
public class DateUtil {

  private static final ZoneId ZONE_ID = ZoneId.systemDefault();

  public static List<Date> getDatesBetween(Date startDate, Date endDate) {
    List<Date> result = new ArrayList<>();

    Calendar start = Calendar.getInstance();
    start.setTime(startDate);
    Calendar end = Calendar.getInstance();
    end.setTime(endDate);

    for (Date date = start.getTime(); start.before(end); start.add(Calendar.DATE, 1), date = start.getTime()) {
      result.add(date);
    }
    if (!endDate.before(startDate)) {
      result.add(endDate);
    }
    return result;
  }

  public static boolean isSameDay(Date one, Date two) {
    if (one == null || two == null) {
      return false;
    }

    if (one.equals(two)) {
      return true;
    }

    return DateUtils.isSameDay(one, two);
  }

  public static Date addDays(Date date, int amount) {
    return DateUtils.addDays(new Date(date.getTime()), amount);
  }

  public static Date beginnDesTages(Date date) {
    return DateUtils.truncate(new Date(date.getTime()), Calendar.DATE);
  }

  public static String getYear(Date date) {
    if (date == null) {
      return StringUtils.EMPTY;
    }
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    return String.valueOf(calendar.get(Calendar.YEAR));
  }

  public static LocalDate asLocalDate(Date value) {
    if (value == null) {
      return null;
    }
    return asZonedDateTime(value).map(ZonedDateTime::toLocalDate).orElse(null);
  }

  public static LocalDateTime asLocalDateTime(Date value) {
    if (value == null) {
      return null;
    }
    return asZonedDateTime(value).map(ZonedDateTime::toLocalDateTime).orElse(null);
  }

  private static Optional<ZonedDateTime> asZonedDateTime(Date value) {
    if (nonNull(value)) {
      // NOTE, dass nicht Date#toInstant verwendet werden darf, da bspw. der Wahltermin aus der DB geladen wird und dieser (als java.sql.Date) keine Uhrzeit besitzt,
      // so dass eine UnsupportedOperationException beim Aufruf fliegen würde, cf. java.sql.Date#toInstant!!!
      return Optional.of(Instant.ofEpochMilli(value.getTime()).atZone(ZONE_ID));
    }

    return Optional.empty();
  }

  public static Date asDate(LocalDate value)  {
    if (value == null) {
      return null;
    }
    return Date.from(value.atStartOfDay(ZONE_ID).toInstant());
  }

  public static Date asDate(LocalDateTime value)  {
    if (value == null) {
      return null;
    }
    return Date.from(value.atZone(ZONE_ID).toInstant());
  }
}
