import { NativeModules } from 'react-native';
import { ApiService } from './API/api.service';

import DefaultWidget from './DefaultWidget';
export { DefaultWidget };

var widgetId: string = "";
var tokenAuth: string = "";

const bridge = NativeModules.BiometricAuth;

if (!bridge) {
  console.error('BiometricAuth is undefined! Ensure the native module is properly linked.');
}

/**
 * Type alias for possible biometry types
 */
export type BiometryType = 'TouchID' | 'FaceID' | 'Biometrics' | 'FaceRecognition' | 'Fingerprint';

/**
 * Options for configuring the biometric module
 */
interface BiometricOptions {
  allowDeviceCredentials?: boolean;
}

/**
 * Response structure for isSensorAvailable method
 */
interface IsSensorAvailableResult {
  available: boolean;
  biometryType?: BiometryType;
  error?: string;
}

/**
 * Options for simple biometric prompt
 */
interface SimplePromptOptions {
  promptMessage: string;
  fallbackPromptMessage?: string;
  cancelButtonText?: string;
  allowDeviceCredentials?: boolean;
}

/**
 * Response structure for simplePrompt method
 */
interface SimplePromptResult {
  success: boolean;
  error?: string;
}

/**
 * Enum for biometric types
 */
export const TouchID = 'TouchID';
export const FaceID = 'FaceID';
export const Biometrics = 'Biometrics';
export const FaceRecognition = 'Face Recognition';
export const Fingerprint = 'Fingerprint';


export const BiometryTypes = {
  TouchID,
  FaceID,
  Biometrics,
  FaceRecognition,
  Fingerprint,
};

/**
 * BiometricAuth class to handle biometric authentication
 */
export class BiometricAuth {
  allowDeviceCredentials: boolean = false;

  /**
   * Constructor to initialize options
   * @param biometricOptions {BiometricOptions}
   */
  constructor(biometricOptions?: BiometricOptions) {
    this.allowDeviceCredentials = biometricOptions?.allowDeviceCredentials ?? false;
  }

  /**
   * Checks if biometric sensor is available
   * @returns {Promise<IsSensorAvailableResult>}
   */
  static isSensorAvailable(): Promise<IsSensorAvailableResult> {
    return bridge?.isSensorAvailable() ?? Promise.reject('Native module not linked properly.');
  }

  /**
   * Triggers biometric authentication dialog
   * @returns {Promise<string>}
   */
  static authenticate(): Promise<string> {
    return bridge?.authenticate() ?? Promise.reject('Native module not linked properly.');
  }

  /**
   * Gets the available biometric type
   * @returns {Promise<string>}
   */
  static getBiometricType(): Promise<string> {
    return bridge?.getBiometricType() ?? Promise.reject('Native module not linked properly.');
  }

  /**
   * Shows a simple biometric prompt with a customizable message
   * @param options {SimplePromptOptions}
   * @returns {Promise<SimplePromptResult>}
   */
  static simplePrompt(options: SimplePromptOptions): Promise<SimplePromptResult> {
    options.cancelButtonText = options.cancelButtonText ?? 'Cancel';
    options.fallbackPromptMessage = options.fallbackPromptMessage ?? 'Use Passcode';

    return bridge?.simplePrompt(options) ?? Promise.reject('Native module not linked properly.');
  }

  /**
   * Cancels any ongoing biometric authentication session
   * @returns {Promise<string>}
   */
  static cancelAuthentication(): Promise<string> {
    return bridge?.cancelAuthentication() ?? Promise.reject('Native module not linked properly.');
  }
}

/**
 * Legacy functions (for backward compatibility)
 */
export const BiometricAuthLegacy = {
  isSensorAvailable: (): Promise<IsSensorAvailableResult> => {
    return BiometricAuth.isSensorAvailable();
  },
  authenticate: (): Promise<string> => {
    return BiometricAuth.authenticate();
  },
  getBiometricType: (): Promise<string> => {
    return BiometricAuth.getBiometricType();
  },
  simplePrompt: (options: SimplePromptOptions): Promise<SimplePromptResult> => {
    return BiometricAuth.simplePrompt(options);
  },
  cancelAuthentication: (): Promise<string> => {
    return BiometricAuth.cancelAuthentication();
  },
};

// export default BiometricAuth;


export class OTPWidget {
    // Checks if the widget has been properly initialized with a widget ID and a token.
    // This is an internal method and should not be called directly.
    private static checkInitialization() {
        if (widgetId === "" || tokenAuth === "") {
            console.error("Widget not initialized. Call initializeWidget before using any method.")
            return false;
        }
        return true
    }


    /**
    * Initializes the widget with necessary authentication details.
    * Must be called before using any other methods in the widget.
    * 
    * @param widgetid
    * @param tokenauth
    */
    static async initializeWidget(widgetid: string, tokenauth: string) {
        widgetId = widgetid
        tokenAuth = tokenauth
    }

    
    /**
     * The sendOTP method is used to send an OTP to an identifier.
     * Identifier (string) - This is a mandatory argument. The identifier can be an email or mobile number (it must contain the country code without +)
     * 
     * @param body body Contains the identifier and other parameters necessary for sending an OTP.
     * @returns {Promise<any>} A Promise resolving to the send response or throws an error if the request fails.
     */
    static async sendOTP(body: any) {
        if (!this.checkInitialization()) return;

        const payload = {
            widgetId: widgetId,
            tokenAuth: tokenAuth,
            ...body
        }
        try {
            const response = await ApiService.sendOTP(payload);
            return response;
        } catch (error) {
            console.error('Error sending OTP:', error);
            throw error; // Re-throw the error to propagate it to the caller
        }

    }
    /**
     * The verifyOtp method is used to verify an OTP entered by the user.
     * 
     * @param body body Must include the otp for verification and the reqId of the original OTP request.
     * @returns {Promise<any>} A Promise resolving to the verification response or throws an error if verification fails.
     */
    static async verifyOTP(body: any) {
        if (!this.checkInitialization()) return;

        const payload = {
            widgetId: widgetId,
            tokenAuth: tokenAuth,
            ...body
        }
        try {
            const response = await ApiService.verifyOTP(payload);
            return response;
        } catch (error) {
            console.error('Error verifying OTP:', error);
            throw error; // Re-throw the error to propagate it to the caller
        }

    }

    /**
     * The retryOtp method allows retrying the OTP if it was not received for any reason.
     * 
     * @param body body must include the req id and channel value for retrying the OTP.
     * @returns {Promise<any>} A Promise resolving to the response of the retry attempt or throws an error if the attempt fails.
     */
    static async retryOTP(body: any) {
        if (!this.checkInitialization()) return;

        const payload = {
            widgetId: widgetId,
            tokenAuth: tokenAuth,
            ...body
        }
        try {
            const response = await ApiService.retryOTP(payload);
            return response;
        } catch (error) {
            console.error('Error sending retry OTP:', error);
            throw error; // Re-throw the error to propagate it to the caller
        }

    }


    /**
    * getWidgetProcess method retrieves the current configuration and process information for the widget.
    * 
    * @returns {Promise<any>} A Promise resolving to the widget's current process data or throws an error if the request fails.
    */
    static async getWidgetProcess() {
        if (!this.checkInitialization()) return;
        try {
            const response = await ApiService.getWidgetProcess(widgetId, tokenAuth);
            return response;
        } catch (error) {
            console.error('Error getting widget process:', error);
            throw error; // Re-throw the error to propagate it to the caller
        }

    }

} 