<script setup>
import { BrowserMultiFormatReader } from "@zxing/browser";
import {} from "@zxing/browser/esm";
import { computed, onBeforeUnmount, onMounted, ref, watchEffect } from "vue";
import { useAlert } from "../composables/alert";
import { useDevicesList, useUserMedia } from "@vueuse/core";
const barcodeReader = new BrowserMultiFormatReader();
const barcodeReaderControl = ref();
const alert = useAlert();
const isLoading = ref(false);
const emit = defineEmits(["decode", "error"]);
const videoScreen = ref();
const currentCameraId = ref();
const { videoInputs: cameras } = useDevicesList({
  requestPermissions: true,
  constraints: { audio: false, video: true },
  onUpdated() {
    if (!cameras.value.find((camera) => camera.deviceId === currentCameraId.value))
      currentCameraId.value = cameras.value[0]?.deviceId;
  }
});
const hasCamera = computed(() => {
  return !!currentCameraId.value;
});
const { stream, start: cameraStart, stop: cameraStop, enabled: cameraEnabled } = useUserMedia({
  constraints: { video: { deviceId: currentCameraId.value } }
});
watchEffect(() => {
  if (videoScreen.value) videoScreen.value.srcObject = stream.value ? stream.value : null;
});
function startCamera() {
  if (!cameraEnabled.value) {
    isLoading.value = true;
    cameraStart().then(() => {
      barcodeReader.decodeFromVideoDevice(currentCameraId.value, videoScreen.value, (result, error, controls) => {
        if (result) {
          emit("decode", result.getText());
          cameraStop();
        }
      }).then((result) => {
        barcodeReaderControl.value = result;
      });
    }).finally(() => {
      isLoading.value = false;
    });
  }
}
function stopCamera() {
  if (barcodeReaderControl.value) barcodeReaderControl.value.stop();
  if (cameraEnabled.value) cameraStop();
}
function scanImageFile(selectedFile) {
  if (!selectedFile) {
    alert?.addAlert({ message: "No file selected.", alertType: "error" });
    return;
  }
  const scanImageSingleFile = Array.isArray(selectedFile) ? selectedFile[0] : selectedFile;
  const reader = new FileReader();
  reader.onload = async (event) => {
    try {
      const imageReader = new BrowserMultiFormatReader();
      const result = await imageReader.decodeFromImageUrl(event.target?.result);
      emit("decode", result.getText());
    } catch (e) {
      emit("error", e);
    }
  };
  reader.readAsDataURL(scanImageSingleFile);
}
onMounted(() => {
  startCamera();
});
onBeforeUnmount(() => {
  stopCamera();
});
</script>

<template>
  <v-card flat>
    <v-card-text class="d-flex justify-center" v-if="isLoading">
      <v-progress-circular indeterminate></v-progress-circular>
    </v-card-text>
    <v-card-text v-else>
      <v-col v-if="hasCamera">
        <div style="position: relative; display: inline-block; width: 100%;" :style="{ maxWidth: '1024px' }">
          <video autoplay ref="videoScreen" width="100%" :style="{ maxWidth: '1024px' }"></video>
          <div style="position: absolute; bottom: 10px; right: 10px; z-index: 2000;">
            <FileBtn
                accept="image/*"
                icon="mdi mdi-image-plus"
                icon-only
                @update:model-value="scanImageFile"
            />
          </div>
        </div>
      </v-col>
      <v-col v-else>
        <FileBtn
          accept="image/*"
          text="Upload Image"
          @update:model-value="scanImageFile"
        />
      </v-col>
    </v-card-text>
  </v-card>
</template>
