<template>
  <v-row no-gutters>
    <v-col cols="12" class="mb-2">
      <v-row no-gutters align="center" justify="space-between">
        <v-row no-gutters class="ga-2">
          <v-btn
            class="text-none"
            rounded="pill"
            variant="tonal"
            size="large"
            :disabled="!items.length"
            @click="handlePrintAll"
          >
            Print All
          </v-btn>
          <v-btn
            class="text-none"
            rounded="pill"
            variant="tonal"
            size="large"
            :disabled="!qrCodeAccessCards.length"
            @click="generateQrCodes"
          >
            Generate QR Code
          </v-btn>
          <v-btn
            class="text-none"
            rounded="pill"
            variant="tonal"
            size="large"
            :disabled="!qrCodeAccessCardsToPrint.length"
            @click="handlePrintQrCode"
          >
            Print QR Code
          </v-btn>
        </v-row>

        <v-row no-gutters class="ga-2" justify="end" style="max-width: 420px">
          <v-text-field
            v-model="searchText"
            placeholder="Search Card..."
            variant="outlined"
            density="comfortable"
            clearable
            hide-details
            style="max-width: 240px"
          />
        </v-row>
      </v-row>
    </v-col>

    <v-col cols="12">
      <v-card
        width="100%"
        variant="outlined"
        border="thin"
        rounded="lg"
        :loading="loading"
      >
        <v-toolbar density="compact" color="grey-lighten-4">
          <template #prepend>
            <v-btn fab icon density="comfortable" @click="fetchItems">
              <v-icon>mdi-refresh</v-icon>
            </v-btn>
          </template>

          <template #append>
            <v-row no-gutters justify="end" align="center">
              <span class="mr-2 text-caption text-fontgray">
                {{ pageRange }}
              </span>
              <local-pagination
                v-model="page"
                :length="pages"
                @update:value="fetchItems"
              />
            </v-row>
          </template>
        </v-toolbar>

        <v-data-table
          :headers="tableHeaders"
          :items="items"
          item-value="_id"
          items-per-page="10"
          fixed-header
          hide-default-footer
          style="max-height: calc(100vh - 200px)"
        >
          <template #header.selectGenerate>
            <v-checkbox
              :model-value="isAllGenerateSelected"
              @update:model-value="toggleSelectAllGenerate"
              hide-details
              density="compact"
              :disabled="!hasGeneratableItems"
            />
          </template>

          <template #header.selectPrint>
            <v-checkbox
              :model-value="isAllPrintSelected"
              @update:model-value="toggleSelectAllPrint"
              hide-details
              density="compact"
              :disabled="!hasPrintableItems"
              style="margin-left: -12px"
            />
          </template>

          <template #item.selectGenerate="{ item }">
            <v-checkbox
              v-if="!item.qrTag"
              :model-value="qrCodeAccessCards.includes(item._id)"
              @update:model-value="toggleGenerateSelection(item._id)"
              hide-details
              density="compact"
            />
          </template>

          <template #item.cardNo="{ item }">
            <v-row no-gutters align="center" class="ga-2">
              <v-icon size="18" color="grey-darken-1">mdi-card-account-details</v-icon>
              <span>{{ item.cardNo ?? "N/A" }}</span>
            </v-row>
          </template>

          <template #item.qrTagCardNo="{ item }">
            <span>{{ item.qrTagCardNo != null ? `C${item.qrTagCardNo}` : "N/A" }}</span>
          </template>

          <template #item.qrTag="{ item }">
            <v-icon
              :color="item.qrTag ? 'success' : 'grey-lighten-1'"
              size="22"
            >
              {{ item.qrTag ? "mdi-check-circle" : "mdi-circle-outline" }}
            </v-icon>
          </template>

          <template #item.selectPrint="{ item }">
            <v-checkbox
              v-if="item.qrTag"
              :model-value="qrCodeAccessCardsToPrint.includes(item._id)"
              @update:model-value="togglePrintSelection(item._id)"
              hide-details
              density="compact"
              style="margin-left: -12px"
            />
          </template>
        </v-data-table>
      </v-card>
    </v-col>

    <!-- Hidden QR canvases for generation -->
    <ClientOnly>
      <div style="display: none">
        <qrcode-vue
          v-for="qrCode in qrCodesToGenerate"
          :key="qrCode._id"
          :value="qrCode.cardNo"
          :size="150"
          :data-card-id="qrCode._id"
        />
      </div>
    </ClientOnly>

    <!-- Print dialog -->
    <v-dialog v-model="showPrintDialog" max-width="fit-content">
      <AccessCardQrTaggingPrintQr
        ref="printQrRef"
        :access-cards="printPayload"
        @close="showPrintDialog = false"
      />
    </v-dialog>

    <!-- Processing loader -->
    <v-dialog v-model="isGenerating" persistent width="300">
      <v-card>
        <v-card-text class="text-center">
          <v-progress-circular indeterminate color="deep-purple" size="50" />
          <div class="mt-3">Processing QR Codes...</div>
        </v-card-text>
      </v-card>
    </v-dialog>

    <Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
  </v-row>
