import APIClient
import Foundation
import Localization
import OrderedCollections

struct ProcessedInAppNotificationData {
    let lastNotifiedAt: Date?
    let hasUnreadNotifications: Bool
    let wrappedNotifications: [InAppNotificationItem]
}

public enum InAppNotificationProcessing {
    static func processResponse(_ responseVersion: InAppNotificationClient.ResponseVersion) -> ProcessedInAppNotificationData {
        let wrappedNotifications: [InAppNotificationItem]
        let notifiedAt: Date?
        switch responseVersion {
        case .v1(let response):
            notifiedAt = response.notifiedAt
            wrappedNotifications = response.notifications.map { .v1($0) }

        case .v2(let response):
            notifiedAt = response.notifiedAt
            wrappedNotifications = response.notifications.map { .v2($0) }
        }

        let hasUnread = hasNotifications(wrappedNotifications)

        return ProcessedInAppNotificationData(
            lastNotifiedAt: notifiedAt,
            hasUnreadNotifications: hasUnread,
            wrappedNotifications: wrappedNotifications
        )
    }

    static func updateFollowOnNotifications(
        _ groupedMap: OrderedNotificationMap,
        handle: String,
        isFollowing: Bool
    ) -> OrderedNotificationMap {
        var mutableGrouped = groupedMap
        mutableGrouped.updateAllItems { item in
            guard item.notificationType == .follow else { return item }
            return item.updatedUserProfile(isFollowing: isFollowing, handle: handle)
        }
        return mutableGrouped
    }

    public static func groupedNotifications(
        _ notifications: [InAppNotificationItem]
    ) -> OrderedNotificationMap {
        var notificationMap = OrderedNotificationMap()
        let uniqueValues = getLatestAllowedUniqueNotifications(notifications)
        for notification in uniqueValues {
            notificationMap.addItem(notification)
        }
        notificationMap.sortAllCategories()
        return notificationMap
    }
}

private extension InAppNotificationProcessing {
    static func hasNotifications(_ notificationItems: [InAppNotificationItem]) -> Bool {
        var result = false
        for item in notificationItems {
            if item.notificationType.canBeRead && item.isUnread {
                result = true
            }
        }
        return result
    }

    static func getLatestAllowedUniqueNotifications(
        _ notifications: [InAppNotificationItem]) -> [InAppNotificationItem]
    {
        /*
            De-Dup
            Only use latest version of notification
         */
        let restrictedTypes = InAppNotificationClient.restrictedNotificationTypes

        var uniqueLatestMap: [String: InAppNotificationItem] = [:]
        for notification in notifications {
            if restrictedTypes.contains(notification.notificationType) {
                continue
            }

            if let current = uniqueLatestMap[notification.id] {
                if current.createdAt < notification.createdAt {
                    uniqueLatestMap[notification.id] = notification
                }
            } else {
                uniqueLatestMap[notification.id] = notification
            }
        }

        let uniqueValues: [InAppNotificationItem] = uniqueLatestMap.values.compactMap { $0 }
        return uniqueValues
    }
}
