package dev.ulfrx.recipe.ui.components.calendar

import kotlinx.datetime.Clock
import kotlinx.datetime.DatePeriod
import kotlinx.datetime.DayOfWeek
import kotlinx.datetime.LocalDate
import kotlinx.datetime.TimeZone
import kotlinx.datetime.minus
import kotlinx.datetime.plus
import kotlinx.datetime.todayIn

/** Today in the system time zone. */
fun todayInSystemTz(): LocalDate = Clock.System.todayIn(TimeZone.currentSystemDefault())

/** Monday-anchored start of the ISO week containing [date]. */
fun LocalDate.startOfWeekMonday(): LocalDate {
    val diff = dayOfWeek.ordinal - DayOfWeek.MONDAY.ordinal
    return this.minus(DatePeriod(days = diff))
}

/** First day of the month containing [date]. */
fun LocalDate.startOfMonth(): LocalDate = LocalDate(year, month, 1)

/**
 * Returns 42 consecutive days starting from the Monday on/before the 1st of
 * [anchor]'s month — i.e., the 6-week visible grid. Anchor's month always
 * starts on the first row; trailing rows fill from the next month.
 */
fun monthGridDays(anchor: LocalDate): List<LocalDate> {
    val gridStart = anchor.startOfMonth().startOfWeekMonday()
    return List(42) { i -> gridStart.plus(DatePeriod(days = i)) }
}

/** Seven days starting from Monday of [anchor]'s week. */
fun weekStripDays(anchor: LocalDate): List<LocalDate> {
    val start = anchor.startOfWeekMonday()
    return List(7) { i -> start.plus(DatePeriod(days = i)) }
}

/** Formats the visible-period label rendered in the topbar pill. */
fun formatPeriodLabel(
    mode: CalendarMode,
    anchor: LocalDate,
    locale: CalendarLocale,
): String =
    when (mode) {
        CalendarMode.Month -> {
            "${locale.monthsLong[anchor.monthNumber - 1]} ${anchor.year}"
        }

        CalendarMode.Week -> {
            val start = anchor.startOfWeekMonday()
            val end = start.plus(DatePeriod(days = 6))
            when {
                start.year == end.year && start.monthNumber == end.monthNumber -> {
                    "${start.dayOfMonth}–${end.dayOfMonth} ${locale.monthsShort[end.monthNumber - 1]} ${end.year}"
                }

                start.year == end.year -> {
                    "${start.dayOfMonth} ${locale.monthsShort[start.monthNumber - 1]} – " +
                        "${end.dayOfMonth} ${locale.monthsShort[end.monthNumber - 1]} ${end.year}"
                }

                else -> {
                    "${start.dayOfMonth} ${locale.monthsShort[start.monthNumber - 1]} ${start.year} – " +
                        "${end.dayOfMonth} ${locale.monthsShort[end.monthNumber - 1]} ${end.year}"
                }
            }
        }
    }

/** True when [date] is inside the period visible at [anchor] under [mode]. */
fun isInVisiblePeriod(
    date: LocalDate,
    anchor: LocalDate,
    mode: CalendarMode,
): Boolean =
    when (mode) {
        CalendarMode.Month -> {
            date.year == anchor.year && date.monthNumber == anchor.monthNumber
        }

        CalendarMode.Week -> {
            val start = anchor.startOfWeekMonday()
            val end = start.plus(DatePeriod(days = 6))
            date in start..end
        }
    }

/**
 * Whole-unit offset between [a] and [b] under [mode] (signed b - a). Used to
 * map between the surface's pager index and an anchor date.
 */
fun periodsBetween(
    a: LocalDate,
    b: LocalDate,
    mode: CalendarMode,
): Int =
    when (mode) {
        CalendarMode.Month -> {
            (b.year - a.year) * 12 + (b.monthNumber - a.monthNumber)
        }

        CalendarMode.Week -> {
            val startDays = a.startOfWeekMonday().toEpochDays()
            val endDays = b.startOfWeekMonday().toEpochDays()
            (endDays - startDays) / 7
        }
    }

/** Advance [date] by [delta] units of [mode]. */
fun LocalDate.plusPeriods(
    delta: Int,
    mode: CalendarMode,
): LocalDate =
    when (mode) {
        CalendarMode.Month -> this.plus(DatePeriod(months = delta))
        CalendarMode.Week -> this.plus(DatePeriod(days = delta * 7))
    }