</template>

<script setup lang="ts">
import QrcodeVue from "qrcode.vue";

definePageMeta({
  middleware: ["01-auth", "02-org"],
  memberOnly: true,
});

const tableHeaders = [
  { title: "", key: "selectGenerate", sortable: false, width: "50px" },
  { title: "Card", key: "cardNo", sortable: false },
  { title: "Location", key: "accessLevel", sortable: false },
  { title: "Card No.", key: "qrTagCardNo", sortable: false },
  { title: "HID", key: "extractedCardNo", sortable: false },
  { title: "QR Code", key: "qrTag", sortable: false },
  { title: "", key: "selectPrint", sortable: false, width: "50px" },
];

const route = useRoute();
const siteId = computed(() => route.params.site as string);
const orgId = computed(() => route.params.org as string);

const page = ref(1);
const pages = ref(0);
const pageRange = ref("-- - -- of --");

const message = ref("");
const messageSnackbar = ref(false);
const messageColor = ref("");

const items = ref<Record<string, any>[]>([]);
const searchText = ref("");

const qrCodeAccessCards = ref<string[]>([]);
const qrCodeAccessCardsToPrint = ref<string[]>([]);
const qrCodesToGenerate = ref<{ _id: string; cardNo: string; qrData: string; qrTagCardNo: string }[]>([]);

const isGenerating = ref(false);
const showPrintDialog = ref(false);
const printPayload = ref<any[]>([]);
const printQrRef = ref();

const {
  getVisitorAccessCards,
  saveVisitorAccessCardQrTag,
  getAllVisitorAccessCardsQrTags,
} = useAccessManagement();

const { addFile, getFileUrl } = useFile();

const {
  data: qrTaggingReq,
  refresh: fetchItems,
  status: fetchStatus,
} = useLazyAsyncData(
  "get-qr-tagging",
  () =>
    getVisitorAccessCards({
      page: page.value,
      limit: 10,
      site: siteId.value,
      search: searchText.value || undefined,
    }),
  { watch: [page, searchText] }
);

const loading = computed(() => fetchStatus.value === "pending");

watchEffect(() => {
  if (qrTaggingReq.value?.data) {
    items.value = qrTaggingReq.value.data.items.map((item: any) => ({
      ...item,
      qrTagCardNo: item.qrTagCardNo ?? item.extractedCardNo,
    }));
    pages.value = qrTaggingReq.value.data.pages;
    pageRange.value = qrTaggingReq.value.data.pageRange;
  }
});

const hasGeneratableItems = computed(() =>
  items.value.some((item) => !item.qrTag)
);
const hasPrintableItems = computed(() =>
  items.value.some((item) => !!item.qrTag)
);

const isAllGenerateSelected = computed(() => {
  const generatable = items.value.filter((item) => !item.qrTag);
  return (
    generatable.length > 0 &&
    generatable.every((item) => qrCodeAccessCards.value.includes(item._id))
  );
});

const isAllPrintSelected = computed(() => {
  const printable = items.value.filter((item) => !!item.qrTag);
  return (
    printable.length > 0 &&
    printable.every((item) =>
      qrCodeAccessCardsToPrint.value.includes(item._id)
    )
  );
});

function toggleSelectAllGenerate(value: boolean | null) {
  if (value) {
    qrCodeAccessCards.value = items.value
      .filter((item) => !item.qrTag)
      .map((item) => item._id);
  } else {
    qrCodeAccessCards.value = [];
  }
}

function toggleSelectAllPrint(value: boolean | null) {
  if (value) {
    qrCodeAccessCardsToPrint.value = items.value
      .filter((item) => !!item.qrTag)
      .map((item) => item._id);
  } else {
    qrCodeAccessCardsToPrint.value = [];
  }
}

