package com.sunzones.domain.usecase

import com.sunzones.data.local.LocationEntity
import com.sunzones.domain.model.SunLocation
import org.shredzone.commons.suncalc.MoonIllumination
import org.shredzone.commons.suncalc.SunTimes
import java.time.Duration
import java.time.LocalDate
import java.time.LocalTime
import java.time.ZoneId
import java.time.ZonedDateTime
import javax.inject.Inject

class CalculateSunTimesUseCase @Inject constructor() {

    operator fun invoke(entity: LocationEntity): SunLocation {
        val zoneId = ZoneId.of(entity.timezoneId)
        val now = ZonedDateTime.now(zoneId)
        val today = now.toLocalDate()

        val sunTimes = SunTimes.compute()
            .on(today)
            .at(entity.latitude, entity.longitude)
            .timezone(zoneId)
            .execute()

        val sunrise = sunTimes.rise?.toLocalTime()
        val sunset = sunTimes.set?.toLocalTime()

        val dayLengthMinutes = if (sunrise != null && sunset != null) {
            Duration.between(sunrise, sunset).toMinutes()
        } else {
            0L
        }

        val hours = dayLengthMinutes / 60
        val minutes = dayLengthMinutes % 60
        val dayLengthFormatted = "${hours}h ${minutes}m"

        val sunProgress = calculateSunProgress(sunrise, sunset, now.toLocalTime())

        val isDaytime = sunrise != null && sunset != null &&
                now.toLocalTime().isAfter(sunrise) && now.toLocalTime().isBefore(sunset)

        // Night calculations
        val nightLengthMinutes = if (sunrise != null && sunset != null) 1440 - dayLengthMinutes else 0L
        val nightHours = nightLengthMinutes / 60
        val nightMinutes = nightLengthMinutes % 60
        val nightLengthFormatted = "${nightHours}h ${nightMinutes}m"

        var nightProgress = 0f
        var sunriseCountdownFormatted: String? = null

        if (!isDaytime && sunrise != null && sunset != null) {
            val nowLocal = now.toLocalTime()

            val nightStart: ZonedDateTime
            val nightEnd: ZonedDateTime

            if (!nowLocal.isBefore(sunset)) {
                // Evening: sunset already happened today, sunrise will be tomorrow
                nightStart = sunTimes.set!!
                val tomorrowSunTimes = SunTimes.compute()
                    .on(today.plusDays(1))
                    .at(entity.latitude, entity.longitude)
                    .timezone(zoneId)
                    .execute()
                nightEnd = tomorrowSunTimes.rise ?: now
            } else {
                // Morning: before sunrise, night started yesterday
                nightEnd = sunTimes.rise!!
                val yesterdaySunTimes = SunTimes.compute()
                    .on(today.minusDays(1))
                    .at(entity.latitude, entity.longitude)
                    .timezone(zoneId)
                    .execute()
                nightStart = yesterdaySunTimes.set ?: now
            }

            val totalNightSeconds = Duration.between(nightStart, nightEnd).seconds.toFloat()
            val elapsedNightSeconds = Duration.between(nightStart, now).seconds.toFloat()
            nightProgress = if (totalNightSeconds > 0) {
                (elapsedNightSeconds / totalNightSeconds).coerceIn(0f, 1f)
            } else 0f

            val countdownDuration = Duration.between(now, nightEnd)
            if (!countdownDuration.isNegative) {
                val countdownH = countdownDuration.toHours()
                val countdownM = countdownDuration.toMinutes() % 60
                sunriseCountdownFormatted = "${countdownH}h ${countdownM}m"
            }
        }

        // Moon calculations
        val moonIll = MoonIllumination.compute().on(now).execute()
        val moonPhase = moonIll.phase
        val moonIllumination = moonIll.fraction

        return SunLocation(
            id = entity.id,
            name = entity.name,
            latitude = entity.latitude,
            longitude = entity.longitude,
            timezoneId = zoneId,
            isCurrentLocation = entity.isCurrentLocation,
            sunrise = sunrise,
            sunset = sunset,
            dayLengthMinutes = dayLengthMinutes,
            dayLengthFormatted = dayLengthFormatted,
            sunProgress = sunProgress,
            isDaytime = isDaytime,
            nightLengthFormatted = nightLengthFormatted,
            nightProgress = nightProgress,
            moonPhase = moonPhase,
            moonIllumination = moonIllumination,
            sunriseCountdownFormatted = sunriseCountdownFormatted
        )
    }

    private fun calculateSunProgress(
        sunrise: LocalTime?,
        sunset: LocalTime?,
        now: LocalTime
    ): Float {
        if (sunrise == null || sunset == null) return 0f

        val totalDaySeconds = Duration.between(sunrise, sunset).seconds.toFloat()
        if (totalDaySeconds <= 0) return 0f

        val elapsedSeconds = Duration.between(sunrise, now).seconds.toFloat()

        return (elapsedSeconds / totalDaySeconds).coerceIn(0f, 1f)
    }
}
