package com.applemand.zmanim.core.jewcal

import com.kosherjava.zmanim.hebrewcalendar.JewishCalendar
import kotlinx.datetime.LocalDate
import java.util.Calendar
import java.util.GregorianCalendar

/**
 * Immutable Hebrew date snapshot — the result of converting a Gregorian LocalDate.
 */
data class HebrewDate(
    val year: Int,
    val monthId: Int,
    val dayOfMonth: Int,
    val dayOfWeek: Int,        // 1=Sunday ... 7=Shabbat (KosherJava convention)
    val isLeapYear: Boolean,
) {
    val monthEn: String get() = HebrewMonthNames.en(monthId)
    val monthHe: String get() = HebrewMonthNames.he(monthId)
    val dayHe: String get() = HebrewNumerals.format(dayOfMonth)
    val yearHe: String get() = formatYear(year)

    fun displayEn(): String = "$dayOfMonth $monthEn $year"
    fun displayHe(): String = "$dayHe $monthHe $yearHe"

    companion object {
        private fun formatYear(year: Int): String {
            // Year displayed sans thousands (standard Hebrew convention).
            val remainder = year % 1000
            return if (remainder in 1..999) HebrewNumerals.format(remainder) else year.toString()
        }
    }
}

/**
 * Gregorian → Hebrew via KosherJava.  Pure function, allocation-light.
 */
fun LocalDate.toHebrewDate(): HebrewDate {
    val gc = GregorianCalendar(year, monthNumber - 1, dayOfMonth)
    val jc = JewishCalendar(gc)
    return HebrewDate(
        year = jc.jewishYear,
        monthId = jc.jewishMonth,
        dayOfMonth = jc.jewishDayOfMonth,
        dayOfWeek = jc.dayOfWeek,
        isLeapYear = jc.isJewishLeapYear,
    )
}

/** Convenience for code paths that already hold a JewishCalendar. */
fun JewishCalendar.toHebrewDate(): HebrewDate = HebrewDate(
    year = jewishYear,
    monthId = jewishMonth,
    dayOfMonth = jewishDayOfMonth,
    dayOfWeek = dayOfWeek,
    isLeapYear = isJewishLeapYear,
)

internal fun LocalDate.toJewishCalendar(): JewishCalendar {
    val gc = GregorianCalendar(year, monthNumber - 1, dayOfMonth)
    return JewishCalendar(gc)
}

internal fun JewishCalendar.toLocalDate(): LocalDate {
    val gc = gregorianCalendar ?: error("KosherJava returned no gregorianCalendar")
    return LocalDate(
        gc.get(Calendar.YEAR),
        gc.get(Calendar.MONTH) + 1,
        gc.get(Calendar.DAY_OF_MONTH),
    )
}
