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

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.datetime.DatePeriod
import kotlinx.datetime.LocalDate
import kotlinx.datetime.plus

/**
 * Paged version of [CalendarWeekStrip] — horizontally swipeable. Each page
 * renders one week's days; swiping fires [onSelectionShift] with the same
 * weekday in the now-visible week so the caller can move the highlighted day
 * along with the navigation. Tapping a day still goes through [onSelectDate].
 */
@Composable
fun CalendarWeekStripPager(
    selectedDate: LocalDate,
    today: LocalDate,
    onSelectDate: (LocalDate) -> Unit,
    onSelectionShift: (LocalDate) -> Unit,
    numberStyle: TextStyle,
    modifier: Modifier = Modifier,
    dayState: (LocalDate) -> DayState = { DayState() },
    locale: CalendarLocale = CalendarLocale.PL,
) {
    val origin = remember { selectedDate }
    val initialPage = remember { PAGE_COUNT / 2 }
    val pagerState = rememberPagerState(initialPage = initialPage) { PAGE_COUNT }
    val currentOnSelectionShift by rememberUpdatedState(onSelectionShift)

    // Bring the pager onto the page that contains [selectedDate] whenever it
    // changes from outside the pager — e.g., the user picked a day from the
    // expanded month grid before collapsing.
    LaunchedEffect(selectedDate) {
        val target = initialPage + periodsBetween(origin, selectedDate, CalendarMode.Week)
        if (target != pagerState.currentPage) {
            pagerState.animateScrollToPage(target)
        }
    }

    // Report swipe-driven page changes upward as "shift selection to the same
    // weekday in the now-visible week" so the highlight follows the navigation.
    LaunchedEffect(pagerState) {
        snapshotFlow { pagerState.settledPage }
            .distinctUntilChanged()
            .collect { page ->
                if (page == initialPage) return@collect
                val visibleWeekAnchor = origin.plusPeriods(page - initialPage, CalendarMode.Week)
                if (!isInVisiblePeriod(selectedDate, visibleWeekAnchor, CalendarMode.Week)) {
                    val deltaWeeks = page - initialPage
                    currentOnSelectionShift(selectedDate.plus(DatePeriod(days = deltaWeeks * DAYS_PER_WEEK)))
                }
            }
    }

    HorizontalPager(
        state = pagerState,
        modifier = modifier.fillMaxWidth(),
        pageSpacing = 0.dp,
    ) { page ->
        val pageAnchor = origin.plusPeriods(page - initialPage, CalendarMode.Week)
        WeekStripWithHeaders(
            anchor = pageAnchor,
            selectedDate = selectedDate,
            today = today,
            onSelectDate = onSelectDate,
            numberStyle = numberStyle,
            dayState = dayState,
            locale = locale,
        )
    }
}

@Composable
private fun WeekStripWithHeaders(
    anchor: LocalDate,
    selectedDate: LocalDate,
    today: LocalDate,
    onSelectDate: (LocalDate) -> Unit,
    numberStyle: TextStyle,
    dayState: (LocalDate) -> DayState,
    locale: CalendarLocale,
) {
    val days = weekStripDays(anchor)
    Row(
        modifier = Modifier.fillMaxWidth(),
        horizontalArrangement = Arrangement.spacedBy(DayCellGap),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        days.forEachIndexed { index, day ->
            Box(modifier = Modifier.weight(1f)) {
                CalendarDayCell(
                    date = day,
                    state = dayState(day),
                    isSelected = day == selectedDate,
                    isToday = day == today,
                    onClick = { onSelectDate(day) },
                    numberStyle = numberStyle,
                    header = locale.weekdaysShort[index],
                )
            }
        }
    }
}

private const val DAYS_PER_WEEK = 7

// Centered start lets the pager scroll forward and backward freely — mirrors
// the convention used by [SwipeableCalendar]; 100k pages in either direction is
// ~1900 years so users will never run off the edge.
private const val PAGE_COUNT: Int = 200_000

private val DayCellGap = 4.dp