function toggleGenerateSelection(id: string) {
  if (qrCodeAccessCards.value.includes(id)) {
    qrCodeAccessCards.value = qrCodeAccessCards.value.filter((i) => i !== id);
  } else {
    qrCodeAccessCards.value.push(id);
  }
}

function togglePrintSelection(id: string) {
  if (qrCodeAccessCardsToPrint.value.includes(id)) {
    qrCodeAccessCardsToPrint.value = qrCodeAccessCardsToPrint.value.filter(
      (i) => i !== id
    );
  } else {
    qrCodeAccessCardsToPrint.value.push(id);
  }
}

async function generateQrCodes() {
  isGenerating.value = true;

  const filteredCards = items.value.filter((card) =>
    qrCodeAccessCards.value.includes(card._id)
  );

  qrCodesToGenerate.value = filteredCards.map((card) => ({
    _id: card._id,
    cardNo: card.cardNo,
    qrData: card.cardNo,
    qrTagCardNo: card.qrTagCardNo ?? "",
  }));

  await nextTick();
  await nextTick();

  const payloads: Array<{ _id: string; cardNo: string; qrTag: string; qrTagCardNo: string }> = [];

  await Promise.all(
    qrCodesToGenerate.value.map(async (qrCode) => {
      const fileUrl = await saveQrCodeToStorage(qrCode._id);
      if (fileUrl) {
        payloads.push({
          _id: qrCode._id,
          cardNo: qrCode.cardNo,
          qrTag: fileUrl,
          qrTagCardNo: qrCode.qrTagCardNo,
        });
      }
    })
  );

  try {
    if (payloads.length > 0) {
      await saveVisitorAccessCardQrTag(siteId.value, payloads);
      showMessage(`${payloads.length} QR code(s) generated successfully`, "success");
    } else {
      showMessage("No QR codes could be generated", "warning");
    }
  } catch {
    showMessage("Failed to save QR codes", "error");
  }

  await fetchItems();

  qrCodesToGenerate.value = [];
  qrCodeAccessCards.value = [];
  isGenerating.value = false;
}

async function saveQrCodeToStorage(_id: string): Promise<string | null> {
  const canvas = document.querySelector<HTMLCanvasElement>(
    `canvas[data-card-id="${_id}"]`
  );
  if (!canvas) return null;

  return new Promise((resolve) => {
    canvas.toBlob(async (blob) => {
      if (!blob) return resolve(null);
      const file = new File([blob], `${_id}.png`, { type: "image/png" });
      try {
        const res = await addFile(file);
        resolve(res?.id ? getFileUrl(res.id) : null);
      } catch {
        resolve(null);
      }
    }, "image/png");
  });
}

async function handlePrintQrCode() {
  const payload = items.value
    .filter((card) => qrCodeAccessCardsToPrint.value.includes(card._id))
    .map((card) => ({
      accessLevel: card.accessLevel,
      cardNumber: card.extractedCardNo,
      qrDataImage: card.qrTag,
      qrTagCardNo: card.qrTagCardNo,
    }));

  if (!payload.length) return;

  printPayload.value = payload;
  showPrintDialog.value = true;

  await nextTick();
  await nextTick();

  printQrRef.value?.downloadPDF();
  qrCodeAccessCardsToPrint.value = [];
  showMessage("Printing QR codes...", "success");
}

async function handlePrintAll() {
  isGenerating.value = true;
  try {
    const response: any = await getAllVisitorAccessCardsQrTags(siteId.value);

    if (!response?.data?.items?.length) {
      showMessage("No QR codes found to print", "warning");
      return;
    }

    printPayload.value = response.data.items.map((card: any) => ({
      accessLevel: card.accessLevel,
      cardNumber: card.extractedCardNo,
      qrDataImage: card.qrTag,
      qrTagCardNo: card.qrTagCardNo,
    }));

    showPrintDialog.value = true;

    await nextTick();
    await nextTick();

    printQrRef.value?.downloadPDF();
    showMessage("Printing all QR codes...", "success");
  } catch (error: any) {
    showMessage(error || "Failed to fetch QR codes", "error");
  } finally {
    isGenerating.value = false;
  }
}

function showMessage(msg: string, color: string) {
  message.value = msg;
  messageColor.value = color;
  messageSnackbar.value = true;
}
</script>
