//===----------------------------------------------------------------------===//
// Copyright © 2025 Apple Inc. and the container project authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//

import ContainerXPC
import ContainerizationExtras
import Foundation
import TerminalProgress

/// A service that sends progress updates to the client.
public actor ProgressUpdateService {
    private let endpointConnection: xpc_connection_t

    /// Creates a new instance for sending progress updates to the client.
    /// - Parameter message: The XPC message that contains the endpoint to connect to.
    public init?(message: XPCMessage) {
        guard let progressUpdateEndpoint = message.endpoint(key: .progressUpdateEndpoint) else {
            return nil
        }
        endpointConnection = xpc_connection_create_from_endpoint(progressUpdateEndpoint)
        xpc_connection_set_event_handler(endpointConnection) { _ in }
        // This connection will be closed by the client.
        xpc_connection_activate(endpointConnection)
    }

    /// Performs a progress update.
    /// - Parameter events: The events that represent the update.
    public func handler(_ events: [ProgressUpdateEvent]) async {
        let object = xpc_dictionary_create(nil, nil, 0)
        let replyMessage = XPCMessage(object: object)
        for event in events {
            switch event {
            case .setDescription(let description):
                replyMessage.set(key: .progressUpdateSetDescription, value: description)
            case .setSubDescription(let subDescription):
                replyMessage.set(key: .progressUpdateSetSubDescription, value: subDescription)
            case .setItemsName(let itemsName):
                replyMessage.set(key: .progressUpdateSetItemsName, value: itemsName)
            case .addTasks(let tasks):
                replyMessage.set(key: .progressUpdateAddTasks, value: tasks)
            case .setTasks(let tasks):
                replyMessage.set(key: .progressUpdateSetTasks, value: tasks)
            case .addTotalTasks(let totalTasks):
                replyMessage.set(key: .progressUpdateAddTotalTasks, value: totalTasks)
            case .setTotalTasks(let totalTasks):
                replyMessage.set(key: .progressUpdateSetTotalTasks, value: totalTasks)
            case .addSize(let size):
                replyMessage.set(key: .progressUpdateAddSize, value: size)
            case .setSize(let size):
                replyMessage.set(key: .progressUpdateSetSize, value: size)
            case .addTotalSize(let totalSize):
                replyMessage.set(key: .progressUpdateAddTotalSize, value: totalSize)
            case .setTotalSize(let totalSize):
                replyMessage.set(key: .progressUpdateSetTotalSize, value: totalSize)
            case .addItems(let items):
                replyMessage.set(key: .progressUpdateAddItems, value: items)
            case .setItems(let items):
                replyMessage.set(key: .progressUpdateSetItems, value: items)
            case .addTotalItems(let totalItems):
                replyMessage.set(key: .progressUpdateAddTotalItems, value: totalItems)
            case .setTotalItems(let totalItems):
                replyMessage.set(key: .progressUpdateSetTotalItems, value: totalItems)
            case .custom(_):
                // Unsupported progress update event in XPC communication.
                break
            }
        }
        xpc_connection_send_message(endpointConnection, replyMessage.underlying)
    }
}
