//
//  CountdownScheduler.swift
//  Countdown
//
//  Created by Laurent Morvillier on 15/01/2023.
//

import Foundation
import UserNotifications

class CountdownScheduler {
    
    static let master = CountdownScheduler()
    
    static let notificationIdSeparator: String = "||"
    
    func scheduleIfPossible(countdown: Countdown, handler: @escaping (Result<Date?, Error>) -> Void) {
        self.cancelCurrentNotifications(countdownId: countdown.stringId)
        self._scheduleCountdownNotification(countdown: countdown, handler: handler)
    }
    
    func cancelCurrentNotifications(countdownId: String) {
        
        UNUserNotificationCenter.current().getPendingNotificationRequests { requests in
            let ids = requests.map { $0.identifier }.filter { $0.hasPrefix(countdownId) }
            UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: ids)
        }
        
//        Conductor.maestro.cancelCountdown(id: countdownId)
    }
    
    fileprivate func _scheduleCountdownNotification(countdown: Countdown, handler: @escaping (Result<Date?, Error>) -> Void) {
        let content = UNMutableNotificationContent()
        content.title = NSLocalizedString("It's time!", comment: "")
        
        let duration = countdown.duration
        let body: String
        if let name = countdown.activity?.name {
            body = NSLocalizedString("Time's up for \(name)!", comment: "")
        } else {
            body = NSLocalizedString("Your \(duration.minuteSecond) countdown is over!", comment: "")
        }
        
        content.body = body
        
        let sound = countdown.soundName
        print("Selected sound = \(sound)")
//        content.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: sound))
        
        content.sound = UNNotificationSound.criticalSoundNamed(UNNotificationSoundName(rawValue: sound), withAudioVolume: 1.0)
        content.interruptionLevel = .critical
        content.relevanceScore = 1.0

        let notificationCount = 1 + countdown.repeatCount
        
//        self._createNotification(countdown: countdown, content: content, handler: handler)
        
        for i in 0..<notificationCount {
            let offset = Double(i) * 10.0 // every 30 seconds
            self._createNotification(countdown: countdown, offset: offset, content: content, handler: handler)
        }
        
    }
    
    fileprivate func _createNotification(countdown: Countdown, offset: TimeInterval = 0.0, content: UNMutableNotificationContent, handler: @escaping (Result<Date?, Error>) -> Void) {
        
        let duration = countdown.duration
        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: duration + offset, repeats: false)
        
        let identifier: String = [countdown.objectID.uriRepresentation().absoluteString, "\(offset)"].joined(separator: CountdownScheduler.notificationIdSeparator)
        
        let request = UNNotificationRequest(identifier: identifier,
                                            content: content,
                                            trigger: trigger)
        UNUserNotificationCenter.current().add(request) { error in
            DispatchQueue.main.async {
                if let error {
                    handler(.failure(error))
                    print("Scheduling error = \(error)")
                } else {
                    
                    if offset == 0.0 {
                        if let triggerDate = trigger.nextTriggerDate() {
                            Conductor.maestro.startCountdown(triggerDate, countdown: countdown)
                            handler(.success(trigger.nextTriggerDate()))
                        } else {
                            let backupDate = Date().addingTimeInterval(duration)
                            Conductor.maestro.startCountdown(backupDate, countdown: countdown)
                        }
                    }
                }
            }
        }
        
    }
    
}
