package com.atlassian.bitbucket.util;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.time.Instant;
import java.util.Date;
import java.util.Locale;

import static java.util.Objects.requireNonNull;

/**
 * Allows the formatting of a date according to predefined formats.
 *
 * @see FormatType
 */
public interface DateFormatter {

    String PROPERTY_KEY_PREFIX = "bitbucket.date.format";

    /**
     * Format the passed date.
     *
     * @param date the date to format.
     * @param type the type of date rendering to generate.
     *
     * @return the formatted date.
     */
    @Nonnull
    String formatDate(@Nonnull Date date, @Nonnull FormatType type);

    /**
     * Format the passed {@link Instant}.
     *
     * @param instant the instant to render.
     * @param type the type of date rendering to generate.
     *
     * @return the formatted instant.
     * @throws NullPointerException if any of the arguments is null.
     * @since 4.5
     */
    @Nonnull
    String formatInstant(@Nonnull Instant instant, @Nonnull FormatType type);

    @Nullable
    String getFormatString(@Nullable String key);

    /**
     * A predefined date format.
     */
    enum FormatType {
        SHORT(PROPERTY_KEY_PREFIX + ".short"),
        LONG(PROPERTY_KEY_PREFIX + ".long"),
        FULL(PROPERTY_KEY_PREFIX + ".full"),
        DATETIME(PROPERTY_KEY_PREFIX + ".datetime"),
        TIMESTAMP(PROPERTY_KEY_PREFIX + ".timestamp"),
        TIMEONLY(PROPERTY_KEY_PREFIX + ".timeonly"),
        SHORTAGE(SHORT),
        LONGAGE(LONG);

        final String key;
        final boolean age;

        FormatType(FormatType delegate) {
            this.key = delegate.key;
            age = true;
        }

        FormatType(String key) {
            this.key = key;
            age = false;
        }

        public boolean isAge() {
            return age;
        }

        public String getKey() {
            return key;
        }

        @Nonnull
        public static FormatType fromString(@Nonnull String s) {
            return valueOf(requireNonNull(s).toUpperCase(Locale.ROOT));
        }
    }
}
