<template>
  <div class="flex flex-col w-full h-full gap-2 justify-between px-7 overflow-hidden">
    <RouterLink :to="{ name: 'public-scanner-select' }" class="text-primary" @click="leave">
      Zurück zur Sessionauswahl
    </RouterLink>
    <div class="relative flex flex-col gap-2 w-full grow overflow-hidden max-w-md mx-auto">
      <Spinner v-if="selectedCamera == undefined" class="absolute top-3 left-1/2 -translate-y-1/2" />
      <qrcode-stream
        class="grow"
        :constraints="selectedCamera?.constraints"
        :track="trackFunctionOptions[4].value"
        :formats="barcodeFormats"
        :paused="paused"
        @error="onError"
        @detect="onDetect"
        @camera-on="onCameraReady"
      />
      <br />
      <select v-model="selectedCamera">
        <option v-for="c in selecteableCameras" :value="c">{{ c.label }}</option>
      </select>
      <div class="flex flex-row justify-end gap-4 py-2">
        <button primary-outline :disabled="!paused" @click="paused = false">weiter scannen</button>
        <button primary :disabled="detected == ''" @click="commit">bestätigen</button>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { SocketConnectionTypes } from "@/enums/socketEnum";
import { SocketManager } from "@/socketManager";
import { useNotificationStore } from "@/stores/notification";
import { mapActions } from "pinia";
import { defineComponent } from "vue";
import {
  barcodeFormats,
  defaultConstraintOptions,
  getAvailableCameras,
  handleScannerError,
  trackFunctionOptions,
  type Camera,
} from "@/helpers/scanner";
import { QrcodeStream, type DetectedBarcode } from "vue-qrcode-reader";
import Spinner from "@/components/Spinner.vue";
</script>

<script lang="ts">
export default defineComponent({
  props: {
    room: String,
  },
  data() {
    return {
      selecteableCameras: defaultConstraintOptions,
      selectedCamera: undefined as undefined | Camera,
      paused: false,
      detected: "",
    };
  },
  mounted() {
    let connection = SocketManager.establishConnection(SocketConnectionTypes.pscanner);
    connection.on("connect", () => {
      SocketManager.getConnection(SocketConnectionTypes.pscanner)?.emit("session:join", this.room);
    });
    connection.on("disconnect", () => {
      this.$router.push({ name: "public-scanner-select" });
    });
    connection.on("status-session:join", (res) => {
      if (res.status == "success") {
        this.push("Socket", `Scan-Session beigetreten`, "success");
      } else {
        this.push("Socket", `Scan-Session nicht gefunden`, "error");
        this.$router.push({ name: "public-scanner-select" });
      }
    });
    connection.on("status-session:leave", () => {
      this.push("Socket", `Scan-Session verlassen`, "info");
      SocketManager.getConnection(SocketConnectionTypes.pscanner)?.disconnect();
    });
    connection.on("status-scan:send", (socketId: string) => {
      this.push("Scan-Verbindung", `Scan erfolgreich versendet`, "info");
    });
    connection.on("package-host_leave", (socketId: string) => {
      this.push("Scan-Verbindung", `Session durch Host beendet`, "info");
      SocketManager.getConnection(SocketConnectionTypes.pscanner)?.disconnect();
    });
  },
  methods: {
    ...mapActions(useNotificationStore, ["push"]),
    async onCameraReady() {
      this.selecteableCameras = await getAvailableCameras();
      if (!this.selectedCamera) {
        this.selectedCamera = this.selecteableCameras[0];
      }
    },
    leave() {
      SocketManager.getConnection(SocketConnectionTypes.pscanner)?.emit("session:leave");
      SocketManager.closeConnection(SocketConnectionTypes.pscanner);
    },
    onDetect(result: Array<DetectedBarcode>) {
      this.paused = true;
      this.detected = result.map((r) => r.rawValue)[0];
    },
    onError(err: Error) {
      console.log(handleScannerError(err));
    },
    commit() {
      SocketManager.getConnection(SocketConnectionTypes.pscanner)?.emit("scan:send", this.detected);
      this.detected = "";
    },
  },
});
</script>
