//
// Copyright 2023 Wultra s.r.o.
//
// 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
//
// http://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 { EmitterSubscription, NativeEventEmitter, Platform } from "react-native";
import { MalwarelyticsModuleIfc, wrapNativeCall } from "./MalwarelyticsModule";
import { MalwarelyticsError } from "../MalwarelyticsError";

/**
 * Type defining events reported from the native code.
 */
export type EventType = 'Malwarelytics.STATE' | 'Malwarelytics.RASP' | 'Malwarelytics.AV_UPDATE' | 'Malwarelytics.AV_APK_THREAT';

/**
 * The `EventHandler` class helps with listening to events sent from the native code.
 */
export class EventHelper {
    /**
     * Instance of native module interface.
     */
    readonly module: MalwarelyticsModuleIfc
    /**
     * Native emitter instance
     */
    private eventEmitter: NativeEventEmitter
    /**
     * Cached list of supported event on the platform.
     */
    private supportedEvents: Array<EventType> | undefined

    /**
     * Construct event handler.
     * @param module Native module
     */
    constructor(module: MalwarelyticsModuleIfc) {
        this.module = module
        this.eventEmitter = new NativeEventEmitter(module)
    }

     /**
     * Test whether the event type is supported.
     * @param event Event type to test
     * @returns Boolean promise indicating support of requested event type.
     */
     async isEventSupported(event: EventType): Promise<boolean> {
        if (this.supportedEvents == undefined) {
            this.supportedEvents = await wrapNativeCall(this.module, module => module.getSupportedEvents() )
        }
        return this.supportedEvents.findIndex(e => e == event) != -1
    }

    /**
     * Add listener for the requested event type. The event type should be supported. Be aware that not all
     * event types are supported on both platforms. You should use `isEventSupported()` function before this call. 
     * @param event Listen to this type of event.
     * @param callback The listener function.
     * @returns `EmitterSubscription` object.
     */
    async addListener(event: EventType, callback: (data: any) => void): Promise<EmitterSubscription> {
        if (!await this.isEventSupported(event)) {
            throw new MalwarelyticsError("METHOD_NOT_SUPPORTED", `Event ${event} is not supported on ${Platform.OS} platform`)
        }
        return this.eventEmitter.addListener(event, callback)
    }

    /**
     * Remove listener previously registered in `addListener()` function.
     * @param subscription `EmitterSubscription` object.
     */
    removeListener(subscription: EmitterSubscription) {
        subscription.remove()
    }
}