package com.pixelized.headache.ui.page.summary.yearly

import android.icu.util.Calendar
import com.pixelized.headache.repository.event.Event
import com.pixelized.headache.ui.page.summary.yearly.YearSummaryMonthUio.DayUio
import javax.inject.Inject

class YearSummaryFactory @Inject constructor() {

    fun convertToUio(
        events: Map<Int, Map<Int, Map<Int, List<Event>>>>,
    ): List<YearUio> {
        val monthFirstDayCalendar = Calendar.getInstance().apply {
            firstDayOfWeek = Calendar.MONDAY
            minimalDaysInFirstWeek = 1
        }
        val monthLastDayCalendar = Calendar.getInstance().apply {
            firstDayOfWeek = Calendar.MONDAY
            minimalDaysInFirstWeek = 1
        }
        val currentDayCalendar = Calendar.getInstance().apply {
            firstDayOfWeek = Calendar.MONDAY
            minimalDaysInFirstWeek = 1
        }

        return events
            .map { yearEntry ->
                YearUio(
                    year = yearEntry.key,
                    months = yearEntry.value.map { monthEntry ->
                        monthFirstDayCalendar.apply {
                            set(Calendar.YEAR, yearEntry.key)
                            set(Calendar.MONTH, monthEntry.key)
                            set(Calendar.DAY_OF_MONTH, 1)
                            set(Calendar.MILLISECONDS_IN_DAY, 1)
                        }
                        monthLastDayCalendar.apply {
                            time = monthFirstDayCalendar.time
                            add(Calendar.MONTH, 1)
                            add(Calendar.DAY_OF_MONTH, -1)
                        }
                        currentDayCalendar.apply {
                            time = monthFirstDayCalendar.time
                        }
                        val initial = MutableList(
                            size = monthLastDayCalendar.get(Calendar.WEEK_OF_MONTH),
                        ) {
                            mutableListOf<DayUio>()
                        }
                        val weeks = (1..monthLastDayCalendar.get(Calendar.DAY_OF_MONTH))
                            .fold(initial = initial) { accumulator, dayNumber ->
                                val event: List<Event> = monthEntry.value[dayNumber] ?: emptyList()
                                val weekIndex = currentDayCalendar
                                    .apply {
                                        set(Calendar.YEAR, yearEntry.key)
                                        set(Calendar.MONTH, monthEntry.key)
                                        set(Calendar.DAY_OF_MONTH, dayNumber)
                                        set(Calendar.MILLISECONDS_IN_DAY, 1)
                                    }
                                    .get(Calendar.WEEK_OF_MONTH) - 1
                                val day = DayUio(
                                    number = dayNumber,
                                    headache = event.isNotEmpty(),
                                    pills = event.flatMap { it.pills.map { pill -> pill.color } },
                                )
                                accumulator.also { acc ->
                                    acc[weekIndex] = acc.get(index = weekIndex).also { week ->
                                        week.add(day)
                                    }
                                }
                            }
                        YearSummaryMonthUio(
                            date = monthFirstDayCalendar.time,
                            weeks = weeks,
                        )
                    }.sortedWith { s1, s2 ->
                        when {
                            s1.date.month / 3 < s2.date.month / 3 -> 1
                            s1.date.month / 3 > s2.date.month / 3 -> -1
                            s1.date.month < s2.date.month -> -1
                            s1.date.month > s2.date.month -> 1
                            else -> 0
                        }
                    },
                )
            }
            .sortedByDescending { it.year }
    }
}