import SwiftUI

private extension Topic {
    var messagingTopic: String {
        self.slug.alphanumeric
    }
}

struct NotificationSettingsView: View {
    @EnvironmentObject private var userService: UserService
    
    @State private var showPushToken: Bool = false
    
    var body: some View {
        Group {
            if let settings = userService.notificationSettings {
                switch settings.authorizationStatus {
                case .denied:
                    Text("You have denied permission for notifications.")
                        .textStyle(.body)
                        .multilineTextAlignment(.center)
                        .padding(.horizontal)
                    
                default:
                    ScrollView {
                        VStack() {
                            Text("Select the topics you'd like to be notified about.")
                                .textStyle(.body)
                                .multilineTextAlignment(.center)
                                .padding(.bottom, 40)
                            
                            NotificationsOptions()
                            
                            Text(showPushToken ? "Hide push token" : "Show push token")
                                .textStyle(.caption2)
                                .onTapGesture(count: 1) {
                                    withAnimation {
                                        showPushToken.toggle()
                                    }
                                }
                            
                            if showPushToken {
                                PushTokenView()
                                    .padding()
                            }
                        }
                        .padding()
                    }
                    .background(ColorName.background.color.ignoresSafeArea())
                }
            }
            
        }
        .background(
            ColorName.background.color.ignoresSafeArea()
        )
        .navigationTitle("Notifications")
    }
}

struct NotificationsOptions: View {
    @EnvironmentObject private var userService: UserService
    @EnvironmentObject private var contentService: ContentService

    var enablePersonalNotifications: Bool {
        get {
            switch userService.signedInState {
            case .unknown, .signedOut, .error:
                return false
            case .signedIn(_):
                return true
            }
        }
    }
       
    private var notificationTypes: [NotificationType] {
        [.replyToComments] + contentService.topics.compactMap { NotificationType.topic(topicSlug: $0.messagingTopic) }
    }
    
    private func titleForNotificationType(_ notificationType: NotificationType) -> String {
        if let topic = contentService.topics.first(where: { $0.messagingTopic == notificationType.messagingTopic }) {
            return topic.name
        }
        
        return notificationType.title
    }
    
    @State private var userSubscriptions: [NotificationType] = []
    
    var body: some View {
        VStack(alignment: .leading, spacing: 6) {
            ForEach(notificationTypes, id: \.self) { notificationType in
                let notificationBinding = Binding<Bool> {
                    userSubscriptions.contains(notificationType)
                } set: { newValue in
                    if newValue {
                        userSubscriptions = (userSubscriptions + [notificationType]).unique()
                    } else {
                        userSubscriptions = userSubscriptions.filter { $0 != notificationType }
                    }
                }
                
                Toggle(isOn: notificationBinding) {
                    SettingsRow(title: titleForNotificationType(notificationType),
                                subtitle: notificationType.requiresLogin ? "requires being signed in" : nil)
                }
                
                if notificationType != notificationTypes.last {
                    Divider()
                        .padding(.top, 6)
                        .padding(.bottom, 2)
                }
                
            }
        }
        .onAppear(perform: {
            userSubscriptions = userService.notificationSubscriptions
        })
        .onDisappear {
            let itemsToRemove = userService.notificationSubscriptions.filter { !userSubscriptions.contains($0) }
            let itemsToLeave = userService.notificationSubscriptions.filter { userSubscriptions.contains($0) }
            let itemsToAdd = userSubscriptions.filter { !itemsToLeave.contains($0) }
            
            unsubscribeFromNotificationTypes(itemsToRemove)
            subscribeToNotificationTypes(itemsToAdd)
        }
    }
    
    private func subscribeToNotificationTypes(_ notificationTypes: [NotificationType]) {
        Task {
            if let settings = userService.notificationSettings {
                switch settings.authorizationStatus {
                case .notDetermined:
                    await userService.requestNotificationPermission()
                default:
                    break
                }
            }
            
            userService.subscribeToNotificationTypes(notificationTypes)
        }
    }
    
    private func unsubscribeFromNotificationTypes(_ notificationTypes: [NotificationType]) {
        userService.unsubscribeFromNotificationTypes(notificationTypes)
    }
}

#if DEBUG
struct NotificationSettingsView_Previews: PreviewProvider {
    static var previews: some View {
        NotificationSettingsView()
            .environmentObject(ContentService.preview)
    }
}
#endif
