import Foundation
import TelegramCore
import TelegramPresentationData

public func stringForTimestamp(day: Int32, month: Int32, year: Int32, dateTimeFormat: PresentationDateTimeFormat) -> String {
    let separator = dateTimeFormat.dateSeparator
    let suffix = dateTimeFormat.dateSuffix
    let displayYear = dateTimeFormat.requiresFullYear ? year - 100 + 2000 : year - 100
    switch dateTimeFormat.dateFormat {
    case .monthFirst:
        return String(format: "%02d%@%02d%@%02d%@", month, separator, day, separator, displayYear, suffix)
    case .dayFirst:
        return String(format: "%02d%@%02d%@%02d%@", day, separator, month, separator, displayYear, suffix)
    }
}

public func stringForTimestamp(day: Int32, month: Int32, dateTimeFormat: PresentationDateTimeFormat) -> String {
    let separator = dateTimeFormat.dateSeparator
    let suffix = dateTimeFormat.dateSuffix
    switch dateTimeFormat.dateFormat {
    case .monthFirst:
        return String(format: "%02d%@%02d%@", month, separator, day, suffix)
    case .dayFirst:
        return String(format: "%02d%@%02d%@", day, separator, month, suffix)
    }
}

public func shortStringForDayOfWeek(strings: PresentationStrings, day: Int32) -> String {
    switch day {
    case 0:
        return strings.Weekday_ShortSunday
    case 1:
        return strings.Weekday_ShortMonday
    case 2:
        return strings.Weekday_ShortTuesday
    case 3:
        return strings.Weekday_ShortWednesday
    case 4:
        return strings.Weekday_ShortThursday
    case 5:
        return strings.Weekday_ShortFriday
    case 6:
        return strings.Weekday_ShortSaturday
    default:
        return ""
    }
}

public func stringForMonth(strings: PresentationStrings, month: Int32) -> String {
    switch month {
    case 0:
        return strings.Month_GenJanuary
    case 1:
        return strings.Month_GenFebruary
    case 2:
        return strings.Month_GenMarch
    case 3:
        return strings.Month_GenApril
    case 4:
        return strings.Month_GenMay
    case 5:
        return strings.Month_GenJune
    case 6:
        return strings.Month_GenJuly
    case 7:
        return strings.Month_GenAugust
    case 8:
        return strings.Month_GenSeptember
    case 9:
        return strings.Month_GenOctober
    case 10:
        return strings.Month_GenNovember
    case 11:
        return strings.Month_GenDecember
    default:
        return ""
    }
}

public func stringForMonth(strings: PresentationStrings, month: Int32, ofYear year: Int32) -> String {
    let yearString = "\(1900 + year)"
    switch month {
    case 0:
        return strings.Time_MonthOfYear_m1(yearString).string
    case 1:
        return strings.Time_MonthOfYear_m2(yearString).string
    case 2:
        return strings.Time_MonthOfYear_m3(yearString).string
    case 3:
        return strings.Time_MonthOfYear_m4(yearString).string
    case 4:
        return strings.Time_MonthOfYear_m5(yearString).string
    case 5:
        return strings.Time_MonthOfYear_m6(yearString).string
    case 6:
        return strings.Time_MonthOfYear_m7(yearString).string
    case 7:
        return strings.Time_MonthOfYear_m8(yearString).string
    case 8:
        return strings.Time_MonthOfYear_m9(yearString).string
    case 9:
        return strings.Time_MonthOfYear_m10(yearString).string
    case 10:
        return strings.Time_MonthOfYear_m11(yearString).string
    default:
        return strings.Time_MonthOfYear_m12(yearString).string
    }
}

public enum RelativeTimestampFormatDay {
    case today
    case yesterday
    case tomorrow
}

