//
//  DarwinNotificationName.swift
//  punchnet
//
//  Created by 安礼成 on 2026/4/3.
//
import Foundation

// MARK: - Darwin Notification Name
public struct DarwinNotificationName: RawRepresentable, Hashable {
    public let rawValue: String
    
    public init(rawValue: String) {
        self.rawValue = rawValue
    }
}

// 预定义名称
extension DarwinNotificationName {
    static let tunnelEventChanged = DarwinNotificationName(rawValue: "com.jihe.punchnetmac.tunnelEventChanged")
}

extension SDLNotificationCenter {
    enum Configuration {
        static let appGroupSuiteName = "group.com.jihe.punchnetmac"
        static let latestEventKey = "tunnel.latestEvent"
    }
}


// MARK: - Manager
public final class SDLNotificationCenter {
    public static let shared = SDLNotificationCenter()
    
    private let center = CFNotificationCenterGetDarwinNotifyCenter()
    
    private var observers: [DarwinNotificationName: (DarwinNotificationName) -> Void] = [:]
    private let lock = NSLock()
    
    private init() {}
    
    // MARK: - Add Observer
    public func addObserver(for name: DarwinNotificationName, queue: DispatchQueue = .main, using block: @escaping (DarwinNotificationName) -> Void ) {
        lock.lock()
        defer {
            lock.unlock()
        }
        
        if observers[name] == nil {
            // 首次注册到 Darwin Center
            CFNotificationCenterAddObserver(
                center,
                UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()),
                { (_, observer, cfName, _, _) in
                    guard let observer, let cfName else {
                        return
                    }
                    
                    let instance = Unmanaged<SDLNotificationCenter>
                        .fromOpaque(observer)
                        .takeUnretainedValue()
                    
                    let name = DarwinNotificationName(rawValue: cfName.rawValue as String)
                    instance.handle(name: name)
                },
                name.rawValue as CFString,
                nil,
                .deliverImmediately
            )
            
            observers[name] = { n in
                queue.async {
                    block(n)
                }
            }
        }
        
    }
    
    // MARK: - Remove Observer
    public func removeObserver(for name: DarwinNotificationName) {
        lock.lock()
        defer {
            lock.unlock()
        }
        
        if observers[name] != nil {
            CFNotificationCenterRemoveObserver(
                center,
                UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()),
                CFNotificationName(name.rawValue as CFString),
                nil
            )
        }
        observers.removeValue(forKey: name)
        
    }
    
    // MARK: - Post
    public func post(_ name: DarwinNotificationName) {
        CFNotificationCenterPostNotification(
            center,
            CFNotificationName(name.rawValue as CFString),
            nil,
            nil,
            true
        )
    }
    
    // MARK: - Handle
    private func handle(name: DarwinNotificationName) {
        lock.lock()
        let block = observers[name]
        lock.unlock()
        
        block?(name)
    }
    
}
