         }
         UIApplication.shared.applicationIconBadgeNumber = 0
     }
+}
+
+private protocol NotificationScheduler {
+    func requestAuthorisation(completionHandler: @escaping (Bool, Error?) -> Void)
+    func scheduleNotification(at date: Date, badgeNumber: Int)
+    func scheduleNotification(at date: Date, body: String)
+    func removeAllNotifications()
+}
+
+private class LocalNotificationScheduler: NotificationScheduler {
+    func requestAuthorisation(completionHandler: @escaping (Bool, Error?) -> Void) {
+        UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil))
+        // We assume success
+        completionHandler(true, nil)
+    }
     
-    private func removeAllNotifications() {
+    func removeAllNotifications() {
         if #available(iOS 10.0, *) {
             os_log("Removing all notifications", type: .debug)
         }
         
-        if #available(iOS 10.0, *) {
-            let center = UNUserNotificationCenter.current()
-            center.removeAllPendingNotificationRequests()
-            center.removeAllDeliveredNotifications()
-        } else {
-            let application = UIApplication.shared
-            application.cancelAllLocalNotifications()
-        }
+        UIApplication.shared.cancelAllLocalNotifications()
     }
     
-    private func scheduleNotification(at date: Date, badgeNumber: Int) {
+    func scheduleNotification(at date: Date, badgeNumber: Int) {
         if #available(iOS 10.0, *) {
             os_log("Scheduling local notification with badge number %d at %@", type: .debug, badgeNumber, date as NSDate)
         }
         
-        if #available(iOS 10.0, *) {
-            let content = UNMutableNotificationContent()
-            content.badge = badgeNumber as NSNumber
-            
-            let dateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: date)
-            let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
-            
-            let request = UNNotificationRequest(identifier: "ACBadge-\(badgeNumber)", content: content, trigger: trigger)
-            let center = UNUserNotificationCenter.current()
-            center.add(request, withCompletionHandler: nil)
-        } else {
-            let localNotification = UILocalNotification()
-            localNotification.fireDate = date
-            localNotification.applicationIconBadgeNumber = badgeNumber
-            
-            UIApplication.shared.scheduleLocalNotification(localNotification)
-        }
+        let localNotification = UILocalNotification()
+        localNotification.fireDate = date
+        localNotification.applicationIconBadgeNumber = badgeNumber
+        
+        UIApplication.shared.scheduleLocalNotification(localNotification)
     }
     
-    private func scheduleNotification(at date: Date, body: String) {
+    func scheduleNotification(at date: Date, body: String) {
         if #available(iOS 10.0, *) {
             os_log("Scheduling local notification at %@", type: .debug, date as NSDate)
         }
         
-        if #available(iOS 10.0, *) {
-            let content = UNMutableNotificationContent()
-            content.body = body
-            content.sound = UNNotificationSound.default()
-            
-            let dateComponents = Calendar.current.dateComponents([.era, .year, .month, .day, .hour, .minute, .second], from: date)
-            let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
-            
-            let request = UNNotificationRequest(identifier: "ACText", content: content, trigger: trigger)
-            let center = UNUserNotificationCenter.current()
-            center.add(request, withCompletionHandler: nil)
-        } else {
-            let localNotification = UILocalNotification()
-            localNotification.fireDate = date
-            localNotification.alertBody = body
-            localNotification.soundName = UILocalNotificationDefaultSoundName
-            
-            UIApplication.shared.scheduleLocalNotification(localNotification)
-        }
+        let localNotification = UILocalNotification()
+        localNotification.fireDate = date
+        localNotification.alertBody = body
+        localNotification.soundName = UILocalNotificationDefaultSoundName
+        
+        UIApplication.shared.scheduleLocalNotification(localNotification)
     }
 }
+
+@available(iOS 10.0, *)
+private class UserNotificationScheduler: NotificationScheduler {
+    func requestAuthorisation(completionHandler: @escaping (Bool, Error?) -> Void) {
+        let center = UNUserNotificationCenter.current()
+        center.requestAuthorization(options: [.alert, .badge, .sound], completionHandler: completionHandler)
+    }
+    
+    func removeAllNotifications() {
+        os_log("Removing all notifications", type: .debug)
+        
+        let center = UNUserNotificationCenter.current()
+        center.removeAllPendingNotificationRequests()
+        center.removeAllDeliveredNotifications()
+    }
+    
+    func scheduleNotification(at date: Date, badgeNumber: Int) {
+        os_log("Scheduling local notification with badge number %d at %@", type: .debug, badgeNumber, date as NSDate)
+        
+        let content = UNMutableNotificationContent()
+        content.badge = badgeNumber as NSNumber
+        
+        let dateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: date)
+        let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
+        
+        let request = UNNotificationRequest(identifier: "ACBadge-\(badgeNumber)", content: content, trigger: trigger)
+        let center = UNUserNotificationCenter.current()
+        center.add(request, withCompletionHandler: nil)
+    }
+    
+    func scheduleNotification(at date: Date, body: String) {
+        os_log("Scheduling local notification at %@", type: .debug, date as NSDate)
+        
+        let content = UNMutableNotificationContent()
+        content.body = body
+        content.sound = UNNotificationSound.default()
+        
+        let dateComponents = Calendar.current.dateComponents([.era, .year, .month, .day, .hour, .minute, .second], from: date)
+        let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
+        
+        let request = UNNotificationRequest(identifier: "ACText", content: content, trigger: trigger)
+        let center = UNUserNotificationCenter.current()
+        center.add(request, withCompletionHandler: nil)
+    }
+}

    
    public func scheduleNotifications(resourceRepository: ResourceRepositoryReader) {
        do {
            removeAllNotifications()
            
            let now = Date()
            let reviewTimeline = try resourceRepository.reviewTimeline()
            
            let currentReviewCount = reviewTimeline.lazy.filter { review in review.dateAvailable <= now }.reduce(0) { count, review in count + review.itemCounts.total }
            if #available(iOS 10.0, *) {
                os_log("Badging app icon: %d", type: .debug, currentReviewCount)
            }
            
            UIApplication.shared.applicationIconBadgeNumber = currentReviewCount
            
            let futureReviews = reviewTimeline.lazy.filter { review in review.dateAvailable > now }.prefix(48)
            let nextReviewDate = futureReviews.first?.dateAvailable
            
            if let nextReviewDate = nextReviewDate, currentReviewCount == 0 {
                scheduleNotification(at: nextReviewDate, body: "You have new WaniKani reviews available")
            }
            
            var cumulativeReviewTotal = currentReviewCount
            for review in futureReviews {
                cumulativeReviewTotal += review.itemCounts.total
                scheduleNotification(at: review.dateAvailable, badgeNumber: cumulativeReviewTotal)
            }
        } catch ResourceRepositoryError.noDatabase {
            clearBadgeNumberAndRemoveAllNotifications()

    
    public func clearBadgeNumberAndRemoveAllNotifications() {
        clearBadgeNumber()
        notificationScheduler.removeAllNotifications()
    }
    
    private func clearBadgeNumber() {