public func stringForUserPresence(strings: PresentationStrings, day: RelativeTimestampFormatDay, dateTimeFormat: PresentationDateTimeFormat, hours: Int32, minutes: Int32) -> String {
    let dayString: String
    switch day {
    case .today, .tomorrow:
        dayString = strings.LastSeen_TodayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).string
    case .yesterday:
        dayString = strings.LastSeen_YesterdayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).string
    }
    return dayString
}

private func humanReadableStringForTimestamp(strings: PresentationStrings, day: RelativeTimestampFormatDay, dateTimeFormat: PresentationDateTimeFormat, hours: Int32, minutes: Int32, format: HumanReadableStringFormat? = nil) -> PresentationStrings.FormattedString {
    let result: PresentationStrings.FormattedString
    switch day {
        case .today:
            let string = stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)
            result = format?.todayFormatString(string) ?? strings.Time_TodayAt(string)
        case .yesterday:
            let string = stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)
            result = format?.yesterdayFormatString(string) ?? strings.Time_YesterdayAt(string)
        case .tomorrow:
            let string = stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)
            result = format?.tomorrowFormatString(string) ?? strings.Time_TomorrowAt(string)
        
    }
    return result
}

public struct HumanReadableStringFormat {
    let dateFormatString: (String) -> PresentationStrings.FormattedString
    let tomorrowFormatString: (String) -> PresentationStrings.FormattedString
    let todayFormatString: (String) -> PresentationStrings.FormattedString
    let yesterdayFormatString: (String) -> PresentationStrings.FormattedString
    
    public init(
        dateFormatString: @escaping (String) -> PresentationStrings.FormattedString,
        tomorrowFormatString: @escaping (String) -> PresentationStrings.FormattedString,
        todayFormatString: @escaping (String) -> PresentationStrings.FormattedString,
        yesterdayFormatString: @escaping (String) -> PresentationStrings.FormattedString = { PresentationStrings.FormattedString(string: $0, ranges: []) }
    ) {
        self.dateFormatString = dateFormatString
        self.tomorrowFormatString = tomorrowFormatString
        self.todayFormatString = todayFormatString
        self.yesterdayFormatString = yesterdayFormatString
    }
}

public func humanReadableStringForTimestamp(strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, timestamp: Int32, alwaysShowTime: Bool = false, allowYesterday: Bool = true, format: HumanReadableStringFormat? = nil) -> PresentationStrings.FormattedString {
    var t: time_t = time_t(timestamp)
    var timeinfo: tm = tm()
    localtime_r(&t, &timeinfo)
    
    let timestampNow = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
    var now: time_t = time_t(timestampNow)
    var timeinfoNow: tm = tm()
    localtime_r(&now, &timeinfoNow)
    
    if timeinfo.tm_year != timeinfoNow.tm_year {
        let string: String
        if alwaysShowTime {
            string = stringForMediumDate(timestamp: timestamp, strings: strings, dateTimeFormat: dateTimeFormat)
        } else {
            string = stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)
        }
        return format?.dateFormatString(string) ?? PresentationStrings.FormattedString(string: string, ranges: [])
    }
    
    let dayDifference = timeinfo.tm_yday - timeinfoNow.tm_yday
    if dayDifference == 0 || (dayDifference == -1 && allowYesterday) || dayDifference == 1 {
        let day: RelativeTimestampFormatDay
        if dayDifference == 0 {
            day = .today
        } else if dayDifference == -1 {
            day = .yesterday
        } else {
            day = .tomorrow
        }
        return humanReadableStringForTimestamp(strings: strings, day: day, dateTimeFormat: dateTimeFormat, hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, format: format)
    } else {
        let string: String
        if alwaysShowTime {
            string = stringForMediumDate(timestamp: timestamp, strings: strings, dateTimeFormat: dateTimeFormat)
        } else {
            string = stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)
        }
        return format?.dateFormatString(string) ?? PresentationStrings.FormattedString(string: string, ranges: [])
    }
}

