<script setup>
import { computed, onBeforeUnmount, onMounted, ref, watchEffect } from "vue";
import { useDevicesList, useUserMedia } from "@vueuse/core";
import { useAlert } from "../composables/alert";
import { useMrzReader } from "../composables/useMrzReader";
const mrzReaderControl = ref(null);
const alert = useAlert();
const isLoading = ref(false);
const props = defineProps({
  intervalMs: { type: Number, required: false, default: 900 },
  scaleFactor: { type: Number, required: false, default: 2 },
  useOpenCv: { type: Boolean, required: false, default: true }
});
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(() => !!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 ?? null;
});
const mrzReader = useMrzReader({
  scaleFactor: props.scaleFactor,
  useOpenCv: props.useOpenCv,
  lang: "ocrb",
  langPath: "/tesseract/"
});
async function scanOnce() {
  if (!videoScreen.value || !cameraEnabled.value) return;
  try {
    const parsed = await mrzReader.decodeFromVideoElement(videoScreen.value);
    if (parsed) {
      emit("decode", parsed);
      stopCamera();
    }
  } catch (err) {
    emit("error", err);
  }
}
function startCamera() {
  if (cameraEnabled.value) return;
  isLoading.value = true;
  cameraStart().then(() => {
    if (mrzReaderControl.value) {
      window.clearInterval(mrzReaderControl.value);
      mrzReaderControl.value = null;
    }
    mrzReaderControl.value = window.setInterval(() => {
      void scanOnce();
    }, props.intervalMs);
  }).catch((err) => {
    emit("error", err);
  }).finally(() => {
    isLoading.value = false;
  });
}
function stopCamera() {
  if (mrzReaderControl.value) {
    window.clearInterval(mrzReaderControl.value);
    mrzReaderControl.value = null;
  }
  if (cameraEnabled.value)
    cameraStop();
}
function scanImageFile(selectedFile) {
  if (!selectedFile) {
    alert?.addAlert({ message: "No file selected.", alertType: "error" });
    return;
  }
  const file = Array.isArray(selectedFile) ? selectedFile[0] : selectedFile;
  void mrzReader.decodeFromImageFile(file).then((parsed) => {
    if (parsed)
      emit("decode", parsed);
    else
      alert?.addAlert({ message: "MRZ not found or checksum invalid.", alertType: "warning" });
  }).catch((err) => {
    emit("error", err);
  });
}
onMounted(() => {
  void mrzReader.ensureOpenCvReady();
  startCamera();
});
onBeforeUnmount(() => {
  stopCamera();
});
</script>

<template>
  <v-card flat>
    <v-card-text class="d-flex justify-center" v-if="isLoading">
      <v-progress-circular indeterminate />
    </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>
