//
//  UDPMessageCenterServer.swift
//  sdlan
//
//  Created by 安礼成 on 2024/5/20.
//

import Foundation
import NIOCore
import NIOPosix
import Combine

final class UDPNoticeCenterServer: ChannelInboundHandler {
    public typealias InboundIn = AddressedEnvelope<ByteBuffer>
    public typealias OutboundOut = AddressedEnvelope<ByteBuffer>
    
    private var group: MultiThreadedEventLoopGroup?
    private var channel: Channel?
    
    var messageFlow = PassthroughSubject<NoticeMessage.InboundMessage, Never>()
    public var port: Int = 0
    
    func start() {
        self.group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
        let bootstrap = DatagramBootstrap(group: self.group!)
            .channelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
            .channelInitializer { channel in
                channel.pipeline.addHandler(self)
            }
        self.channel = try! bootstrap.bind(host: "127.0.0.1", port: 0).wait()
        self.port = self.channel?.localAddress?.port ?? 0
    }
    
    func stop() {
        try? self.group?.syncShutdownGracefully()
    }
    
    // --MARK: ChannelInboundHandler
    
    public func channelRead(context: ChannelHandlerContext, data: NIOAny) {
        let envelope = self.unwrapInboundIn(data)
        var buffer = envelope.data
        
        let notice = NoticeMessage.decodeMessage(buffer: &buffer)
        self.messageFlow.send(notice)
    }
    
    public func channelReadComplete(context: ChannelHandlerContext) {
        // As we are not really interested getting notified on success or failure we just pass nil as promise to
        // reduce allocations.
        context.flush()
    }
    
    public func errorCaught(context: ChannelHandlerContext, error: Error) {
        // As we are not really interested getting notified on success or failure we just pass nil as promise to
        // reduce allocations.
        context.close(promise: nil)
    }
    
}
