package com.applemand.zmanim.core.jewcal

import com.kosherjava.zmanim.hebrewcalendar.JewishCalendar
import kotlinx.datetime.LocalDate

enum class HolidayTier { YOM_TOV, FAST, MINOR, ROSH_CHODESH, SHABBAT }

data class Holiday(
    val key: Key,
    val tier: HolidayTier,
    val nameEn: String,
    val nameHe: String,
    /** 1-based Omer day when applicable (7-day range triggers Sefirat HaOmer). */
    val omerDay: Int? = null,
) {
    enum class Key {
        EREV_PESACH, PESACH, CHOL_HAMOED_PESACH, PESACH_SHENI, LAG_BAOMER,
        EREV_SHAVUOS, SHAVUOS,
        SEVENTEEN_OF_TAMMUZ, TISHA_BAV, TU_BAV,
        EREV_ROSH_HASHANA, ROSH_HASHANA, FAST_OF_GEDALYAH, EREV_YOM_KIPPUR,
        YOM_KIPPUR, EREV_SUCCOS, SUCCOS, CHOL_HAMOED_SUCCOS, HOSHANA_RABBA,
        SHEMINI_ATZERES, SIMCHAS_TORAH,
        EREV_CHANUKAH, CHANUKAH, TENTH_OF_TEVES, TU_BISHVAT,
        FAST_OF_ESTHER, PURIM, SHUSHAN_PURIM, PURIM_KATAN, SHUSHAN_PURIM_KATAN,
        ROSH_CHODESH, YOM_HASHOAH, YOM_HAZIKARON, YOM_HAATZMAUT, YOM_YERUSHALAYIM,
        ISRU_CHAG, SHABBAT,
    }
}

/**
 * Maps KosherJava's JewishCalendar.getYomTovIndex() constants to our tier + names.
 * KosherJava constants are stable; we reference them by name.
 */
internal object KosherYomTovMap {
    fun describe(index: Int): Holiday? = when (index) {
        JewishCalendar.EREV_PESACH -> Holiday(Holiday.Key.EREV_PESACH, HolidayTier.MINOR, "Erev Pesach", "ערב פסח")
        JewishCalendar.PESACH -> Holiday(Holiday.Key.PESACH, HolidayTier.YOM_TOV, "Pesach", "פסח")
        JewishCalendar.CHOL_HAMOED_PESACH ->
            Holiday(Holiday.Key.CHOL_HAMOED_PESACH, HolidayTier.MINOR, "Chol HaMoed Pesach", "חול המועד פסח")
        JewishCalendar.PESACH_SHENI -> Holiday(Holiday.Key.PESACH_SHENI, HolidayTier.MINOR, "Pesach Sheni", "פסח שני")
        JewishCalendar.LAG_BAOMER -> Holiday(Holiday.Key.LAG_BAOMER, HolidayTier.MINOR, "Lag B'Omer", "ל״ג בעומר")
        JewishCalendar.EREV_SHAVUOS -> Holiday(Holiday.Key.EREV_SHAVUOS, HolidayTier.MINOR, "Erev Shavuot", "ערב שבועות")
        JewishCalendar.SHAVUOS -> Holiday(Holiday.Key.SHAVUOS, HolidayTier.YOM_TOV, "Shavuot", "שבועות")
        JewishCalendar.SEVENTEEN_OF_TAMMUZ ->
            Holiday(Holiday.Key.SEVENTEEN_OF_TAMMUZ, HolidayTier.FAST, "17 of Tammuz", "י״ז בתמוז")
        JewishCalendar.TISHA_BEAV -> Holiday(Holiday.Key.TISHA_BAV, HolidayTier.FAST, "Tisha B'Av", "תשעה באב")
        JewishCalendar.TU_BEAV -> Holiday(Holiday.Key.TU_BAV, HolidayTier.MINOR, "Tu B'Av", "ט״ו באב")
        JewishCalendar.EREV_ROSH_HASHANA ->
            Holiday(Holiday.Key.EREV_ROSH_HASHANA, HolidayTier.MINOR, "Erev Rosh Hashanah", "ערב ראש השנה")
        JewishCalendar.ROSH_HASHANA -> Holiday(Holiday.Key.ROSH_HASHANA, HolidayTier.YOM_TOV, "Rosh Hashanah", "ראש השנה")
        JewishCalendar.FAST_OF_GEDALYAH ->
            Holiday(Holiday.Key.FAST_OF_GEDALYAH, HolidayTier.FAST, "Fast of Gedaliah", "צום גדליה")
        JewishCalendar.EREV_YOM_KIPPUR ->
            Holiday(Holiday.Key.EREV_YOM_KIPPUR, HolidayTier.MINOR, "Erev Yom Kippur", "ערב יום כיפור")
        JewishCalendar.YOM_KIPPUR -> Holiday(Holiday.Key.YOM_KIPPUR, HolidayTier.YOM_TOV, "Yom Kippur", "יום כיפור")
        JewishCalendar.EREV_SUCCOS -> Holiday(Holiday.Key.EREV_SUCCOS, HolidayTier.MINOR, "Erev Sukkot", "ערב סוכות")
        JewishCalendar.SUCCOS -> Holiday(Holiday.Key.SUCCOS, HolidayTier.YOM_TOV, "Sukkot", "סוכות")
        JewishCalendar.CHOL_HAMOED_SUCCOS ->
            Holiday(Holiday.Key.CHOL_HAMOED_SUCCOS, HolidayTier.MINOR, "Chol HaMoed Sukkot", "חול המועד סוכות")
        JewishCalendar.HOSHANA_RABBA ->
            Holiday(Holiday.Key.HOSHANA_RABBA, HolidayTier.MINOR, "Hoshana Rabbah", "הושענא רבה")
        JewishCalendar.SHEMINI_ATZERES ->
            Holiday(Holiday.Key.SHEMINI_ATZERES, HolidayTier.YOM_TOV, "Shemini Atzeret", "שמיני עצרת")
        JewishCalendar.SIMCHAS_TORAH ->
            Holiday(Holiday.Key.SIMCHAS_TORAH, HolidayTier.YOM_TOV, "Simchat Torah", "שמחת תורה")
        JewishCalendar.CHANUKAH -> Holiday(Holiday.Key.CHANUKAH, HolidayTier.MINOR, "Chanukah", "חנוכה")
        JewishCalendar.TENTH_OF_TEVES -> Holiday(Holiday.Key.TENTH_OF_TEVES, HolidayTier.FAST, "10 of Tevet", "עשרה בטבת")
        JewishCalendar.TU_BESHVAT -> Holiday(Holiday.Key.TU_BISHVAT, HolidayTier.MINOR, "Tu BiShvat", "ט״ו בשבט")
        JewishCalendar.FAST_OF_ESTHER -> Holiday(Holiday.Key.FAST_OF_ESTHER, HolidayTier.FAST, "Fast of Esther", "תענית אסתר")
        JewishCalendar.PURIM -> Holiday(Holiday.Key.PURIM, HolidayTier.MINOR, "Purim", "פורים")
        JewishCalendar.SHUSHAN_PURIM -> Holiday(Holiday.Key.SHUSHAN_PURIM, HolidayTier.MINOR, "Shushan Purim", "שושן פורים")
        JewishCalendar.PURIM_KATAN -> Holiday(Holiday.Key.PURIM_KATAN, HolidayTier.MINOR, "Purim Katan", "פורים קטן")
        JewishCalendar.SHUSHAN_PURIM_KATAN ->
            Holiday(Holiday.Key.SHUSHAN_PURIM_KATAN, HolidayTier.MINOR, "Shushan Purim Katan", "שושן פורים קטן")
        JewishCalendar.YOM_HASHOAH -> Holiday(Holiday.Key.YOM_HASHOAH, HolidayTier.MINOR, "Yom HaShoah", "יום השואה")
        JewishCalendar.YOM_HAZIKARON ->
            Holiday(Holiday.Key.YOM_HAZIKARON, HolidayTier.MINOR, "Yom HaZikaron", "יום הזיכרון")
        JewishCalendar.YOM_HAATZMAUT ->
            Holiday(Holiday.Key.YOM_HAATZMAUT, HolidayTier.MINOR, "Yom HaAtzmaut", "יום העצמאות")
        JewishCalendar.YOM_YERUSHALAYIM ->
            Holiday(Holiday.Key.YOM_YERUSHALAYIM, HolidayTier.MINOR, "Yom Yerushalayim", "יום ירושלים")
        else -> null
    }
}

