 import WaniKaniKit
 
 class NotificationManager {
+    private let notificationScheduler: NotificationScheduler
     private var assignmentsChangeObserver: NSObjectProtocol?
+    
+    init() {
+        if #available(iOS 10.0, *) {
+            notificationScheduler = UserNotificationScheduler()
+        } else {
+            notificationScheduler = LocalNotificationScheduler()
+        }
+    }
     
     deinit {
         unregisterForNotifications()
     }
     
     public func registerForNotifications(resourceRepository: ResourceRepositoryReader) {
-        if #available(iOS 10.0, *) {
-            let center = UNUserNotificationCenter.current()
-            center.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
-                if let error = error {
+        notificationScheduler.requestAuthorisation { (granted, error) in
+            if let error = error {
+                if #available(iOS 10.0, *) {
                     os_log("Got error from notification authorisation: %@", type: .error, error as NSError)
                 }
+            }
+            if #available(iOS 10.0, *) {
                 os_log("Notification authorisation granted = %@", type: .info, String(granted))
-                
-                if granted {
-                    self.listenForAssignmentChanges(resourceRepository: resourceRepository)
-                }
             }
-        } else {
-            UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil))
-            listenForAssignmentChanges(resourceRepository: resourceRepository)
+            
+            if granted {
+                self.listenForAssignmentChanges(resourceRepository: resourceRepository)
+            }
         }
     }
     

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

        }
        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)
    }
    
    func removeAllNotifications() {
        if #available(iOS 10.0, *) {
            os_log("Removing all notifications", type: .debug)
        }
        
        UIApplication.shared.cancelAllLocalNotifications()
    }
    
    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)
        }
        
        let localNotification = UILocalNotification()
        localNotification.fireDate = date
        localNotification.applicationIconBadgeNumber = badgeNumber
        
        UIApplication.shared.scheduleLocalNotification(localNotification)
    }
    
    func scheduleNotification(at date: Date, body: String) {
        if #available(iOS 10.0, *) {
            os_log("Scheduling local notification at %@", type: .debug, date as NSDate)
        }
        
        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)
    }
}
