package com.tt.honeyDue.util

import kotlin.time.Clock
import kotlin.time.ExperimentalTime
import kotlinx.datetime.DateTimeUnit
import kotlinx.datetime.Instant
import kotlinx.datetime.LocalDate
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.LocalTime
import kotlinx.datetime.TimeZone
import kotlinx.datetime.minus
import kotlinx.datetime.plus
import kotlinx.datetime.toInstant
import kotlinx.datetime.toLocalDateTime

/**
 * Utility object for formatting dates in a human-readable format
 */
@OptIn(ExperimentalTime::class)
object DateUtils {

    private fun getToday(): LocalDate {
        val nowMillis = Clock.System.now().toEpochMilliseconds()
        val instant = Instant.fromEpochMilliseconds(nowMillis)
        return instant.toLocalDateTime(TimeZone.currentSystemDefault()).date
    }

    /**
     * Get today's date as an ISO string (YYYY-MM-DD)
     */
    fun getTodayString(): String {
        return getToday().toString()
    }

    /**
     * Format a date string (YYYY-MM-DD) to a human-readable format
     * Returns "Today", "Tomorrow", "Yesterday", or "Mon, Dec 15" format
     */
    fun formatDate(dateString: String?): String {
        if (dateString.isNullOrBlank()) return ""

        return try {
            // Parse the date string (handle both "YYYY-MM-DD" and "YYYY-MM-DDTHH:mm:ss" formats)
            val datePart = dateString.substringBefore("T")
            val date = LocalDate.parse(datePart)
            val today = getToday()

            when {
                date == today -> "Today"
                date == today.plus(1, DateTimeUnit.DAY) -> "Tomorrow"
                date == today.minus(1, DateTimeUnit.DAY) -> "Yesterday"
                else -> formatDateMedium(date)
            }
        } catch (e: Exception) {
            dateString // Return original if parsing fails
        }
    }

    /**
     * Format a date string to medium format (e.g., "Dec 15, 2024")
     */
    fun formatDateMedium(dateString: String?): String {
        if (dateString.isNullOrBlank()) return ""

        return try {
            val datePart = dateString.substringBefore("T")
            val date = LocalDate.parse(datePart)
            formatDateMedium(date)
        } catch (e: Exception) {
            dateString
        }
    }

    /**
     * Format a LocalDate to medium format (e.g., "Dec 15, 2024")
     */
    private fun formatDateMedium(date: LocalDate): String {
        val monthName = date.month.name.lowercase().replaceFirstChar { it.uppercase() }.take(3)
        return "$monthName ${date.dayOfMonth}, ${date.year}"
    }

    /**
     * Format an ISO datetime string to a human-readable date format
     * Handles formats like "2024-01-01T00:00:00Z" or "2024-01-01T00:00:00.000Z"
     */
    fun formatDateTime(dateTimeString: String?): String {
        if (dateTimeString.isNullOrBlank()) return ""

        return try {
            // Try to parse as full ISO datetime
            val instant = Instant.parse(dateTimeString)
            val localDateTime = instant.toLocalDateTime(TimeZone.currentSystemDefault())
            val date = localDateTime.date
            val today = getToday()

            when {
                date == today -> "Today"
                date == today.plus(1, DateTimeUnit.DAY) -> "Tomorrow"
                date == today.minus(1, DateTimeUnit.DAY) -> "Yesterday"
                else -> formatDateMedium(date)
            }
        } catch (e: Exception) {
            // Fall back to just date parsing
            formatDate(dateTimeString)
        }
    }

    /**
     * Format a datetime string with time (e.g., "Dec 15, 2024 at 3:30 PM")
     */
    fun formatDateTimeWithTime(dateTimeString: String?): String {
        if (dateTimeString.isNullOrBlank()) return ""

        return try {
            val instant = Instant.parse(dateTimeString)
            val localDateTime = instant.toLocalDateTime(TimeZone.currentSystemDefault())
            val date = localDateTime.date
            val time = localDateTime.time

            val hour = if (time.hour == 0) 12 else if (time.hour > 12) time.hour - 12 else time.hour
            val amPm = if (time.hour < 12) "AM" else "PM"
            val minuteStr = time.minute.toString().padStart(2, '0')

            "${formatDateMedium(date)} at $hour:$minuteStr $amPm"
        } catch (e: Exception) {
            formatDate(dateTimeString)
        }
    }