/**
 * Top-level holiday lookup for a given Gregorian date in the user's location.
 * Returns a short list — most days have 0 or 1 entry, but "Shabbat Chanukah 5" style
 * compositions are handled by the caller.
 */
class HolidayCatalog(private val inIsrael: Boolean = false) {

    fun holidaysFor(date: LocalDate): List<Holiday> {
        val jc = date.toJewishCalendar().also { it.inIsrael = inIsrael }
        val out = mutableListOf<Holiday>()

        val yomTov = jc.yomTovIndex
        if (yomTov >= 0) KosherYomTovMap.describe(yomTov)?.let(out::add)

        if (jc.dayOfWeek == 7) {
            out += Holiday(Holiday.Key.SHABBAT, HolidayTier.SHABBAT, "Shabbat", "שבת קודש")
        }
        if (jc.isRoshChodesh) {
            out += Holiday(Holiday.Key.ROSH_CHODESH, HolidayTier.ROSH_CHODESH, "Rosh Chodesh", "ראש חודש")
        }

        val omer = jc.dayOfOmer
        if (omer > 0) {
            // Tag it on any present holiday; if nothing else, surface an "Omer day N" entry.
            if (out.none { it.tier == HolidayTier.YOM_TOV || it.key == Holiday.Key.LAG_BAOMER }) {
                out += Holiday(
                    Holiday.Key.LAG_BAOMER, // reuse key visually for omer days that fall outside named holidays
                    HolidayTier.MINOR,
                    "Omer Day $omer",
                    "יום $omer לעומר",
                    omerDay = omer,
                )
            }
        }
        return out
    }

    /** Filter honoring the user's HolidayFilters preference. */
    fun filter(
        holidays: List<Holiday>,
        yomTov: Boolean,
        fast: Boolean,
        minor: Boolean,
        roshChodesh: Boolean = true,
        shabbat: Boolean = true,
    ): List<Holiday> = holidays.filter {
        when (it.tier) {
            HolidayTier.YOM_TOV -> yomTov
            HolidayTier.FAST -> fast
            HolidayTier.MINOR -> minor
            HolidayTier.ROSH_CHODESH -> roshChodesh
            HolidayTier.SHABBAT -> shabbat
        }
    }
}
