/* UtilLib - Copyright (c) 2025 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package net.mapeadores.util.date;

import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.FormatStyle;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;


/**
 *
 * @author Vincent Calame
 */
public class FuzzyDateFormatter {

    private final static Map<String, FuzzyDateFormatter> internMap = new HashMap<String, FuzzyDateFormatter>();
    private final FormatStyle formatStyle;
    private final Locale locale;
    private final String dayPattern;
    private final String monthPattern;
    private final String quarterPattern;
    private final DateTimeFormatter dayFormatter;
    private final DateTimeFormatter monthFormatter;
    private final DateTimeFormatter quarterFormatter;
    private final ResourceBundle dateBundle;

    private FuzzyDateFormatter(FormatStyle formatStyle, Locale locale, String dayPattern, String monthPattern, String quarterPattern) {
        this.formatStyle = formatStyle;
        this.locale = locale;
        this.dayPattern = dayPattern;
        this.monthPattern = monthPattern;
        this.quarterPattern = quarterPattern;
        this.dayFormatter = new DateTimeFormatterBuilder().appendPattern(dayPattern).toFormatter(locale);
        this.monthFormatter = new DateTimeFormatterBuilder().appendPattern(monthPattern).toFormatter(locale);
        this.quarterFormatter = new DateTimeFormatterBuilder().appendPattern(quarterPattern).toFormatter(locale);
        this.dateBundle = ResourceBundle.getBundle("net.mapeadores.util.date.resources.DateResourceBundle", locale);
    }

    public FormatStyle getFormatStyle() {
        return formatStyle;
    }

    public Locale getLocale() {
        return locale;
    }

    public String getPattern(String fuzzyDateType) {
        switch (fuzzyDateType) {
            case FuzzyDate.YEAR_TYPE:
                return "y";
            case FuzzyDate.HALFYEAR_TYPE:
                return "y-M";
            case FuzzyDate.QUARTER_TYPE:
                return quarterPattern;
            case FuzzyDate.MONTH_TYPE:
                return monthPattern;
            case FuzzyDate.DAY_TYPE:
                return dayPattern;
            default:
                throw new IllegalArgumentException("Unknown fuzzyDateType = " + fuzzyDateType);
        }
    }

    public String format(FuzzyDate fuzzyDate) {
        switch (fuzzyDate.getDateType()) {
            case FuzzyDate.YEAR_TYPE:
                return fuzzyDate.toString();
            case FuzzyDate.HALFYEAR_TYPE:
                return formatHalfYear(fuzzyDate);
            case FuzzyDate.QUARTER_TYPE:
                return quarterFormatter.format(fuzzyDate.toLocalDate());
            case FuzzyDate.MONTH_TYPE:
                return monthFormatter.format(fuzzyDate.toLocalDate());
            case FuzzyDate.DAY_TYPE:
                return dayFormatter.format(fuzzyDate.toLocalDate());
            default:
                throw new IllegalArgumentException("Unknown fuzzyDateType = " + fuzzyDate.getDateType());

        }
    }

    private String formatHalfYear(FuzzyDate fuzzyDate) {
        String key = getHalfYearPrefix() + fuzzyDate.getHalfYear();
        String value = dateBundle.getString(key);
        value = value.replace("%y", String.valueOf(fuzzyDate.getYear()));
        return value;
    }

    private String getHalfYearPrefix() {
        switch (formatStyle) {
            case SHORT:
                return "halfyear_short_";
            case MEDIUM:
                return "halfyear_medium_";
            case LONG:
            case FULL:
            default:
                return "halfyear_long_";
        }
    }

    /**
     * Pour monthPattern et quarterPattern :
     * DateTimeFormatterBuilder.getLocalizedDateTimePattern() serait tout à fait
     * approprié mais n'est disponible qu'à partir de Java 19.
     *
     */

    public static FuzzyDateFormatter build(FormatStyle formatStyle, Locale locale) {
        String key = locale.toString() + '|' + formatStyle;
        FuzzyDateFormatter fuzzyDateFormatter = internMap.get(key);
        if (fuzzyDateFormatter != null) {
            return fuzzyDateFormatter;
        }
        String dayPattern = DateUtils.getLocalizedPattern(formatStyle, locale);
        String monthPattern;
        String quarterPattern;
        switch (formatStyle) {
            case SHORT:
                if (dayPattern.indexOf("/") > 0) {
                    monthPattern = "MM/y";
                    quarterPattern = "qqq/y";
                } else {
                    monthPattern = "y-MM";
                    quarterPattern = "y-qqq";
                }
                break;
            case MEDIUM:
                monthPattern = "MMM y";
                quarterPattern = "QQQ y";
                break;
            case LONG:
            case FULL:
            default:
                monthPattern = "MMMM y";
                quarterPattern = "QQQQ y";
        }
        fuzzyDateFormatter = new FuzzyDateFormatter(formatStyle, locale, dayPattern, monthPattern, quarterPattern);
        synchronized (internMap) {
            internMap.put(key, fuzzyDateFormatter);
        }
        return fuzzyDateFormatter;
    }

}
