//: Advanced Dates and Times in Swift

import Foundation

#if os(macOS)
    import PlaygroundSupport
    import UserNotifications
#endif

// Date Intervals

let calendar = Calendar.autoupdatingCurrent
let timeZone = TimeZone(identifier: "America/Denver")!

let talkStart = DateComponents(
    timeZone: timeZone,
    year: 2017, month: 8, day: 14,
    hour: 15, minute: 45, second: 00)

let talkEnd = DateComponents(
    timeZone: timeZone,
    year: 2017, month: 8, day: 14,
    hour: 16, minute: 30, second: 00)

let startDate = calendar.date(from: talkStart)!
let endDate = calendar.date(from: talkEnd)!

let talkInterval = DateInterval(
    start: startDate,
    end: endDate)

// 2700
talkInterval.duration

// "2017-08-14 21:45:00 +0000 to 2017-08-14 22:30:00 +0000"
talkInterval.description

// true
talkInterval.contains(Date())

// Date Interval Formatting

let formatter = DateIntervalFormatter()

formatter.string(from: talkInterval)
// "8/14/17, 3:45 - 4:30 PM"

var prefix = ""

if calendar.isDateInToday(startDate) && calendar.isDateInToday(endDate) {
    formatter.dateStyle = .none
    prefix = "Today "
}
else if calendar.isDateInYesterday(startDate) && calendar.isDateInYesterday(endDate) {
    formatter.dateStyle = .none
    prefix = "Yesterday "
}
else if calendar.isDateInTomorrow(startDate) && calendar.isDateInTomorrow(endDate) {
    formatter.dateStyle = .none
    prefix = "Tomorrow "
}
else {
    formatter.dateStyle = .short
}

prefix + formatter.string(from: talkInterval)!
// "Today 3:45 – 4:30 PM"

// Converting Between Units

// How many days are there in this month?
calendar.range(of: Calendar.Component.day, in: Calendar.Component.month, for: Date())!

// Range(1..<31)

// How many days are there in this year?
calendar.range(of: .day, in: .year, for: Date())

// Range(1..<32)

calendar.maximumRange(of: .second)
// Range(0..<60)

calendar.minimumRange(of: .day)
// Range(1..<29)

// How many seconds are there in this year?
calendar.range(of: .second, in: .year, for: Date())

// Range(0..<60)

let monthRange = calendar.range(of: .month, in: .year, for: Date())!

for month in monthRange.lowerBound ..< monthRange.upperBound {
    let date = calendar.date(bySetting: .month, value: month, of: Date())!
    
    let dayRange = calendar.range(of: .day, in: .month, for: date)!
    
    for day in dayRange.lowerBound ..< dayRange.upperBound {
        let date = calendar.date(bySetting: .day, value: day, of: date)!
        
        let hourRange = calendar.range(of: .hour, in: .day, for: date)!
        
        for hour in hourRange.lowerBound ..< hourRange.upperBound {
            // This is getting out of hand!
        }
    }
}

// Measure time interval
let year = 2017

let beginningOfAnyYearComponents = DateComponents(
    month: 1,
    day: 1,
    hour: 0,
    minute: 0,
    second: 0,
    nanosecond: 0)

var beginningOfThisYearComponents = beginningOfAnyYearComponents
beginningOfThisYearComponents.year = year

let beginningOfThisYear = calendar.date(from: beginningOfThisYearComponents)!

let beginningOfNextYear = calendar
    .nextDate(after: beginningOfThisYear,
              matching: beginningOfAnyYearComponents,
              matchingPolicy: .strict)!

let seconds = beginningOfNextYear.timeIntervalSince(beginningOfThisYear)

// Measure date interval
let interval = DateInterval(start: beginningOfThisYear,
                            end: beginningOfNextYear)

interval.duration

// Measure components
calendar.dateComponents([.second],
                        from: beginningOfThisYear,
                        to: beginningOfNextYear).second

calendar.dateComponents([.minute],
                        from: beginningOfThisYear,
                        to: beginningOfNextYear)

// Notifications
#if os(macOS)
let trigger =
    UNCalendarNotificationTrigger(dateMatching:beginningOfAnyYearComponents,
                                  repeats: true)

trigger.nextTriggerDate()
// "Jan 1, 2018 at 12:00 AM"

calendar.nextDate(after: Date(),
                  matching: beginningOfAnyYearComponents,
                  matchingPolicy: .nextTime)
// "Jan 1, 2018 at 12:00 AM"

let content = UNMutableNotificationContent()
content.title = "Happy new year!"

let request = UNNotificationRequest(identifier: "com.slaunchaman.happynewyear",
                                    content: content,
                                    trigger: trigger)

PlaygroundPage.current.needsIndefiniteExecution = true

UNUserNotificationCenter.current().add(request) { (error) in
    if let error = error {
        print("Error: \(error.localizedDescription)")
    }
    else {
        print("Success!")
    }
    
    PlaygroundPage.current.finishExecution()
}
#endif