import React, { memo, useEffect, useState } from 'react';
import { StyleSheet, View, type StyleProp, type ViewStyle } from 'react-native';

import {
  Camera as RNCamera,
  useCodeScanner,
  useCameraDevice,
  type Code as ICameraResults,
  type CodeScannerFrame,
} from 'react-native-vision-camera';

type Props = {
  style?: StyleProp<ViewStyle> | undefined;
  children: any;
  NoCameraDeviceError?: React.ReactNode | React.Component | Function;
  shouldScan?: boolean;
  onBarcodesDetected: (result: { code: string[] }) => void;
};

const BarcodeScanner = ({
  style,
  NoCameraDeviceError,
  onBarcodesDetected,
  children,
  ...props
}: Props) => {
  const [hasPermission, setHasPermission] = useState(false);
  const device = useCameraDevice('back');

  const codeScanner = useCodeScanner({
    codeTypes: [
      'code-128',
      'code-39',
      'code-93',
      'codabar',
      'ean-13',
      'ean-8',
      'itf',
      'upc-e',
      'qr',
      'pdf-417',
      'aztec',
      'data-matrix',
    ],
    onCodeScanned: (barcodes: ICameraResults[], _frame: CodeScannerFrame) => {
      let data: any[] = [];
      barcodes.forEach((barcode) => {
        if (!!barcode.value) data.push(barcode.value);
      });
      if (!data.length) return;
      onBarcodesDetected({ code: data });
    },
  });

  useEffect(() => {
    (async () => {
      if (RNCamera.getCameraPermissionStatus() !== 'granted') {
        const status = await RNCamera.requestCameraPermission();
        setHasPermission(status === 'granted');
      } else {
        setHasPermission(true);
      }
    })();
  }, []);

  if (device == null) {
    if (typeof NoCameraDeviceError === 'function') return NoCameraDeviceError();
    if (React.isValidElement(NoCameraDeviceError)) return NoCameraDeviceError;
    return null;
  }

  return (
    <View style={[styles.cameraStyle, StyleSheet.flatten(style)]}>
      {hasPermission && (
        <RNCamera
          {...props}
          device={device}
          isActive={true}
          style={StyleSheet.absoluteFill}
          codeScanner={codeScanner}
        />
      )}
      {children}
    </View>
  );
};

export default memo(BarcodeScanner);

const styles = StyleSheet.create({
  cameraStyle: { flex: 1, width: '100%' },
});