public enum RelativeUserPresenceLastSeen {
    case justNow
    case minutesAgo(Int32)
    case hoursAgo(Int32)
    case todayAt(hours: Int32, minutes: Int32)
    case yesterdayAt(hours: Int32, minutes: Int32)
    case thisYear(month: Int32, day: Int32)
    case atDate(year: Int32, month: Int32)
}

public enum RelativeUserPresenceStatus {
    case offline
    case online(at: Int32)
    case lastSeen(at: Int32)
    case recently
    case lastWeek
    case lastMonth
}

public func relativeUserPresenceStatus(_ presence: EnginePeer.Presence, relativeTo timestamp: Int32) -> RelativeUserPresenceStatus {
    switch presence.status {
    case .longTimeAgo:
        return .offline
    case let .present(statusTimestamp):
        if statusTimestamp >= timestamp {
            return .online(at: statusTimestamp)
        } else {
            return .lastSeen(at: statusTimestamp)
        }
    case .recently:
        let activeUntil = presence.lastActivity + 30
        if activeUntil >= timestamp {
            return .online(at: activeUntil)
        } else {
            return .recently
        }
    case .lastWeek:
        return .lastWeek
    case .lastMonth:
        return .lastMonth
    }
}

public func stringForRelativeTimestamp(strings: PresentationStrings, relativeTimestamp: Int32, relativeTo timestamp: Int32, dateTimeFormat: PresentationDateTimeFormat) -> String {
    var t: time_t = time_t(relativeTimestamp)
    var timeinfo: tm = tm()
    localtime_r(&t, &timeinfo)
    
    var now: time_t = time_t(timestamp)
    var timeinfoNow: tm = tm()
    localtime_r(&now, &timeinfoNow)
    
    if timeinfo.tm_year != timeinfoNow.tm_year {
        return stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)
    }
    
    let dayDifference = timeinfo.tm_yday - timeinfoNow.tm_yday
    if dayDifference > -7 {
        if dayDifference == 0 {
            return stringForShortTimestamp(hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, dateTimeFormat: dateTimeFormat)
        } else {
            return shortStringForDayOfWeek(strings: strings, day: timeinfo.tm_wday)
        }
    } else {
        return stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, dateTimeFormat: dateTimeFormat)
    }
}

public func stringForPreciseRelativeTimestamp(strings: PresentationStrings, relativeTimestamp: Int32, relativeTo timestamp: Int32, dateTimeFormat: PresentationDateTimeFormat) -> String {
    var t: time_t = time_t(relativeTimestamp)
    var timeinfo: tm = tm()
    localtime_r(&t, &timeinfo)
    
    var now: time_t = time_t(timestamp)
    var timeinfoNow: tm = tm()
    localtime_r(&now, &timeinfoNow)
    
    let dayDifference = timeinfo.tm_yday - timeinfoNow.tm_yday
    if dayDifference == 0 {
        return stringForShortTimestamp(hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, dateTimeFormat: dateTimeFormat)
    } else {
        return "\(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)), \(stringForShortTimestamp(hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, dateTimeFormat: dateTimeFormat))"
    }
}

public func stringForRelativeLiveLocationTimestamp(strings: PresentationStrings, relativeTimestamp: Int32, relativeTo timestamp: Int32, dateTimeFormat: PresentationDateTimeFormat) -> String {
    let difference = timestamp - relativeTimestamp
    if difference < 60 {
        return strings.LiveLocationUpdated_JustNow
    } else if difference < 60 * 60 {
        let minutes = difference / 60
        return strings.LiveLocationUpdated_MinutesAgo(minutes)
    } else {
        var t: time_t = time_t(relativeTimestamp)
        var timeinfo: tm = tm()
        localtime_r(&t, &timeinfo)
        
        var now: time_t = time_t(timestamp)
        var timeinfoNow: tm = tm()
        localtime_r(&now, &timeinfoNow)
        
        let dayDifference = timeinfo.tm_yday - timeinfoNow.tm_yday
        
        let hours = timeinfo.tm_hour
        let minutes = timeinfo.tm_min
        
        if dayDifference == 0 {
            return strings.LiveLocationUpdated_TodayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).string
        } else {
            return stringForFullDate(timestamp: relativeTimestamp, strings: strings, dateTimeFormat: dateTimeFormat)
        }
    }
}

