import { NfcErrorType, } from "./definitions.js";
import { WebNfc } from "./web.js";
/**
 * Main NFC class that provides access to NFC functionality.
 * It automatically chooses the appropriate implementation for the current platform.
 */
export class Nfc {
    constructor() {
        this.listeners = new Map();
        // Currently we only have the Web implementation
        this.implementation = new WebNfc();
        // Set up status monitoring to track NFC availability
        this.monitorNfcStatus();
    }
    /**
     * Internal method to monitor NFC status changes
     */
    async monitorNfcStatus() {
        try {
            // Set up listener for NFC status changes from implementation
            await this.implementation.addListener("nfcStatusChanged", (status) => {
                // Propagate to our own listeners
                this.notifyListeners("nfcStatusChanged", status);
            });
        }
        catch (error) {
            console.warn("Failed to set up NFC status monitoring:", error);
        }
    }
    /**
     * Check if NFC is enabled (Android) or available (iOS/Web).
     * @returns Promise resolving to an object with an `enabled` boolean property
     */
    async isEnabled() {
        try {
            return await this.implementation.isEnabled();
        }
        catch (error) {
            console.error("Error checking NFC status:", error);
            return { enabled: false };
        }
    }
    /**
     * Open NFC settings (Android) or app settings (iOS) or shows guidance (Web).
     * This helps users enable NFC if it's disabled.
     */
    async openSettings() {
        return this.implementation.openSettings();
    }
    /**
     * Start scanning for NFC tags.
     * @param options Configuration options for the scan session
     */
    async startScanSession(options) {
        var _a, _b, _c;
        try {
            return await this.implementation.startScanSession(options);
        }
        catch (error) {
            // Convert to a standardized error object if possible
            const nfcError = new Error(error.message || "Failed to start NFC scan");
            if (((_a = error.message) === null || _a === void 0 ? void 0 : _a.includes("not supported")) ||
                error.name === "NotSupportedError") {
                nfcError.code = NfcErrorType.NOT_SUPPORTED;
            }
            else if (((_b = error.message) === null || _b === void 0 ? void 0 : _b.includes("permission")) ||
                error.name === "NotAllowedError") {
                nfcError.code = NfcErrorType.PERMISSION_DENIED;
            }
            else if ((_c = error.message) === null || _c === void 0 ? void 0 : _c.includes("not enabled")) {
                nfcError.code = NfcErrorType.NOT_ENABLED;
            }
            else {
                nfcError.code = NfcErrorType.UNEXPECTED_ERROR;
            }
            throw nfcError;
        }
    }
    /**
     * Stop the current NFC scan session.
     */
    async stopScanSession() {
        return this.implementation.stopScanSession();
    }
    /**
     * Write an NDEF message to an NFC tag.
     * @param options Object containing the NDEF message to write
     */
    async write(options) {
        return this.implementation.write(options);
    }
    /**
     * Make an NFC tag read-only.
     * WARNING: This is a permanent operation that cannot be undone.
     */
    async makeReadOnly() {
        return this.implementation.makeReadOnly();
    }
    /**
     * Format an NFC tag, erasing its contents and preparing it for writing.
     */
    async format() {
        return this.implementation.format();
    }
    /**
     * Erase the contents of an NFC tag.
     */
    async erase() {
        return this.implementation.erase();
    }
    /**
     * Share NDEF data via NFC (Android only, not available on iOS or Web).
     * @param options Object containing the NDEF message to share
     */
    async share(options) {
        return this.implementation.share(options);
    }
    /**
     * Stop sharing NDEF data via NFC (Android only).
     */
    async stopSharing() {
        return this.implementation.stopSharing();
    }
    async addListener(eventName, listenerFunc) {
        var _a;
        // Add to our internal listener registry
        if (!this.listeners.has(eventName)) {
            this.listeners.set(eventName, new Set());
        }
        (_a = this.listeners.get(eventName)) === null || _a === void 0 ? void 0 : _a.add(listenerFunc);
        // Register with the implementation
        const handle = await this.implementation.addListener(eventName, listenerFunc);
        // Return a handle that will clean up properly
        return {
            remove: async () => {
                var _a;
                (_a = this.listeners.get(eventName)) === null || _a === void 0 ? void 0 : _a.delete(listenerFunc);
                return handle.remove();
            },
        };
    }
    /**
     * Remove all event listeners registered for this plugin.
     */
    async removeAllListeners() {
        // Clear our internal listener registry
        this.listeners.clear();
        // Remove listeners from the implementation
        return this.implementation.removeAllListeners();
    }
    /**
     * Internal method to notify listeners of events
     */
    notifyListeners(eventName, data) {
        const listeners = this.listeners.get(eventName);
        if (listeners) {
            for (const listener of listeners) {
                try {
                    listener(data);
                }
                catch (error) {
                    console.error(`Error in ${eventName} listener:`, error);
                }
            }
        }
    }
}
