import { NativeModules, Platform, NativeEventEmitter } from 'react-native';
import type { FingerprintConfig } from './config/FingerprintConfig';
import type { FingerprintCaptureState } from './config/enums/FingerprintCaptureState';
import type { FingerprintRect } from './config/FingerprintRect';
import { mergeConfigs } from './utils/Utils';

const LINKING_ERROR =
  `The package '@biopassid/fingerprint-sdk-react-native' doesn't seem to be linked. Make sure: \n\n` +
  Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
  '- You rebuilt the app after installing the package\n' +
  '- You are not using Expo Go\n';

const FingerprintSdkReactNative = NativeModules.FingerprintSdkReactNative
  ? NativeModules.FingerprintSdkReactNative
  : new Proxy(
      {},
      {
        get() {
          throw new Error(LINKING_ERROR);
        },
      }
    );

const eventEmitter = new NativeEventEmitter(FingerprintSdkReactNative);

const supportedEvents = [
  'fingerprint-sdk-react-native/onFingerCapture',
  'fingerprint-sdk-react-native/onStatusChanged',
  'fingerprint-sdk-react-native/onFingerDetected',
];

export interface TakeFingerprintOptions {
  config: FingerprintConfig;
  onFingerCapture: (images: string[], error: string | null) => void;
  onStatusChanged?: (state: FingerprintCaptureState) => void;
  onFingerDetected?: (fingerRects: FingerprintRect[]) => void;
}

interface OnFingerCaptureEvent {
  images: string[];
  error: string | null;
}

interface OnStatusChangedEvent {
  state: FingerprintCaptureState;
}

interface OnFingerDetectedEvent {
  fingerRects: FingerprintRect[];
}

export async function takeFingerprint(
  options: TakeFingerprintOptions
): Promise<void | never> {
  try {
    const newConfig = mergeConfigs(options.config);

    supportedEvents.map((eventName: string) => {
      eventEmitter.removeAllListeners(eventName);

      const exactEventName = eventName.split('/')[1];

      if (exactEventName === 'onFingerCapture') {
        eventEmitter.addListener(eventName, (event: OnFingerCaptureEvent) => {
          options.onFingerCapture(event.images, event.error);
        });
      } else if (exactEventName === 'onStatusChanged') {
        eventEmitter.addListener(eventName, (event: OnStatusChangedEvent) => {
          if (options.onStatusChanged) {
            options.onStatusChanged(event.state);
          }
        });
      } else if (exactEventName === 'onFingerDetected') {
        eventEmitter.addListener(eventName, (event: OnFingerDetectedEvent) => {
          if (options.onFingerDetected) {
            options.onFingerDetected(event.fingerRects);
          }
        });
      }
    });

    await FingerprintSdkReactNative.takeFingerprint(newConfig);
  } catch (error) {
    console.error(`Unknown error: ${error}`);
  }
}