public func stringForRelativeSymbolicTimestamp(strings: PresentationStrings, relativeTimestamp: Int32, relativeTo timestamp: Int32, dateTimeFormat: PresentationDateTimeFormat) -> String {
    var t: time_t = time_t(relativeTimestamp)
    var timeinfo: tm = tm()
    localtime_r(&t, &timeinfo)
    
    var now: time_t = time_t(timestamp)
    var timeinfoNow: tm = tm()
    localtime_r(&now, &timeinfoNow)
    
    let dayDifference = timeinfo.tm_yday - timeinfoNow.tm_yday
    
    let hours = timeinfo.tm_hour
    let minutes = timeinfo.tm_min
    
    if dayDifference == 0 {
        return strings.Time_TodayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).string
    } else {
        return stringForFullDate(timestamp: relativeTimestamp, strings: strings, dateTimeFormat: dateTimeFormat)
    }
}

public func stringForRelativeLiveLocationUpdateTimestamp(strings: PresentationStrings, relativeTimestamp: Int32, relativeTo timestamp: Int32, dateTimeFormat: PresentationDateTimeFormat) -> String {
    var t: time_t = time_t(relativeTimestamp)
    var timeinfo: tm = tm()
    localtime_r(&t, &timeinfo)
    
    var now: time_t = time_t(timestamp)
    var timeinfoNow: tm = tm()
    localtime_r(&now, &timeinfoNow)
    
    if timeinfo.tm_year != timeinfoNow.tm_year {
        return stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)
    }
    
    let dayDifference = timeinfo.tm_yday - timeinfoNow.tm_yday
    if dayDifference > -7 {
        if dayDifference == 0 {
            return stringForShortTimestamp(hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, dateTimeFormat: dateTimeFormat)
        } else {
            return shortStringForDayOfWeek(strings: strings, day: timeinfo.tm_wday)
        }
    } else {
        return stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, dateTimeFormat: dateTimeFormat)
    }
}

private func monthAtIndex(_ index: Int, strings: PresentationStrings) -> String {
    switch index {
        case 0:
            return strings.Month_GenJanuary
        case 1:
            return strings.Month_GenFebruary
        case 2:
            return strings.Month_GenMarch
        case 3:
            return strings.Month_GenApril
        case 4:
            return strings.Month_GenMay
        case 5:
            return strings.Month_GenJune
        case 6:
            return strings.Month_GenJuly
        case 7:
            return strings.Month_GenAugust
        case 8:
            return strings.Month_GenSeptember
        case 9:
            return strings.Month_GenOctober
        case 10:
            return strings.Month_GenNovember
        case 11:
            return strings.Month_GenDecember
        default:
            return ""
    }
}

public func stringForRelativeActivityTimestamp(strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, preciseTime: Bool = false, relativeTimestamp: Int32, relativeTo timestamp: Int32) -> String {
    let difference = timestamp - relativeTimestamp
    if difference < 60 {
        return strings.Time_JustNow
    } else if difference < 60 * 60 {
        let minutes = difference / 60
        return strings.Time_MinutesAgo(minutes)
    } else {
        var t: time_t = time_t(relativeTimestamp)
        var timeinfo: tm = tm()
        localtime_r(&t, &timeinfo)
        
        var now: time_t = time_t(timestamp)
        var timeinfoNow: tm = tm()
        localtime_r(&now, &timeinfoNow)
        
        if timeinfo.tm_year != timeinfoNow.tm_year {
            return strings.Time_AtDate(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)).string
        }
        
        let dayDifference = timeinfo.tm_yday - timeinfoNow.tm_yday
        if dayDifference == 0 || dayDifference == -1 {
            let day: RelativeTimestampFormatDay
            if dayDifference == 0 {
                let minutes = difference / (60 * 60)
                return strings.Time_HoursAgo(minutes)
            } else {
                day = .yesterday
            }
            return humanReadableStringForTimestamp(strings: strings, day: day, dateTimeFormat: dateTimeFormat, hours: timeinfo.tm_hour, minutes: timeinfo.tm_min).string
        } else if preciseTime {
            return strings.Time_AtPreciseDate(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat), stringForShortTimestamp(hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, dateTimeFormat: dateTimeFormat)).string
        } else {
            return strings.Time_AtDate(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)).string
        }
    }
}

