/**
 * Copyright (c) 2025 Opal Kelly Incorporated
 *
 * This source code is licensed under the FrontPanel license.
 * See the LICENSE file found in the root directory of this project.
 */

import { IDeviceEvent, DeviceEventHandler, DeviceEventAsyncHandler } from "./IDeviceEvent";

import { IEventSubscription } from "./IEventSubscription";

import EventSubscription from "./EventSubscription";

import { SubEvent, Subscription } from "sub-events";

import IDeviceManager from "./IDeviceManager";

interface DeviceEventArgs {
    sender: IDeviceManager;
    serialNumber: string;
}

/**
 * Class representing a FrontPanel event.
 */
class DeviceEvent implements IDeviceEvent {
    private readonly _Target: SubEvent<DeviceEventArgs> = new SubEvent();

    /**
     * Creates a new instance of a Device event.
     */
    constructor() {}

    /**
     * Dispatches the event to all subscribed handlers.
     * @param sender - The sender of the event.
     * @param serialNumber - The serial number of the device.
     * @returns {boolean} - Returns true after the event has been dispatched.
     */
    public dispatch(sender: IDeviceManager, serialNumber: string): boolean {
        this._Target.emit({ sender, serialNumber });
        return true;
    }

    /**
     * Subscribes a handler to the event.
     * @param handler - The handler function to subscribe to the event.
     * @returns {IEventSubscription} - The subscription object, which can be used to cancel the subscription.
     */
    public subscribe(handler: DeviceEventHandler): IEventSubscription {
        const adaptedHandler = ({ sender, serialNumber }: DeviceEventArgs) =>
            handler(sender, serialNumber);
        const subscription: Subscription = this._Target.subscribe(adaptedHandler);
        return new EventSubscription(subscription);
    }

    /**
     * Subscribes an asynchronous handler to the event.
     * @param handler - The asynchronous handler function to subscribe to the event.
     * @returns {IEventSubscription} - The subscription object, which can be used to cancel the subscription.
     */
    public subscribeAsync(handler: DeviceEventAsyncHandler): IEventSubscription {
        const adaptedHandler = ({ sender, serialNumber }: DeviceEventArgs) =>
            handler(sender, serialNumber);
        const subscription: Subscription = this._Target.subscribe(adaptedHandler);
        return new EventSubscription(subscription);
    }
}

export default DeviceEvent;
