import Foundation
import os.log
import UserNotifications

/// Representation of the 3 states of the Notifications permission prompt which may either have not been shown, or was shown and denied or accepted
/// Unknown is value to indicate that we have not yet determined the status and should not be used other than as a default value before determining the actual status
public enum NotificationPermissionPromptStatus: Int {
    case unknown, notShown, shownAndDenied, shownAndAccepted
}

public enum XcodesNotificationCategory: String {
    case normal
    case error
}

public enum XcodesNotificationType: String, Identifiable, CaseIterable, CustomStringConvertible {
    case newVersionAvailable
    case finishedInstalling

    public var id: Self { self }
    
    public var description: String {
        switch self {
            case .newVersionAvailable:
                return localizeString("Notification.NewVersionAvailable")
            case .finishedInstalling:
                return localizeString("Notification.FinishedInstalling")
        }
    }
}

public class NotificationManager: NSObject, UNUserNotificationCenterDelegate, ObservableObject {
    private let notificationCenter = UNUserNotificationCenter.current()
    
    @Published var notificationStatus = NotificationPermissionPromptStatus.unknown
    
    public override init() {
        super.init()
        loadNotificationStatus()
        
        notificationCenter.delegate = self
    }
    
    public func loadNotificationStatus() {
        UNUserNotificationCenter.current().getNotificationSettings(completionHandler: { [weak self] (settings) in
            let status = NotificationManager.systemPromptStatusFromSettings(settings)
            self?.notificationStatus = status
        })
    }
    
    private class func systemPromptStatusFromSettings(_ settings: UNNotificationSettings) -> NotificationPermissionPromptStatus {
        switch settings.authorizationStatus {
            case .notDetermined:
                return .notShown
            case .authorized, .provisional:
                return .shownAndAccepted
            case .denied:
                return .shownAndDenied
            @unknown default:
                return .unknown
        }
    }
    
    public func requestAccess() {
        
        notificationCenter.requestAuthorization(options: [.alert, .sound, .badge]) { [weak self] granted, error in
            DispatchQueue.main.async {
                if let error = error {
                    // Handle the error here.
                    Logger.appState.error("Error requesting notification accesss: \(error.legibleLocalizedDescription)")
                } else {
                    Logger.appState.log("User has \(granted ? "Granted" : "NOT GRANTED") notification permission")
                }
                self?.loadNotificationStatus()
            }
        }
    }
    
    func scheduleNotification(title: String?, body: String, category: XcodesNotificationCategory) {
          
        let content = UNMutableNotificationContent()
        if let title = title {
            content.title = title
        }
        content.body = body
        content.sound = .default
        content.categoryIdentifier = category.rawValue
        
        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.3, repeats: false)
        let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
        notificationCenter.add(request)
    }
    
    // MARK: UNUserNotificationCenterDelegate
    
    public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler( [.banner, .badge, .sound])
    }
}