    /**
     * Format a date for relative display (e.g., "2 days ago", "in 3 days")
     */
    fun formatRelativeDate(dateString: String?): String {
        if (dateString.isNullOrBlank()) return ""

        return try {
            val datePart = dateString.substringBefore("T")
            val date = LocalDate.parse(datePart)
            val today = getToday()
            val daysDiff = (date.toEpochDays() - today.toEpochDays()).toInt()

            when (daysDiff) {
                0 -> "Today"
                1 -> "Tomorrow"
                -1 -> "Yesterday"
                in 2..7 -> "in $daysDiff days"
                in -7..-2 -> "${-daysDiff} days ago"
                else -> formatDateMedium(date)
            }
        } catch (e: Exception) {
            dateString
        }
    }

    /**
     * Check if a date string represents a date in the past
     */
    fun isOverdue(dateString: String?): Boolean {
        if (dateString.isNullOrBlank()) return false

        return try {
            val datePart = dateString.substringBefore("T")
            val date = LocalDate.parse(datePart)
            val today = getToday()
            date < today
        } catch (e: Exception) {
            false
        }
    }

    /**
     * Convert a local hour (0-23) to UTC hour
     * @param localHour Hour in the device's local timezone (0-23)
     * @return Hour in UTC (0-23)
     */
    fun localHourToUtc(localHour: Int): Int {
        val tz = TimeZone.currentSystemDefault()
        val nowMillis = Clock.System.now().toEpochMilliseconds()
        val now = Instant.fromEpochMilliseconds(nowMillis)
        val today = now.toLocalDateTime(tz).date

        // Create a LocalDateTime with the given local hour
        val localDateTime = LocalDateTime(today, LocalTime(localHour, 0))

        // Convert to UTC instant, then to UTC datetime
        val instant = localDateTime.toInstant(tz)
        val utcDateTime = instant.toLocalDateTime(TimeZone.UTC)

        return utcDateTime.hour
    }

    /**
     * Convert a UTC hour (0-23) to local hour
     * @param utcHour Hour in UTC (0-23)
     * @return Hour in the device's local timezone (0-23)
     */
    fun utcHourToLocal(utcHour: Int): Int {
        val tz = TimeZone.currentSystemDefault()
        val nowMillis = Clock.System.now().toEpochMilliseconds()
        val now = Instant.fromEpochMilliseconds(nowMillis)
        val today = now.toLocalDateTime(TimeZone.UTC).date

        // Create a LocalDateTime in UTC with the given UTC hour
        val utcDateTime = LocalDateTime(today, LocalTime(utcHour, 0))

        // Convert to local instant, then to local datetime
        val instant = utcDateTime.toInstant(TimeZone.UTC)
        val localDateTime = instant.toLocalDateTime(tz)

        return localDateTime.hour
    }

    /**
     * Get the current timezone offset in hours from UTC
     * @return Offset in hours (e.g., -6 for CST)
     */
    fun getTimezoneOffsetHours(): Int {
        val tz = TimeZone.currentSystemDefault()
        val nowMillis = Clock.System.now().toEpochMilliseconds()
        val now = Instant.fromEpochMilliseconds(nowMillis)

        // Get UTC hour and local hour for the same instant
        val utcHour = now.toLocalDateTime(TimeZone.UTC).hour
        val localHour = now.toLocalDateTime(tz).hour

        // Calculate offset (handle day boundary)
        var offset = localHour - utcHour
        if (offset > 12) offset -= 24
        if (offset < -12) offset += 24

        return offset
    }

    /**
     * Format an hour (0-23) to a human-readable 12-hour format
     * @param hour Hour in 24-hour format (0-23)
     * @return Formatted string like "8:00 AM" or "2:00 PM"
     */
    fun formatHour(hour: Int): String {
        return when {
            hour == 0 -> "12:00 AM"
            hour < 12 -> "$hour:00 AM"
            hour == 12 -> "12:00 PM"
            else -> "${hour - 12}:00 PM"
        }
    }
}