public func stringForStoryActivityTimestamp(strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, preciseTime: Bool = false, relativeTimestamp: Int32, relativeTo timestamp: Int32) -> String {
    let difference = timestamp - relativeTimestamp
    if difference < 60 {
        return strings.Time_JustNow
    } else if difference < 60 * 60 {
        let minutes = difference / 60
        return strings.Time_MinutesAgo(minutes)
    } else {
        var t: time_t = time_t(relativeTimestamp)
        var timeinfo: tm = tm()
        localtime_r(&t, &timeinfo)
        
        var now: time_t = time_t(timestamp)
        var timeinfoNow: tm = tm()
        localtime_r(&now, &timeinfoNow)
        
        if timeinfo.tm_year != timeinfoNow.tm_year {
            return strings.Time_AtDate(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)).string
        }
        
        let dayDifference = timeinfo.tm_yday - timeinfoNow.tm_yday
        if dayDifference == 0 || dayDifference == -1 {
            let day: RelativeTimestampFormatDay
            if dayDifference == 0 {
                let minutes = difference / (60 * 60)
                return strings.Time_HoursAgo(minutes)
            } else {
                day = .yesterday
            }
            return humanReadableStringForTimestamp(strings: strings, day: day, dateTimeFormat: dateTimeFormat, hours: timeinfo.tm_hour, minutes: timeinfo.tm_min).string
        } else if preciseTime {
            let yearDate: String
            if timeinfo.tm_year == timeinfoNow.tm_year {
                if timeinfo.tm_yday == timeinfoNow.tm_yday {
                    yearDate = strings.Weekday_Today
                } else {
                    yearDate = strings.Date_ChatDateHeader(monthAtIndex(Int(timeinfo.tm_mon), strings: strings), "\(timeinfo.tm_mday)").string
                }
            } else {
                yearDate = strings.Date_ChatDateHeaderYear(monthAtIndex(Int(timeinfo.tm_mon), strings: strings), "\(timeinfo.tm_mday)", "\(1900 + timeinfo.tm_year)").string
            }
            
            return strings.Time_AtPreciseDate(yearDate, stringForShortTimestamp(hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, dateTimeFormat: dateTimeFormat)).string
        } else {
            return strings.Time_AtDate(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)).string
        }
    }
}

