import Foundation

protocol AttachmentFlowTransporting {
    func uploadFile(id: String, content: Data) async throws -> (tag: String, server: String)
    func uploadFile(id: String, content: Data, onProgress: (@MainActor (Double) -> Void)?) async throws -> (tag: String, server: String)
    func downloadFile(tag: String, server: String?) async throws -> Data
}

protocol PacketFlowSending {
    func sendPacket(_ packet: any Packet)
}

protocol SearchResultDispatching {
    var connectionState: ConnectionState { get }
    var privateHash: String? { get }
    func sendSearchPacket(_ packet: PacketSearch)
    @discardableResult
    func addSearchResultHandler(_ handler: @escaping (PacketSearch) -> Void) -> UUID
    func removeSearchResultHandler(_ id: UUID)
}

struct LiveAttachmentFlowTransport: AttachmentFlowTransporting {
    func uploadFile(id: String, content: Data) async throws -> (tag: String, server: String) {
        try await TransportManager.shared.uploadFile(id: id, content: content)
    }

    func uploadFile(id: String, content: Data, onProgress: (@MainActor (Double) -> Void)?) async throws -> (tag: String, server: String) {
        try await TransportManager.shared.uploadFile(id: id, content: content, onProgress: onProgress)
    }

    func downloadFile(tag: String, server: String?) async throws -> Data {
        try await TransportManager.shared.downloadFile(tag: tag, server: server)
    }
}

struct LivePacketFlowSender: PacketFlowSending {
    func sendPacket(_ packet: any Packet) {
        ProtocolManager.shared.sendPacket(packet)
    }
}

struct LiveSearchResultDispatcher: SearchResultDispatching {
    private let channel: SearchPacketChannel

    init(channel: SearchPacketChannel = .ui(UUID())) {
        self.channel = channel
    }

    var connectionState: ConnectionState {
        ProtocolManager.shared.connectionState
    }

    var privateHash: String? {
        ProtocolManager.shared.privateHash
    }

    func sendSearchPacket(_ packet: PacketSearch) {
        ProtocolManager.shared.sendSearchPacket(packet, channel: channel)
    }

    @discardableResult
    func addSearchResultHandler(_ handler: @escaping (PacketSearch) -> Void) -> UUID {
        ProtocolManager.shared.addSearchResultHandler(channel: channel, handler)
    }

    func removeSearchResultHandler(_ id: UUID) {
        ProtocolManager.shared.removeSearchResultHandler(id)
    }
}
