import FirebaseMessaging
import MMKV
import UserNotifications

private let APP_GROUP_ID = "group.humand.demo.app"
private let MMKV_ID = "pending_push_messages"
private let NEW_MESSAGE_TYPE = "CHATS_V2_NEW_MESSAGE"

class NotificationService: UNNotificationServiceExtension {
  private var contentHandler: ((UNNotificationContent) -> Void)?
  private var bestAttemptContent: UNMutableNotificationContent?

  override init() {
    super.init()
    if let containerURL = FileManager.default
      .containerURL(forSecurityApplicationGroupIdentifier: APP_GROUP_ID)
    {
      // groupDir sets g_groupPath = containerURL/mmkv, required for
      // MMKVMultiProcess instances to resolve their root without an explicit path.
      MMKV.initialize(rootDir: nil, groupDir: containerURL.path, logLevel: .warning)
    }
  }

  private lazy var mmkv: MMKV? = {
    guard let keychainKey = KeysHelper.secure(for: "KEYCHAIN_KEY"),
          !keychainKey.isEmpty else { return nil }
    
    guard let keychainKeyData = keychainKey.data(using: .utf8) else {
      return nil
    }
    // Multi-process: the main app and the NSE are separate OS processes.
    // Single-process mode caches state in memory and ignores writes from other processes.
    guard let mmkv = MMKV(mmapID: MMKV_ID, cryptKey: keychainKeyData, mode: .multiProcess) else {
      return nil
    }
    return mmkv
  }()

  override func didReceive(
    _ request: UNNotificationRequest,
    withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
  ) {
    saveToMMKV(userInfo: request.content.userInfo)

    self.contentHandler = contentHandler
    bestAttemptContent = request.content.mutableCopy() as? UNMutableNotificationContent

    Messaging.serviceExtension()
      .populateNotificationContent(bestAttemptContent!, withContentHandler: contentHandler)
  }

  override func serviceExtensionTimeWillExpire() {
    if let handler = contentHandler, let content = bestAttemptContent {
      handler(content)
    }
  }

  private func saveToMMKV(userInfo: [AnyHashable: Any]) {
    guard
      let type = userInfo["type"] as? String,
      type == NEW_MESSAGE_TYPE,
      let ts = userInfo["msg_ts"] as? String
    else { return }

    if let jsonData = try? JSONSerialization.data(withJSONObject: userInfo, options: []), let jsonString = String(data: jsonData, encoding: .utf8) {
      mmkv?.set(jsonString, forKey: ts)
      mmkv?.sync() // flush CRC + data to disk before the extension process may be killed
    }
  }
}