public func stringAndActivityForUserPresence(strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, presence: EnginePeer.Presence, relativeTo timestamp: Int32, expanded: Bool = false) -> (String, Bool) {
    switch presence.status {
    case let .present(statusTimestamp):
        if statusTimestamp >= timestamp {
            return (strings.Presence_online, true)
        } else {
            let difference = timestamp - statusTimestamp
            if difference < 60 {
                return (strings.LastSeen_JustNow, false)
            } else if difference < 60 * 60 && !expanded {
                let minutes = difference / 60
                return (strings.LastSeen_MinutesAgo(minutes), false)
            } else {
                var t: time_t = time_t(statusTimestamp)
                var timeinfo: tm = tm()
                localtime_r(&t, &timeinfo)
                
                var now: time_t = time_t(timestamp)
                var timeinfoNow: tm = tm()
                localtime_r(&now, &timeinfoNow)
                
                if timeinfo.tm_year != timeinfoNow.tm_year {
                    return (strings.LastSeen_AtDate(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)).string, false)
                }
                
                let dayDifference = timeinfo.tm_yday - timeinfoNow.tm_yday
                if dayDifference == 0 || dayDifference == -1 {
                    let day: RelativeTimestampFormatDay
                    if dayDifference == 0 {
                        if expanded {
                            day = .today
                        } else {
                            let minutes = difference / (60 * 60)
                            return (strings.LastSeen_HoursAgo(minutes), false)
                        }
                    } else {
                        day = .yesterday
                    }
                    return (stringForUserPresence(strings: strings, day: day, dateTimeFormat: dateTimeFormat, hours: timeinfo.tm_hour, minutes: timeinfo.tm_min), false)
                } else {
                    return (strings.LastSeen_AtDate(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)).string, false)
                }
            }
        }
    case .recently:
        let activeUntil = presence.lastActivity + 30
        if activeUntil >= timestamp {
            return (strings.Presence_online, true)
        } else {
            return (strings.LastSeen_Lately, false)
        }
    case .lastWeek:
        return (strings.LastSeen_WithinAWeek, false)
    case .lastMonth:
        return (strings.LastSeen_WithinAMonth, false)
    case .longTimeAgo:
        return (strings.LastSeen_ALongTimeAgo, false)
    }
}

public func peerStatusExpirationString(statusTimestamp: Int32, relativeTo timestamp: Int32, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) -> String {
    let difference = max(statusTimestamp - timestamp, 60)
    if difference < 60 * 60 {
        return strings.PeerStatusExpiration_Minutes(Int32(round(Double(difference) / Double(60))))
    } else if difference < 24 * 60 * 60 {
        return strings.PeerStatusExpiration_Hours(Int32(round(Double(difference) / Double(60 * 60))))
    } else {
        var t: time_t = time_t(statusTimestamp)
        var timeinfo: tm = tm()
        localtime_r(&t, &timeinfo)
        
        var now: time_t = time_t(timestamp)
        var timeinfoNow: tm = tm()
        localtime_r(&now, &timeinfoNow)
        
        let dayDifference = timeinfo.tm_yday - timeinfoNow.tm_yday
        if dayDifference == 1 {
            return strings.PeerStatusExpiration_TomorrowAt(stringForShortTimestamp(hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, dateTimeFormat: dateTimeFormat)).string
        } else {
            return strings.PeerStatusExpiration_AtDate(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, dateTimeFormat: dateTimeFormat)).string
        }
    }
}

public func userPresenceStringRefreshTimeout(_ presence: TelegramUserPresence, relativeTo timestamp: Int32) -> Double {
    switch presence.status {
    case let .present(statusTimestamp):
        if statusTimestamp >= timestamp {
            return Double(statusTimestamp - timestamp)
        } else {
            let difference = timestamp - statusTimestamp
            if difference < 30 {
                return Double((30 - difference) + 1)
            } else if difference < 60 * 60 {
                return Double((difference % 60) + 1)
            } else {
                return Double.infinity
            }
        }
    case .recently:
        let activeUntil = presence.lastActivity + 30
        if activeUntil >= timestamp {
            return Double(activeUntil - timestamp + 1)
        } else {
            return Double.infinity
        }
    case .none, .lastWeek, .lastMonth:
        return Double.infinity
    }
}


public func stringForRemainingMuteInterval(strings: PresentationStrings, muteInterval value: Int32) -> String {
    let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
    let value = max(1 * 60, value - timestamp)
    if value <= 1 * 60 * 60 {
        return strings.MuteExpires_Minutes(Int32(round(Float(value) / 60)))
    } else if value <= 24 * 60 * 60 {
        return strings.MuteExpires_Hours(Int32(round(Float(value) / (60 * 60))))
    } else {
        return strings.MuteExpires_Days(Int32(round(Float(value) / (24 * 60 * 60))))
    }
}