<template>
  <div>
    <!-- Page Header Component -->
    <PageHeader
      logo="/Rumah_Sakit_Umum_Daerah_Dr._Saiful_Anwar.webp"
      title="Check-In Pasien"
      subtitle="Scan QR Code atau Input Manual untuk Check-In"
      :show-add-button="true"
      add-button-text="Generate QR"
      theme="primary"
      @add-click="showGenerateQRDialog = true"
    />

    <div class="checkin-page-container">
      <!-- Main Content Grid - Same pattern as AdminLoket.vue -->
      <v-row class="content-grid" dense>
        <!-- Left Column: QR Scan Card -->
        <v-col cols="12" md="6" lg="7" class="sticky-column d-flex">
          <div class="sticky-wrapper" style="width: 100%">
            <v-card class="qr-scan-card" elevation="0" style="height: 100%">
              <v-card-text class="pa-4 d-flex flex-column" style="height: 100%">
                <!-- Status Header -->
                <div class="status-header mb-3">
                  <div class="status-icon-wrapper">
                    <v-icon :color="primaryColor" size="20"
                      >mdi-qrcode-scan</v-icon
                    >
                  </div>
                  <div class="status-text">
                    <h3 class="status-title">
                      {{
                        isScanning
                          ? "Arahkan Kamera ke QR Code"
                          : "Siap untuk Scan QR Code"
                      }}
                    </h3>
                    <p class="status-subtitle">
                      {{
                        isScanning
                          ? "Pastikan QR code terlihat jelas dan tidak terpotong"
                          : "Klik tombol di bawah untuk memulai scan"
                      }}
                    </p>
                  </div>
                </div>

                <!-- Camera Status Check -->
                <div v-if="cameraChecking" class="text-center mb-4">
                  <v-progress-circular
                    indeterminate
                    :color="primaryColor"
                    size="24"
                    class="mr-2"
                  ></v-progress-circular>
                  <span class="text-body-2 text-grey"
                    >Memeriksa ketersediaan kamera...</span
                  >
                </div>

                <!-- Camera Not Available Warning -->
                <v-alert
                  v-else-if="!hasCamera && !isScanning"
                  type="warning"
                  variant="tonal"
                  class="mb-3 compact-alert"
                  density="compact"
                >
                  <template v-slot:prepend>
                    <v-icon>mdi-camera-off</v-icon>
                  </template>
                  <div>
                    <p class="font-weight-bold mb-1">Kamera tidak terdeteksi</p>
                    <p class="text-body-2 mb-0">
                      Perangkat Anda tidak memiliki kamera atau kamera tidak
                      dapat diakses. Silakan gunakan input
                      <strong>Manual</strong> di sebelah kanan .
                    </p>
                  </div>
                </v-alert>

                <!-- QR Scanner Area dengan webcam -->
                <div class="qr-scanner-container mb-4">
                  <div
                    v-if="!isScanning"
                    class="qr-placeholder"
                    role="region"
                    aria-label="Area pemindaian QR code"
                  >
                    <div class="scanner-overlay">
                      <div class="corner corner-tl"></div>
                      <div class="corner corner-tr"></div>
                      <div class="corner corner-bl"></div>
                      <div class="corner corner-br"></div>
                      <div class="scan-line"></div>
                    </div>
                    <v-icon size="64" :color="primaryColor" class="qr-icon"
                      >mdi-qrcode-scan</v-icon
                    >
                  </div>
                  <div v-else class="qr-reader-container">
                    <div
                      class="scanner-status mb-2"
                      role="status"
                      aria-live="polite"
                      aria-atomic="true"
                    >
                      <v-chip color="success" size="small" class="mr-2">
                        <v-icon start size="16">mdi-camera</v-icon>
                        Kamera Aktif
                      </v-chip>
                      <span class="text-caption text-grey"
                        >Preview kamera sedang berjalan</span
                      >
                      <v-spacer></v-spacer>
                      <v-btn
                        icon
                        variant="text"
                        size="small"
                        :color="primaryColor"
                        @click="switchCamera"
                        title="Ganti Kamera"
                      >
                        <v-icon>mdi-camera-flip</v-icon>
                      </v-btn>
                    </div>
                    <div
                      id="qr-reader"
                      class="qr-reader-wrapper"
                      :class="{ 'is-front': isFrontCamera }"
                      role="region"
                      aria-label="Area pemindaian QR code"
                      aria-live="polite"
                    ></div>
                    <!-- Hidden input for Photo Mode -->
                    <input
                      type="file"
                      ref="fileInput"
                      style="display: none"
                      accept="image/*"
                      @change="handleFileSelect"
                    />
                    <!-- Moved overlay outside to prevent Vue/DOM conflict -->
                    <div class="scanner-loading-overlay" v-show="!cameraReady && isScanning">
                      <v-progress-circular
                        indeterminate
                        color="white"
                        size="48"
                      ></v-progress-circular>
                      <p class="text-white mt-4">Memuat kamera...</p>
                    </div>
                    <div class="scanner-instruction">
                      <v-icon :color="primaryColor" size="16"
                        >mdi-information</v-icon
                      >
                      <span class="text-caption"
                        >Arahkan kamera ke QR code. Pastikan QR code berada
                        dalam kotak pemindaian.</span
                      >
                    </div>
                  </div>
                </div>

                <!-- Action Button Minimalis -->
                <div class="action-buttons">
                  <v-btn
                    v-if="!isScanning"
                    class="btn-primary-modern btn-centered"
                    size="x-large"
                    elevation="2"
                    @click="startScanning"
                    @keydown.enter="startScanning"
                    @keydown.space.prevent="startScanning"
                    :disabled="!hasCamera && !cameraChecking"
                    block
                    tabindex="0"
                    aria-label="Mulai scan QR code"
                    style="
                      font-weight: 600;
                      letter-spacing: 0.5px;
                      min-height: 56px;
                    "
                  >
                    <v-icon start size="24">mdi-camera</v-icon>
                    {{ hasCamera ? "Mulai Scan QR" : "Kamera Tidak Tersedia" }}
                  </v-btn>
                  <v-btn
                    v-else
                    class="btn-stop-modern btn-centered"
                    size="x-large"
                    elevation="2"
                    @click="stopScanning"
                    @keydown.enter="stopScanning"
                    @keydown.space.prevent="stopScanning"
                    block
                    tabindex="0"
                    aria-label="Stop scan QR code"
                    style="
                      font-weight: 600;
                      letter-spacing: 0.5px;
                      min-height: 56px;
                    "
                  >
                    <v-icon start size="24">mdi-camera-off</v-icon>
                    Stop Scan
                  </v-btn>
                </div>

                <!-- Info tambahan -->
                <div class="info-card mt-3">
                  <v-alert
                    type="info"
                    variant="tonal"
                    :color="primaryColor"
                    class="text-body-2 info-alert-centered"
                    density="compact"
                  >
                    <div class="d-flex align-center justify-center">
                      <v-icon size="16" class="mr-2"
                        >mdi-lightbulb-outline</v-icon
                      >
                      <span style="font-size: 12px"
                        >Tips: Pastikan pencahayaan cukup untuk hasil scan
                        optimal</span
                      >
                    </div>
                  </v-alert>
                </div>

                <!-- Test Camera Button (Debug) - Hidden in production -->
                <div v-if="false" class="test-camera-section mt-2 mb-2">
                  <v-btn
                    variant="outlined"
                    color="primary"
                    size="small"
                    class="text-none btn-centered-small btn-test-camera"
                    @click="testCamera"
                    block
                  >
                    <v-icon start size="18" color="#1565C0">mdi-camera</v-icon>
                    Test Kamera
                  </v-btn>
                  <p
                    class="text-caption text-grey text-center mt-1"
                    style="font-size: 11px"
                  >
                    Klik untuk menguji apakah browser dapat mengakses kamera
                  </p>
                </div>

                <!-- Quick Access Buttons -->
                <div class="quick-actions mt-4">
                  <p class="text-caption text-grey text-center mb-3">
                    Akses Cepat
                  </p>
                  <v-row dense>
                    <v-col cols="12">
                      <v-btn
                        variant="outlined"
                        :color="primaryColor"
                        block
                        size="small"
                        class="text-none"
                        @click="openHistoryDialog"
                      >
                        <v-icon start size="18">mdi-history</v-icon>
                        Riwayat Check-in
                      </v-btn>
                    </v-col>
                    <v-col cols="12">
                      <v-btn
                        variant="outlined"
                        color="primary"
                        block
                        size="small"
                        class="text-none"
                        @click="openQRHistoryDialog"
                      >
                        <v-icon start size="18" color="#1565C0"
                          >mdi-qrcode-scan</v-icon
                        >
                        Riwayat QR Scan
                      </v-btn>
                    </v-col>
                  </v-row>
                </div>
              </v-card-text>
            </v-card>
          </div>
        </v-col>

        <!-- Right Column: Manual Input Card -->
        <v-col cols="12" md="6" lg="5" class="manual-input-column d-flex">
          <v-card
            class="manual-input-card"
            elevation="0"
            style="height: 100%; width: 100%"
          >
            <v-card-text class="pa-4 d-flex flex-column" style="height: 100%">
              <!-- Status Header -->
              <div class="status-header mb-3">
                <div class="status-icon-wrapper">
                  <v-icon :color="secondaryColor" size="20"
                    >mdi-keyboard</v-icon
                  >
                </div>
                <div class="status-text">
                  <h3 class="status-title">Input Manual</h3>
                  <p class="status-subtitle">
                    Masukkan nomor Antrean atau Barcode Pasien
                  </p>
                </div>
              </div>

              <v-form @submit.prevent="checkInManual" ref="manualForm">
                <v-text-field
                  v-model="manualInput"
                  label="Nomor Antrean / Barcode Pasien"
                  placeholder="Contoh: RA020 atau 26011500001"
                  prepend-inner-icon="mdi-account-card-details"
                  variant="outlined"
                  :color="primaryColor"
                  class="input-modern mb-4"
                  required
                  :rules="[(v) => !!v || 'Field ini wajib diisi']"
                  density="comfortable"
                  hide-details="auto"
                >
                  <template v-slot:append-inner>
                    <v-icon :color="manualInput ? 'success' : 'grey'" size="20">
                      {{
                        manualInput ? "mdi-check-circle" : "mdi-circle-outline"
                      }}
                    </v-icon>
                  </template>
                </v-text-field>

                <v-btn
                  class="btn-primary-modern btn-centered"
                  size="x-large"
                  type="submit"
                  elevation="2"
                  block
                  tabindex="0"
                  aria-label="Check-in sekarang dengan nomor antrean atau barcode pasien"
                  style="
                    font-weight: 600;
                    letter-spacing: 0.5px;
                    min-height: 56px;
                  "
                  @keydown.enter.prevent="checkInManual"
                >
                  <v-icon start size="24">mdi-login</v-icon>
                  Check-in Sekarang
                </v-btn>
              </v-form>

              <!-- Quick Access Buttons -->
              <div class="quick-actions mt-4">
                <p class="text-caption text-grey text-center mb-3">
                  Akses Cepat
                </p>
                <v-row dense>
                  <v-col cols="12">
                    <v-btn
                      variant="outlined"
                      :color="primaryColor"
                      block
                      size="small"
                      class="text-none"
                      @click="openHistoryDialog"
                    >
                      <v-icon start size="18">mdi-history</v-icon>
                      Lihat Semua Riwayat
                    </v-btn>
                  </v-col>
                </v-row>
              </div>

              <!-- Riwayat Check-in -->
              <div class="history-section mt-6">
                <div class="d-flex align-center justify-space-between mb-4">
                  <div class="d-flex align-center">
                    <div class="history-header-icon">
                      <v-icon size="24" :color="primaryColor"
                        >mdi-history</v-icon
                      >
                    </div>
                    <h4
                      class="text-h6 font-weight-bold ml-3"
                      style="color: #1a1a1a"
                    >
                      Riwayat Check-in
                    </h4>
                  </div>
                  <v-chip
                    size="small"
                    :color="
                      recentHistory.length > 0 ? 'primary' : 'grey-lighten-2'
                    "
                    variant="flat"
                    class="font-weight-semibold"
                  >
                    {{ recentHistory.length }} item
                  </v-chip>
                </div>

                <div
                  v-if="recentHistory.length > 0"
                  class="recent-history-list"
                >
                  <!-- Info jumlah data -->
                  <div
                    v-if="recentHistory.length > recentHistoryItemsPerPage"
                    class="mb-2 text-caption text-grey-darken-1"
                  >
                    Menampilkan
                    {{
                      (recentHistoryPage - 1) * recentHistoryItemsPerPage + 1
                    }}
                    -
                    {{
                      Math.min(
                        recentHistoryPage * recentHistoryItemsPerPage,
                        recentHistory.length,
                      )
                    }}
                    dari {{ recentHistory.length }} riwayat
                  </div>

                  <v-card
                    v-for="(item, index) in paginatedRecentHistory"
                    :key="index"
                    variant="flat"
                    elevation="0"
                    class="mb-1 history-item-compact"
                    :class="getStatusClass(item.status)"
                  >
                    <v-card-text class="pa-1">
                      <div class="history-item-content">
                        <!-- Header Row: Status Badge & Time -->
                        <div
                          class="d-flex align-center justify-space-between mb-1"
                        >
                          <div class="d-flex align-center gap-1">
                            <div
                              class="history-status-badge"
                              :class="`status-${getStatusColor(item.status)}`"
                            >
                              <v-icon size="12">{{
                                getStatusIcon(item.status)
                              }}</v-icon>
                            </div>
                            <div>
                              <div
                                class="history-status-text"
                                :class="`text-${getStatusColor(item.status)}`"
                              >
                                {{ getStatusText(item.status) }}
                              </div>
                              <div class="history-method-text">
                                {{ item.method }}
                              </div>
                            </div>
                          </div>
                          <div class="history-time-badge">
                            <v-icon size="10" class="mr-1"
                              >mdi-clock-outline</v-icon
                            >
                            <span>{{ formatTime(item.checkInTime) }}</span>
                          </div>
                        </div>

                        <!-- Content Row: Klinik & Queue Number -->
                        <div
                          class="d-flex align-center justify-space-between mb-1 flex-wrap gap-1"
                        >
                          <div
                            v-if="item.klinik && item.klinik !== 'N/A'"
                            class="history-klinik-badge"
                          >
                            <v-icon size="10" class="mr-1"
                              >mdi-hospital-building</v-icon
                            >
                            <span>{{ item.klinik }}</span>
                          </div>
                          <div
                            v-if="item.klinikQueueNumber || item.queueNumber"
                            class="history-queue-badge"
                          >
                            <v-icon size="10" class="mr-1">mdi-ticket</v-icon>
                            <span class="font-weight-semibold">{{
                              item.klinikQueueNumber || item.queueNumber
                            }}</span>
                          </div>
                        </div>

                        <!-- Footer Row: Patient ID & Payment -->
                        <div
                          v-if="
                            item.patientId ||
                            (item.pembayaran && item.pembayaran !== 'N/A')
                          "
                          class="d-flex align-center flex-wrap gap-1 pt-1 border-top-history"
                        >
                          <div v-if="item.patientId" class="history-info-badge">
                            <v-icon size="10" class="mr-1"
                              >mdi-account-circle</v-icon
                            >
                            <span>{{ item.patientId }}</span>
                          </div>
                          <div
                            v-if="item.pembayaran && item.pembayaran !== 'N/A'"
                            class="history-info-badge"
                          >
                            <v-icon size="10" class="mr-1"
                              >mdi-credit-card</v-icon
                            >
                            <span>{{ item.pembayaran }}</span>
                          </div>
                        </div>
                      </div>
                    </v-card-text>
                  </v-card>

                  <!-- Pagination untuk recent history -->
                  <div
                    v-if="totalRecentHistoryPages > 1"
                    class="mt-3 d-flex justify-center"
                  >
                    <v-pagination
                      v-model="recentHistoryPage"
                      :length="totalRecentHistoryPages"
                      :total-visible="5"
                      color="primary"
                      size="small"
                      density="compact"
                      rounded="circle"
                    ></v-pagination>
                  </div>
                </div>

                <div v-else class="empty-history-state text-center py-8">
                  <div class="empty-history-icon mb-4">
                    <v-icon size="64" color="grey-lighten-1"
                      >mdi-history</v-icon
                    >
                  </div>
                  <h5
                    class="text-subtitle-1 font-weight-semibold mb-2"
                    style="color: #4a5568"
                  >
                    Belum ada riwayat check-in
                  </h5>
                  <p class="text-body-2 text-grey mb-4">
                    Riwayat check-in Anda akan muncul di sini setelah melakukan
                    check-in
                  </p>
                </div>
              </div>
            </v-card-text>
          </v-card>
        </v-col>
      </v-row>
      <!-- Stats Footer (Horizontal) - Permanent Footer for All Screens -->
      <v-row class="stats-footer-row" dense>
        <v-col cols="12">
          <div class="stats-footer-horizontal">
            <div
              class="stat-item-footer-enhanced stat-item-footer-primary"
              :title="`Total Check-in Hari Ini: ${todayStats.total}`"
            >
              <div class="stat-icon-footer-enhanced">
                <v-icon :color="primaryColor" size="18"
                  >mdi-calendar-today</v-icon
                >
              </div>
              <div class="stat-content-footer-enhanced">
                <div class="stat-value-footer-enhanced">
                  {{ todayStats.total }}
                </div>
                <div class="stat-label-footer-enhanced">Hari Ini</div>
              </div>
            </div>
            <div
              class="stat-item-footer-enhanced stat-item-footer-success"
              :title="`Check-in Berhasil: ${todayStats.success}`"
            >
              <div class="stat-icon-footer-enhanced">
                <v-icon color="success" size="18">mdi-check-circle</v-icon>
              </div>
              <div class="stat-content-footer-enhanced">
                <div class="stat-value-footer-enhanced">
                  {{ todayStats.success }}
                </div>
                <div class="stat-label-footer-enhanced">Berhasil</div>
              </div>
            </div>
            <div
              class="stat-item-footer-enhanced stat-item-footer-error"
              :title="`Check-in Gagal: ${todayStats.failed}`"
            >
              <div class="stat-icon-footer-enhanced">
                <v-icon color="error" size="18">mdi-close-circle</v-icon>
              </div>
              <div class="stat-content-footer-enhanced">
                <div class="stat-value-footer-enhanced">
                  {{ todayStats.failed }}
                </div>
                <div class="stat-label-footer-enhanced">Gagal</div>
              </div>
            </div>
            <div
              class="stat-item-footer-enhanced stat-item-footer-info"
              :title="`Check-in via QR: ${todayStats.qr}`"
            >
              <div class="stat-icon-footer-enhanced">
                <v-icon color="info" size="18">mdi-qrcode-scan</v-icon>
              </div>
              <div class="stat-content-footer-enhanced">
                <div class="stat-value-footer-enhanced">
                  {{ todayStats.qr }}
                </div>
                <div class="stat-label-footer-enhanced">QR Scan</div>
              </div>
            </div>
            <div
              class="stat-item-footer-enhanced stat-item-footer-warning"
              :title="`Check-in Manual: ${todayStats.manual}`"
            >
              <div class="stat-icon-footer-enhanced">
                <v-icon color="warning" size="18">mdi-keyboard</v-icon>
              </div>
              <div class="stat-content-footer-enhanced">
                <div class="stat-value-footer-enhanced">
                  {{ todayStats.manual }}
                </div>
                <div class="stat-label-footer-enhanced">Manual</div>
              </div>
            </div>
          </div>
        </v-col>
      </v-row>

      <!-- Generate QR Dialog -->
      <v-dialog v-model="showGenerateQRDialog" max-width="600px" scrollable>
        <v-card>
          <v-card-title class="text-h5 pa-4 bg-primary text-white">
            <v-icon class="mr-2" color="white">mdi-qrcode</v-icon>
            Generate QR Code untuk Testing
          </v-card-title>
          <v-card-text class="pa-6">
            <!-- Status Header -->
            <div class="mb-4">
              <p class="text-body-2 text-grey">
                Buat QR code yang bisa Anda scan untuk testing check-in
              </p>
            </div>

            <!-- Quick Preset Buttons -->
            <div class="mb-4">
              <p class="text-caption text-grey text-center mb-2">
                Quick Generate:
              </p>
              <v-row dense>
                <v-col cols="12">
                  <v-btn
                    variant="outlined"
                    color="primary"
                    size="small"
                    @click="generateQRCode"
                    class="text-none"
                    block
                    :disabled="!selectedKlinik"
                  >
                    <v-icon start size="16">mdi-qrcode-plus</v-icon>
                    Generate QR Code dengan Barcode Count
                  </v-btn>
                </v-col>
              </v-row>
            </div>

            <!-- Form Generate -->
            <v-form @submit.prevent="generateQRCode">
              <v-select
                v-model="selectedKlinik"
                label="Pilih Klinik/Poli"
                :items="klinikOptions"
                prepend-inner-icon="mdi-hospital-building"
                variant="outlined"
                :color="primaryColor"
                class="mb-3"
                density="comfortable"
                :rules="[(v) => !!v || 'Klinik/Poli harus dipilih']"
                hide-details="auto"
                required
              ></v-select>

              <v-select
                v-model="selectedPembayaran"
                label="Jenis Pembayaran"
                :items="[
                  { title: 'UMUM', value: 'UMUM' },
                  { title: 'BPJS', value: 'BPJS' },
                  { title: 'ASURANSI', value: 'ASURANSI' },
                ]"
                prepend-inner-icon="mdi-credit-card"
                variant="outlined"
                :color="primaryColor"
                class="mb-3"
                density="comfortable"
                hide-details="auto"
              ></v-select>

              <v-text-field
                v-model="generateBarcode"
                label="Barcode"
                placeholder="Auto-generate berdasarkan tanggal"
                prepend-inner-icon="mdi-barcode"
                variant="outlined"
                :color="primaryColor"
                class="mb-3"
                density="comfortable"
                readonly
                hint="Barcode akan di-generate otomatis menggunakan format YYMMDD + 5 digit sequential"
                persistent-hint
                hide-details="auto"
              ></v-text-field>

              <v-text-field
                v-model="generateQueueNumber"
                label="Nomor Antrean"
                placeholder="Auto-generate berdasarkan Klinik dan Pembayaran"
                prepend-inner-icon="mdi-ticket"
                variant="outlined"
                :color="primaryColor"
                class="mb-4"
                density="comfortable"
                readonly
                hint="Nomor Antrean akan di-generate otomatis dengan format R/E + Loket + 3 digit"
                persistent-hint
                hide-details="auto"
              ></v-text-field>

              <div class="d-flex justify-center">
                <v-btn
                  color="primary"
                  size="large"
                  type="submit"
                  elevation="0"
                  :disabled="!selectedKlinik"
                >
                  <v-icon start size="20">mdi-qrcode-plus</v-icon>
                  Generate QR Code
                </v-btn>
              </div>
            </v-form>

            <!-- QR Code Display -->
            <div v-if="generatedQRData" class="mt-6">
              <v-card variant="outlined" class="pa-4">
                <div class="text-center">
                  <p class="text-subtitle-2 text-grey mb-3">QR Code Tiket:</p>
                  <div id="qrcode" class="qr-code-container mb-4"></div>

                  <div v-if="generatedPatient" class="mb-3">
                    <v-chip color="primary" class="mb-2">
                      <v-icon start size="16">mdi-ticket</v-icon>
                      Nomor Antrean: {{ generateQueueNumber }}
                    </v-chip>
                    <v-chip color="info" class="mb-2 ml-2">
                      <v-icon start size="16">mdi-barcode</v-icon>
                      Barcode: {{ generateBarcode }}
                    </v-chip>
                  </div>

                  <p class="text-body-2 text-grey mb-4">
                    QR Code berisi: <strong>{{ generatedQRData }}</strong>
                  </p>

                  <!-- Action Buttons -->
                  <v-row dense>
                    <v-col cols="6">
                      <v-btn
                        color="primary"
                        variant="flat"
                        block
                        size="default"
                        @click="handlePrintTicket"
                        :loading="isPrinting"
                        :disabled="isPrinting || !generatedPatient"
                        class="text-none"
                      >
                        <v-icon start size="20">mdi-printer</v-icon>
                        {{ isPrinting ? "Mencetak..." : "Cetak Tiket" }}
                      </v-btn>
                    </v-col>
                    <v-col cols="3">
                      <v-btn
                        variant="outlined"
                        :color="primaryColor"
                        block
                        size="small"
                        @click="downloadQR"
                        class="text-none"
                      >
                        <v-icon start size="18">mdi-download</v-icon>
                        Download
                      </v-btn>
                    </v-col>
                    <v-col cols="3">
                      <v-btn
                        variant="outlined"
                        :color="primaryColor"
                        block
                        size="small"
                        @click="copyQRToClipboard"
                        class="text-none"
                      >
                        <v-icon start size="18">mdi-content-copy</v-icon>
                        Copy
                      </v-btn>
                    </v-col>
                  </v-row>
                </div>
              </v-card>

              <!-- Instructions -->
              <v-alert type="success" variant="tonal" class="mt-4 text-body-2">
                <template v-slot:prepend>
                  <v-icon>mdi-information</v-icon>
                </template>
                <strong>Cara menggunakan:</strong>
                <ol class="ml-4 mt-2">
                  <li>
                    Pilih <strong>Klinik/Poli</strong> dan
                    <strong>Jenis Pembayaran</strong>
                  </li>
                  <li>
                    Klik <strong>"Generate QR Code"</strong> untuk membuat QR
                    code dengan barcode count
                  </li>
                  <li>
                    Klik <strong>"Cetak Tiket"</strong> untuk mencetak tiket
                    menggunakan thermal printer
                  </li>
                  <li>
                    Atau gunakan <strong>"Download"</strong> untuk menyimpan QR
                    code sebagai gambar
                  </li>
                  <li>Scan QR code pada tiket untuk proses check-in</li>
                </ol>
              </v-alert>
            </div>
          </v-card-text>
          <v-card-actions class="pa-4">
            <v-spacer></v-spacer>
            <v-btn
              color="grey"
              variant="text"
              @click="showGenerateQRDialog = false"
            >
              Tutup
            </v-btn>
          </v-card-actions>
        </v-card>
      </v-dialog>

      <!-- Enhanced Dialog with Blur -->
      <v-dialog
        v-model="infoDialog"
        max-width="500"
        persistent
        transition="dialog-transition"
        scrim="rgba(0, 0, 0, 0.5)"
        class="blur-dialog"
      >
        <v-card class="rounded-xl dialog-card" elevation="24">
          <div
            class="dialog-header text-center pa-6"
            :class="
              lastCheckInResult?.success && infoAction === 'checkin'
                ? 'success-header'
                : lastCheckInResult?.status === 'NOT_ALLOWED'
                  ? 'warning-header'
                  : lastCheckInResult?.status === 'ALREADY_CHECKED_IN'
                    ? 'warning-header'
                    : 'error-header'
            "
          >
            <div class="icon-wrapper mb-3">
              <div
                class="icon-bg"
                :class="
                  lastCheckInResult?.success && infoAction === 'checkin'
                    ? 'icon-bg-success'
                    : lastCheckInResult?.status === 'NOT_ALLOWED'
                      ? 'icon-bg-warning'
                      : lastCheckInResult?.status === 'ALREADY_CHECKED_IN'
                        ? 'icon-bg-warning'
                        : 'icon-bg-error'
                "
              >
                <v-icon size="56" color="white" class="dialog-icon">
                  {{
                    lastCheckInResult?.success && infoAction === "checkin"
                      ? "mdi-check-circle"
                      : lastCheckInResult?.status === "NOT_ALLOWED"
                        ? "mdi-clock-alert"
                        : lastCheckInResult?.status === "ALREADY_CHECKED_IN"
                          ? "mdi-check-circle"
                          : "mdi-close-circle"
                  }}
                </v-icon>
              </div>
            </div>

            <h2 class="text-h5 font-weight-bold text-white mb-2">
              {{
                lastCheckInResult?.success && infoAction === "checkin"
                  ? "Check-in Berhasil!"
                  : lastCheckInResult?.status === "NOT_ALLOWED"
                    ? "Belum Diizinkan"
                    : lastCheckInResult?.status === "ALREADY_CHECKED_IN"
                      ? "Sudah Check-in"
                      : "Check-in Gagal"
              }}
            </h2>

            <div class="status-badge mt-2">
              <v-chip
                :color="
                  lastCheckInResult?.success && infoAction === 'checkin'
                    ? 'white'
                    : 'white'
                "
                :text-color="
                  lastCheckInResult?.success && infoAction === 'checkin'
                    ? 'success'
                    : lastCheckInResult?.status === 'NOT_ALLOWED'
                      ? 'orange'
                      : lastCheckInResult?.status === 'ALREADY_CHECKED_IN'
                        ? 'orange'
                        : 'error'
                "
                size="small"
                class="font-weight-bold"
              >
                <v-icon start size="14">
                  {{
                    lastCheckInResult?.success && infoAction === "checkin"
                      ? "mdi-check"
                      : lastCheckInResult?.status === "NOT_ALLOWED"
                        ? "mdi-clock-alert"
                        : lastCheckInResult?.status === "ALREADY_CHECKED_IN"
                          ? "mdi-check-circle"
                          : "mdi-close-circle"
                  }}
                </v-icon>
                {{
                  lastCheckInResult?.success && infoAction === "checkin"
                    ? "Berhasil"
                    : lastCheckInResult?.status === "NOT_ALLOWED"
                      ? "Menunggu"
                      : lastCheckInResult?.status === "ALREADY_CHECKED_IN"
                        ? "Sudah Check-in"
                        : "Gagal"
                }}
              </v-chip>
            </div>
          </div>

          <v-card-text class="pa-5">
            <div class="message-container">
              <div
                class="text-body-1 font-weight-medium mb-4 text-center"
                style="white-space: pre-line; color: #2d3748"
              >
                {{ infoMessage }}
              </div>

              <v-divider class="my-4"></v-divider>

              <div
                v-if="lastCheckInResult"
                class="instruction-box pa-3 rounded-lg mb-4"
                :class="
                  lastCheckInResult.success && infoAction === 'checkin'
                    ? 'instruction-success'
                    : lastCheckInResult?.status === 'ALREADY_CHECKED_IN'
                      ? 'instruction-warning'
                      : 'instruction-warning'
                "
              >
                <div class="d-flex align-start">
                  <v-icon
                    :color="
                      lastCheckInResult.success && infoAction === 'checkin'
                        ? 'success'
                        : lastCheckInResult?.status === 'ALREADY_CHECKED_IN'
                          ? 'orange'
                          : 'orange'
                    "
                    class="mr-2 mt-1"
                    size="20"
                  >
                    {{
                      lastCheckInResult.success && infoAction === "checkin"
                        ? "mdi-check-circle"
                        : lastCheckInResult?.status === "ALREADY_CHECKED_IN"
                          ? "mdi-check-circle"
                          : "mdi-timer-sand"
                    }}
                  </v-icon>
                  <div>
                    <p class="text-body-2 font-weight-medium mb-1">
                      {{
                        lastCheckInResult.success && infoAction === "checkin"
                          ? "Status Check-in:"
                          : "Status:"
                      }}
                    </p>
                    <p class="text-body-2 text-grey-darken-1 mb-0">
                      {{
                        lastCheckInResult.success && infoAction === "checkin"
                          ? "Check-in telah berhasil dilakukan. Pasien dapat melanjutkan ke tahap selanjutnya."
                          : lastCheckInResult.status === "NOT_ALLOWED"
                            ? "Mohon menunggu hingga antrean Anda dipanggil oleh petugas"
                            : lastCheckInResult.status === "ALREADY_CHECKED_IN"
                              ? "Tiket ini sudah melakukan check-in sebelumnya. Tidak perlu check-in ulang."
                              : "Proses check-in gagal. Silakan coba lagi atau hubungi petugas."
                      }}
                    </p>
                  </div>
                </div>
              </div>

              <!-- Patient Info Card -->
              <v-card
                variant="outlined"
                class="patient-info-card"
                elevation="0"
              >
                <v-card-text class="py-3">
                  <div class="d-flex justify-space-between align-center">
                    <div class="d-flex align-center">
                      <v-icon
                        color="primary"
                        class="mr-2 patient-info-icon"
                        size="20"
                        >mdi-barcode</v-icon
                      >
                      <div>
                        <p class="text-caption patient-info-label mb-0">
                          Barcode Pasien
                        </p>
                        <p
                          class="text-body-2 patient-info-value mb-0 font-weight-medium"
                        >
                          {{
                            lastCheckInResult?.patientId ||
                            scannedData?.split("|")[0] ||
                            "N/A"
                          }}
                        </p>
                      </div>
                    </div>
                    <div class="text-right">
                      <p class="text-caption patient-info-label mb-0">
                        Waktu Scan
                      </p>
                      <p
                        class="text-body-2 patient-info-value mb-0 font-weight-medium"
                      >
                        {{ getCurrentTime() }}
                      </p>
                    </div>
                  </div>
                </v-card-text>
              </v-card>
            </div>
          </v-card-text>

          <v-card-actions class="pa-3 pt-0">
            <v-row dense>
              <v-col v-if="infoAction === 'kembali'" cols="12">
                <v-btn
                  color="grey-darken-1"
                  class="text-white font-weight-semibold text-none dialog-button"
                  size="large"
                  block
                  variant="flat"
                  @click="handleInfoAction"
                  elevation="0"
                  prepend-icon="mdi-arrow-left"
                  rounded="lg"
                >
                  Kembali
                </v-btn>
              </v-col>
              <template v-else>
                <v-col cols="12">
                  <v-btn
                    :color="
                      lastCheckInResult?.success && infoAction === 'checkin'
                        ? 'success'
                        : 'primary'
                    "
                    class="text-white font-weight-semibold text-none dialog-button"
                    size="large"
                    block
                    variant="flat"
                    @click="handleInfoAction"
                    elevation="2"
                    :prepend-icon="
                      lastCheckInResult?.success && infoAction === 'checkin'
                        ? 'mdi-check'
                        : 'mdi-close'
                    "
                    rounded="lg"
                  >
                    Tutup
                  </v-btn>
                </v-col>
              </template>
            </v-row>
          </v-card-actions>
        </v-card>
      </v-dialog>

      <!-- Enhanced Snackbar -->
      <v-snackbar
        v-model="snackbar.show"
        :color="snackbar.color"
        :timeout="snackbar.timeout"
        location="bottom right"
        rounded="pill"
        elevation="24"
        class="custom-snackbar"
      >
        <div class="d-flex align-center">
          <v-avatar :color="snackbar.color" size="32" class="mr-3">
            <v-icon size="20" color="white">{{ snackbar.icon }}</v-icon>
          </v-avatar>
          <div>
            <div class="font-weight-bold">{{ snackbar.title }}</div>
            <div class="text-body-2">{{ snackbar.message }}</div>
          </div>
        </div>
      </v-snackbar>

      <!-- History Dialog -->
      <v-dialog
        v-model="historyDialog"
        max-width="800"
        persistent
        transition="dialog-transition"
        scrim="rgba(0, 0, 0, 0.5)"
        class="blur-dialog"
      >
        <v-card class="rounded-xl dialog-card" elevation="24">
          <div
            class="dialog-header text-center pa-5"
            style="
              background: linear-gradient(135deg, #1565c0 0%, #0d47a1 100%);
            "
          >
            <h2 class="text-h5 font-weight-bold text-white mb-1">
              <v-icon color="white" class="mr-2" size="24">mdi-history</v-icon>
              Riwayat Check-in
            </h2>
            <p class="text-body-2 text-white opacity-90">
              Daftar check-in yang telah dilakukan
            </p>
          </div>

          <v-card-text class="pa-3">
            <!-- Header Stats -->
            <div class="history-header-stats mb-3">
              <div class="history-header-title mb-2">
                <h3
                  class="text-subtitle-1 font-weight-bold d-flex align-center"
                >
                  <v-icon size="20" class="mr-2" color="primary"
                    >mdi-history</v-icon
                  >
                  Riwayat Check-in
                </h3>
              </div>
              <v-row dense>
                <v-col cols="6" md="3">
                  <div class="stat-card-header">
                    <div class="stat-icon-header stat-icon-total">
                      <v-icon size="20">mdi-history</v-icon>
                    </div>
                    <div class="stat-content-header">
                      <div class="stat-value-header">
                        {{ checkInHistory.length }}
                      </div>
                      <div class="stat-label-header">Total</div>
                    </div>
                  </div>
                </v-col>
                <v-col cols="6" md="3">
                  <div class="stat-card-header">
                    <div class="stat-icon-header stat-icon-success">
                      <v-icon size="20">mdi-check-circle</v-icon>
                    </div>
                    <div class="stat-content-header">
                      <div class="stat-value-header">
                        {{
                          checkInHistory.filter(
                            (item) =>
                              item.status === "success" ||
                              item.status === "ALLOWED",
                          ).length
                        }}
                      </div>
                      <div class="stat-label-header">Berhasil</div>
                    </div>
                  </div>
                </v-col>
                <v-col cols="6" md="3">
                  <div class="stat-card-header">
                    <div class="stat-icon-header stat-icon-failed">
                      <v-icon size="20">mdi-close-circle</v-icon>
                    </div>
                    <div class="stat-content-header">
                      <div class="stat-value-header">
                        {{
                          checkInHistory.filter(
                            (item) =>
                              item.status === "failed" ||
                              item.status === "NOT_ALLOWED",
                          ).length
                        }}
                      </div>
                      <div class="stat-label-header">Gagal</div>
                    </div>
                  </div>
                </v-col>
                <v-col cols="6" md="3">
                  <div class="stat-card-header">
                    <div class="stat-icon-header stat-icon-filtered">
                      <v-icon size="20">mdi-filter</v-icon>
                    </div>
                    <div class="stat-content-header">
                      <div class="stat-value-header">
                        {{ filteredHistory.length }}
                      </div>
                      <div class="stat-label-header">Tersaring</div>
                    </div>
                  </div>
                </v-col>
              </v-row>
            </div>

            <!-- Filter dan Search -->
            <div class="mb-3">
              <v-row dense>
                <v-col cols="12" md="6">
                  <v-text-field
                    v-model="historySearch"
                    label="Cari ID Pasien, Nomor Antrean, atau Klinik"
                    prepend-inner-icon="mdi-magnify"
                    variant="outlined"
                    density="comfortable"
                    clearable
                    hide-details
                  ></v-text-field>
                </v-col>
                <v-col cols="12" md="3">
                  <v-select
                    v-model="historyStatusFilter"
                    label="Filter Status"
                    :items="historyStatusOptions"
                    variant="outlined"
                    density="comfortable"
                    hide-details
                    clearable
                  ></v-select>
                </v-col>
                <v-col cols="12" md="3">
                  <v-btn
                    color="error"
                    variant="outlined"
                    block
                    @click="clearHistory"
                    :disabled="checkInHistory.length === 0"
                  >
                    <v-icon start>mdi-delete</v-icon>
                    Hapus Semua
                  </v-btn>
                </v-col>
              </v-row>
            </div>

            <!-- History List -->
            <div v-if="filteredHistory.length > 0">
              <!-- Info jumlah data -->
              <div class="mb-2 text-body-2 text-grey-darken-1">
                Menampilkan {{ (historyPage - 1) * historyItemsPerPage + 1 }} -
                {{
                  Math.min(
                    historyPage * historyItemsPerPage,
                    filteredHistory.length,
                  )
                }}
                dari {{ filteredHistory.length }} riwayat
              </div>

              <div class="history-list">
                <v-card
                  v-for="(item, index) in paginatedHistory"
                  :key="index"
                  variant="flat"
                  elevation="0"
                  class="mb-1 history-item-dialog"
                  :class="getStatusClass(item.status)"
                >
                  <v-card-text class="pa-2">
                    <div class="d-flex justify-space-between align-start">
                      <div class="flex-grow-1">
                        <!-- Header: Status & Method -->
                        <div class="d-flex align-center mb-1 gap-1">
                          <div
                            class="history-status-badge-dialog"
                            :class="`status-${getStatusColor(item.status)}`"
                          >
                            <v-icon size="14">{{
                              getStatusIcon(item.status)
                            }}</v-icon>
                          </div>
                          <div>
                            <div
                              class="history-status-text-dialog"
                              :class="`text-${getStatusColor(item.status)}`"
                            >
                              {{ getStatusText(item.status) }}
                            </div>
                            <div class="history-method-text-dialog">
                              {{ item.method }}
                            </div>
                          </div>
                        </div>

                        <!-- Queue Number -->
                        <div
                          v-if="item.klinikQueueNumber || item.queueNumber"
                          class="mb-1"
                        >
                          <div class="history-queue-badge-dialog">
                            <v-icon size="12" class="mr-1">mdi-ticket</v-icon>
                            <span class="font-weight-semibold">{{
                              item.klinikQueueNumber || item.queueNumber
                            }}</span>
                          </div>
                        </div>

                        <!-- Info Badges: Patient ID, Klinik & Pembayaran -->
                        <div class="d-flex flex-wrap gap-1 mb-1">
                          <div
                            v-if="item.patientId"
                            class="history-info-badge-dialog"
                          >
                            <v-icon size="12" class="mr-1"
                              >mdi-account-circle</v-icon
                            >
                            <span>{{ item.patientId }}</span>
                          </div>
                          <div
                            v-if="item.klinik && item.klinik !== 'N/A'"
                            class="history-klinik-badge-dialog"
                          >
                            <v-icon size="12" class="mr-1"
                              >mdi-hospital-building</v-icon
                            >
                            <span>{{ item.klinik }}</span>
                          </div>
                          <div
                            v-if="item.pembayaran"
                            class="history-payment-badge-dialog"
                          >
                            <v-icon size="12" class="mr-1"
                              >mdi-credit-card</v-icon
                            >
                            <span>{{ item.pembayaran }}</span>
                          </div>
                        </div>

                        <!-- Time Info -->
                        <div class="d-flex flex-wrap gap-1">
                          <div class="history-time-badge-dialog">
                            <v-icon size="10" class="mr-1"
                              >mdi-clock-outline</v-icon
                            >
                            <span>{{ formatDateTime(item.checkInTime) }}</span>
                          </div>
                          <div
                            v-if="item.checkInDate"
                            class="history-time-badge-dialog"
                          >
                            <v-icon size="10" class="mr-1">mdi-calendar</v-icon>
                            <span>{{ formatDate(item.checkInDate) }}</span>
                          </div>
                        </div>
                      </div>

                      <div class="ml-2">
                        <v-btn
                          icon
                          size="small"
                          variant="text"
                          color="error"
                          @click="deleteHistoryItem(index)"
                          class="history-delete-btn"
                        >
                          <v-icon size="18">mdi-delete-outline</v-icon>
                        </v-btn>
                      </div>
                    </div>
                  </v-card-text>
                </v-card>
              </div>

              <!-- Pagination -->
              <div
                v-if="totalHistoryPages > 1"
                class="mt-3 d-flex justify-center"
              >
                <v-pagination
                  v-model="historyPage"
                  :length="totalHistoryPages"
                  :total-visible="7"
                  color="primary"
                  rounded="circle"
                ></v-pagination>
              </div>
            </div>

            <!-- Empty State -->
            <div v-else class="text-center py-6">
              <v-icon size="48" color="grey-lighten-1" class="mb-2"
                >mdi-history</v-icon
              >
              <p class="text-h6 text-grey mb-1">Belum ada riwayat check-in</p>
              <p class="text-body-2 text-grey">
                Riwayat check-in akan muncul di sini setelah Anda melakukan
                check-in
              </p>
            </div>
          </v-card-text>

          <v-card-actions class="pa-3 pt-0">
            <v-spacer></v-spacer>
            <v-btn
              color="primary"
              class="text-white font-weight-semibold text-none"
              size="large"
              variant="flat"
              @click="historyDialog = false"
              prepend-icon="mdi-close"
              rounded="lg"
              elevation="2"
            >
              Tutup
            </v-btn>
          </v-card-actions>
        </v-card>
      </v-dialog>

      <!-- QR History Dialog -->
      <v-dialog
        v-model="qrHistoryDialog"
        max-width="800"
        persistent
        transition="dialog-transition"
        scrim="rgba(0, 0, 0, 0.5)"
        class="blur-dialog"
      >
        <v-card class="rounded-xl dialog-card" elevation="24">
          <div
            class="dialog-header text-center pa-5"
            style="
              background: linear-gradient(135deg, #fb8c00 0%, #e65100 100%);
            "
          >
            <h2 class="text-h5 font-weight-bold text-white mb-1">
              <v-icon color="white" class="mr-2" size="24"
                >mdi-qrcode-scan</v-icon
              >
              Riwayat QR Scan
            </h2>
            <p class="text-body-2 text-white opacity-90">
              Daftar QR code yang telah di-scan
            </p>
          </div>

          <v-card-text class="pa-3">
            <!-- Header Stats -->
            <div class="history-header-stats mb-3">
              <div class="history-header-title mb-2">
                <h3
                  class="text-subtitle-1 font-weight-bold d-flex align-center"
                >
                  <v-icon size="20" class="mr-2" color="secondary"
                    >mdi-qrcode-scan</v-icon
                  >
                  Riwayat QR Scan
                </h3>
              </div>
              <v-row dense>
                <v-col cols="6" md="4">
                  <div class="stat-card-header">
                    <div class="stat-icon-header stat-icon-total">
                      <v-icon size="20">mdi-qrcode-scan</v-icon>
                    </div>
                    <div class="stat-content-header">
                      <div class="stat-value-header">
                        {{ scannedQRHistory.length }}
                      </div>
                      <div class="stat-label-header">Total Scan</div>
                    </div>
                  </div>
                </v-col>
                <v-col cols="6" md="4">
                  <div class="stat-card-header">
                    <div class="stat-icon-header stat-icon-filtered">
                      <v-icon size="20">mdi-filter</v-icon>
                    </div>
                    <div class="stat-content-header">
                      <div class="stat-value-header">
                        {{ filteredQRHistory.length }}
                      </div>
                      <div class="stat-label-header">Tersaring</div>
                    </div>
                  </div>
                </v-col>
                <v-col cols="12" md="4">
                  <v-btn
                    color="error"
                    variant="outlined"
                    block
                    @click="clearQRHistory"
                    :disabled="scannedQRHistory.length === 0"
                    class="mt-2 mt-md-0"
                  >
                    <v-icon start>mdi-delete</v-icon>
                    Hapus Semua
                  </v-btn>
                </v-col>
              </v-row>
            </div>

            <!-- Filter dan Search -->
            <div class="mb-3">
              <v-row dense>
                <v-col cols="12">
                  <v-text-field
                    v-model="historySearch"
                    label="Cari Data QR Code"
                    prepend-inner-icon="mdi-magnify"
                    variant="outlined"
                    density="comfortable"
                    clearable
                    hide-details
                  ></v-text-field>
                </v-col>
              </v-row>
            </div>

            <!-- QR History List -->
            <div v-if="filteredQRHistory.length > 0" class="history-list">
              <v-card
                v-for="(item, index) in filteredQRHistory"
                :key="index"
                variant="flat"
                elevation="0"
                class="mb-2 history-item-dialog history-item-qr"
              >
                <v-card-text class="pa-2">
                  <div class="d-flex justify-space-between align-start">
                    <div class="flex-grow-1">
                      <!-- QR Data -->
                      <div class="mb-1">
                        <div class="history-qr-badge-dialog">
                          <v-icon size="14" class="mr-1">mdi-qrcode</v-icon>
                          <span class="font-weight-semibold">{{
                            item.data
                          }}</span>
                        </div>
                      </div>

                      <!-- Time Info -->
                      <div class="d-flex flex-wrap gap-1">
                        <div class="history-time-badge-dialog">
                          <v-icon size="10" class="mr-1"
                            >mdi-clock-outline</v-icon
                          >
                          <span>{{ item.time }}</span>
                        </div>
                        <div class="history-time-badge-dialog">
                          <v-icon size="10" class="mr-1">mdi-calendar</v-icon>
                          <span>{{ item.date }}</span>
                        </div>
                      </div>
                    </div>

                    <div class="ml-2 d-flex gap-1">
                      <v-btn
                        icon
                        size="small"
                        variant="text"
                        color="primary"
                        @click="useQRData(item.data)"
                        class="history-action-btn"
                      >
                        <v-icon size="18">mdi-refresh</v-icon>
                      </v-btn>
                      <v-btn
                        icon
                        size="small"
                        variant="text"
                        color="error"
                        @click="deleteQRHistoryItem(index)"
                        class="history-delete-btn"
                      >
                        <v-icon size="18">mdi-delete-outline</v-icon>
                      </v-btn>
                    </div>
                  </div>
                </v-card-text>
              </v-card>
            </div>

            <!-- Empty State -->
            <div v-else class="text-center py-6">
              <v-icon size="48" color="grey-lighten-1" class="mb-2"
                >mdi-qrcode-scan</v-icon
              >
              <p class="text-h6 text-grey mb-1">Belum ada riwayat QR scan</p>
              <p class="text-body-2 text-grey">
                Riwayat QR scan akan muncul di sini setelah Anda melakukan scan
              </p>
            </div>
          </v-card-text>

          <v-card-actions class="pa-3 pt-0">
            <v-spacer></v-spacer>
            <v-btn
              color="primary"
              class="text-white font-weight-semibold text-none"
              size="large"
              variant="flat"
              @click="qrHistoryDialog = false"
              prepend-icon="mdi-close"
              rounded="lg"
              elevation="2"
            >
              Tutup
            </v-btn>
          </v-card-actions>
        </v-card>
      </v-dialog>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, nextTick, onMounted, onUnmounted, watch } from "vue";
import { useQueueStore } from "@/stores/queueStore";
import { useMasterStore } from "@/stores/masterStore";
import { useWebSocket } from "@/composables/useWebSocket";
import { useThermalPrint } from "@/composables/useThermalPrint";
import PageHeader from "@/components/common/PageHeader.vue";

definePageMeta({
  // middleware:['auth'],
  layout: false,
});

const queueStore = useQueueStore();
const masterStore = useMasterStore();
const { printTicketFromPatient, isPrinting } = useThermalPrint();
const config = useRuntimeConfig();
const wsBaseUrl =
  config.public?.wsBaseUrl || "ws://10.10.123.135:8084/api/v1/ws";

// TypeScript declaration for QRCode
declare global {
  interface Window {
    QRCode: any;
  }
}

// --- DESAIN & TEMA ---
const primaryColor = ref("#1565C0");
const secondaryColor = ref("#FB8C00");

// --- LOGIKA ---
const tab = ref("checkin");
const showGenerateQRDialog = ref(false);
const infoDialog = ref(false);
const infoMessage = ref("");
const infoAction = ref<"checkin" | "kembali">("kembali");
let autoCloseTimer: ReturnType<typeof setTimeout> | null = null;
const scannedData = ref<string | null>(null);
const manualInput = ref("");
const manualForm = ref(null);
const lastCheckInResult = ref<{
  success: boolean;
  patientId: string;
  status: string;
} | null>(null);

// QR Scanner state
const isScanning = ref(false);
const hasCamera = ref(false);
const cameraChecking = ref(true);
const cameraReady = ref(false);
const isProcessingScan = ref(false); // Flag untuk mencegah scan ganda saat sedang proses
let html5QrCode: any = null;
const qrCodeId = "qr-reader";
let lastScannedQR: string | null = null;
let lastScanTime: number = 0;
const SCAN_DEBOUNCE_MS = 2000; // 2 detik debounce untuk mencegah scan berulang
const currentFacingMode = ref<"user" | "environment">("environment");
const isFrontCamera = computed(() => currentFacingMode.value === "user");
const fileInput = ref<HTMLInputElement | null>(null);
const isProcessingFile = ref(false);

// Daftar QR code yang sudah berhasil di-scan (untuk mencegah double antrian)
const SUCCESSFUL_SCANS_KEY = "successful_qr_scans";
const successfulScans = ref<Set<string>>(new Set());

// Detect mobile device
const isMobile = ref(false);
if (typeof window !== "undefined") {
  isMobile.value =
    /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
      navigator.userAgent,
    ) || window.innerWidth <= 768;
}

// History Dialog
const historyDialog = ref(false);
const historySearch = ref("");
const historyStatusFilter = ref("");
const historyPage = ref(1);
const historyItemsPerPage = ref(10);
const checkInHistory = ref<
  Array<{
    patientId: string;
    queueNumber?: string;
    klinikQueueNumber?: string;
    pembayaran?: string;
    status: string;
    checkInTime: string;
    checkInDate: string;
    method: string;
    klinik?: string;
    kodeKlinik?: string;
  }>
>([]);

// QR History Dialog
const qrHistoryDialog = ref(false);
const scannedQRHistory = ref<
  Array<{
    data: string;
    timestamp: string;
    date: string;
    time: string;
  }>
>([]);

const historyStatusOptions = [
  { title: "Berhasil", value: "success" },
  { title: "Gagal", value: "failed" },
  { title: "Pending", value: "pending" },
];

// Generate QR variables
const generateBarcode = ref("");
const generateQueueNumber = ref("");
const generateStatus = ref("ALLOWED");
const generatedQRData = ref("");
const selectedKlinik = ref("");
const selectedPembayaran = ref("UMUM");
const generatedPatient = ref<any>(null);
const statusOptions = [
  { title: "Diizinkan Check-in", value: "ALLOWED" },
  { title: "Belum Diizinkan", value: "NOT_ALLOWED" },
];

// WebSocket stabilization - version 1.1
// Generate a unique session suffix (random ID)
const uniqueSessionSuffix = ref(process.client ? Math.random().toString(36).substring(2, 8) : '')

const checkInClientId = computed(() => {
  return `checkin-${uniqueSessionSuffix.value}`
})

const fetchAllData = async () => {
  console.log('🔄 CheckIn refresh: Syncing data...');
  try {
    await queueStore.fetchAllPatients();
    queueStore.ensureInitialData();
    checkAndResetDaily();
    console.log('✅ CheckIn refresh: Success');
  } catch (err) {
    console.error('❌ CheckIn refresh error:', err);
  }
};

const isConnected = computed(() => queueStore.isWsConnected);

// Watch for clientId changes and reconnect if needed
watch(checkInClientId, (newClientId, oldClientId) => {
  if (newClientId && newClientId !== oldClientId) {
    console.log('🔄 Client ID changed, reconnecting centralized WebSocket...')
    queueStore.initWebSocket(newClientId)
  }
})

// Get klinik list for dropdown
const klinikOptions = computed(() => {
  const klinikList = masterStore.klinikList.map(
    (k: { kode: string; nama: string }) => ({
      title: `${k.kode} - ${k.nama}`,
      value: k.kode,
    }),
  );

  // Tambahkan opsi "UM" (Umum) di awal list
  return [{ title: "UM - Umum", value: "UM" }, ...klinikList];
});

// Sequential Patient ID Management
const PATIENT_ID_STORAGE_KEY = "checkin_patient_id_counter";
const QUEUE_NUMBER_STORAGE_KEY = "checkin_queue_number_counters";
const LAST_RESET_TIME_KEY = "checkin_last_reset_time";
const RESET_HOUR = 2; // Jam 2 pagi
const HISTORY_STORAGE_KEY = "checkin_history";

// Check and reset daily at 2 AM (02:00)
const checkAndResetDaily = () => {
  if (typeof window === "undefined") return;

  const now = new Date();
  const currentHour = now.getHours();
  const currentDate = now.toISOString().split("T")[0]; // YYYY-MM-DD

  // Get last reset time
  const lastResetTime = localStorage.getItem(LAST_RESET_TIME_KEY);
  let lastResetDate = null;

  if (lastResetTime) {
    const lastReset = new Date(lastResetTime);
    lastResetDate = lastReset.toISOString().split("T")[0];
  }

  // Check if it's 10 PM or later and hasn't been reset today
  // Reset happens at 22:00 (10 PM) or later, but only once per day
  const shouldReset =
    currentHour >= RESET_HOUR && lastResetDate !== currentDate;

  if (shouldReset) {
    // Reset counters to 0 (so next will be 0001)
    localStorage.setItem(PATIENT_ID_STORAGE_KEY, "0");
    localStorage.setItem(QUEUE_NUMBER_STORAGE_KEY, "{}");

    // Clear check-in history (reset riwayat check-in)
    checkInHistory.value = [];
    if (typeof window !== "undefined") {
      localStorage.removeItem(HISTORY_STORAGE_KEY);
    }

    // Save reset time
    localStorage.setItem(LAST_RESET_TIME_KEY, now.toISOString());

    console.log(
      "✅ Daily reset executed at",
      now.toLocaleString("id-ID"),
      "- Counters and history reset",
    );
  }
};

// Generate sequential patient ID (P-00001, P-00002, etc.)
const generateSequentialPatientId = (): string => {
  if (typeof window === "undefined") return "P-00001";

  // Check and reset if needed (before generating)
  checkAndResetDaily();

  let counter = parseInt(
    localStorage.getItem(PATIENT_ID_STORAGE_KEY) || "0",
    10,
  );
  counter += 1;
  localStorage.setItem(PATIENT_ID_STORAGE_KEY, counter.toString());

  return `P-${String(counter).padStart(5, "0")}`;
};

// Generate sequential queue number based on klinik code (AN-0001, AS-0001, etc.)
const generateSequentialQueueNumber = (kodeKlinik: string): string => {
  if (typeof window === "undefined") return `${kodeKlinik}-0001`;

  // Check and reset if needed (before generating)
  checkAndResetDaily();

  const counters = JSON.parse(
    localStorage.getItem(QUEUE_NUMBER_STORAGE_KEY) || "{}",
  );
  let counter = parseInt(counters[kodeKlinik] || "0", 10);
  counter += 1;
  counters[kodeKlinik] = counter;
  localStorage.setItem(QUEUE_NUMBER_STORAGE_KEY, JSON.stringify(counters));

  return `${kodeKlinik}-${String(counter).padStart(4, "0")}`;
};

const snackbar = ref({
  show: false,
  title: "",
  message: "",
  color: "",
  icon: "",
  timeout: 4000,
});

// Check camera availability
const checkCameraAvailability = async () => {
  cameraChecking.value = true;
  hasCamera.value = false;

  // Check if browser supports mediaDevices
  if (typeof navigator === "undefined" || !navigator.mediaDevices) {
    console.error("navigator.mediaDevices is not supported");
    showSnackbar(
      "Error",
      "Browser tidak mendukung akses kamera. Pastikan menggunakan HTTPS atau localhost.",
      "error",
      "mdi-camera-off",
    );
    cameraChecking.value = false;
    return;
  }

  try {
    // First, request permission by trying to get user media
    // This is required for enumerateDevices to return device labels
    const stream = await navigator.mediaDevices.getUserMedia({ video: true });

    // Stop the stream immediately after getting permission
    stream.getTracks().forEach((track) => track.stop());

    // Now enumerate devices (will have labels after permission granted)
    const devices = await navigator.mediaDevices.enumerateDevices();
    const videoDevices = devices.filter(
      (device) => device.kind === "videoinput",
    );

    hasCamera.value = videoDevices.length > 0;

    if (hasCamera.value) {
      console.log(
        `Found ${videoDevices.length} camera(s):`,
        videoDevices.map((d) => d.label || d.deviceId),
      );
    } else {
      console.warn("No video input devices found");
      showSnackbar(
        "Warning",
        "Tidak ada kamera yang terdeteksi",
        "warning",
        "mdi-camera-off",
      );
    }
  } catch (err: any) {
    console.error("Error checking camera:", err);
    hasCamera.value = false;

    let errorMessage = "Gagal mengakses kamera. ";
    if (
      err.name === "NotAllowedError" ||
      err.name === "PermissionDeniedError"
    ) {
      errorMessage +=
        "Izin kamera ditolak. Mohon izinkan akses kamera di pengaturan browser.";
    } else if (
      err.name === "NotFoundError" ||
      err.name === "DevicesNotFoundError"
    ) {
      errorMessage += "Tidak ada kamera yang ditemukan.";
    } else if (
      err.name === "NotReadableError" ||
      err.name === "TrackStartError"
    ) {
      errorMessage += "Kamera sedang digunakan aplikasi lain.";
    } else if (
      err.name === "OverconstrainedError" ||
      err.name === "ConstraintNotSatisfiedError"
    ) {
      errorMessage += "Kamera tidak memenuhi persyaratan.";
    } else {
      errorMessage += `Error: ${err.message || err.name}`;
    }

    showSnackbar("Error", errorMessage, "error", "mdi-camera-off");
  } finally {
    cameraChecking.value = false;
  }
};

// Test camera function for debugging
const testCamera = async () => {
  try {
    showSnackbar("Info", "Menguji akses kamera...", "info", "mdi-camera");

    if (typeof navigator === "undefined") {
      showSnackbar(
        "Error",
        "navigator is undefined - pastikan di browser, bukan SSR",
        "error",
        "mdi-alert",
      );
      return;
    }

    if (!navigator.mediaDevices) {
      showSnackbar(
        "Error",
        "navigator.mediaDevices is undefined - pastikan menggunakan HTTPS atau localhost",
        "error",
        "mdi-alert",
      );
      return;
    }

    if (!navigator.mediaDevices.getUserMedia) {
      showSnackbar(
        "Error",
        "getUserMedia is not supported",
        "error",
        "mdi-alert",
      );
      return;
    }

    const stream = await navigator.mediaDevices.getUserMedia({
      video: {
        facingMode: "user",
        width: { ideal: 1920, min: 1280 },
        height: { ideal: 1080, min: 720 },
      },
    });

    showSnackbar(
      "Success",
      "Kamera berhasil diakses!",
      "success",
      "mdi-check-circle",
    );

    // Stop stream after 2 seconds
    setTimeout(() => {
      stream.getTracks().forEach((track) => track.stop());
    }, 2000);
  } catch (err: any) {
    console.error("Test camera error:", err);
    let errorMsg = `Error: ${err.name || "Unknown"}`;
    if (err.message) errorMsg += ` - ${err.message}`;
    showSnackbar("Error", errorMsg, "error", "mdi-alert");
  }
};

// QR Scanner Functions
const startScanning = async () => {
  // Check camera first
  if (!hasCamera.value) {
    await checkCameraAvailability();
    if (!hasCamera.value) {
      showSnackbar(
        "Error",
        "Kamera tidak tersedia. Silakan gunakan input manual atau pastikan kamera terhubung.",
        "error",
        "mdi-camera-off",
      );
      return;
    }
  }

  try {
    // Set scanning state first to render the element
    isScanning.value = true;

    // Wait for DOM to update and element to be rendered
    await nextTick();

    // Wait a bit more to ensure element is fully rendered
    await new Promise((resolve) => setTimeout(resolve, 200));

    // Check if element exists
    const qrElement = document.getElementById(qrCodeId);
    if (!qrElement) {
      console.error(`Element with id "${qrCodeId}" not found in DOM`);
      isScanning.value = false;
      showSnackbar(
        "Error",
        "Element scanner tidak ditemukan. Silakan refresh halaman.",
        "error",
        "mdi-alert",
      );
      return;
    }

    // Cleanup existing instance if any (untuk handle refresh)
    if (html5QrCode) {
      try {
        // Try to check if scanner is active and stop it
        try {
          if (html5QrCode.getState && html5QrCode.getState() === 2) {
            // Scanning state
            await html5QrCode.stop();
            await html5QrCode.clear();
          }
        } catch {
          // If getState doesn't exist or fails, just try to stop
          await html5QrCode.stop().catch(() => {});
          await html5QrCode.clear().catch(() => {});
        }
        html5QrCode = null;
      } catch (err) {
        console.warn("Error cleaning up existing QR scanner:", err);
        html5QrCode = null;
      }
    }

    // Dynamic import html5-qrcode
    if (!html5QrCode) {
      const { Html5Qrcode: Html5QrcodeClass } = await import("html5-qrcode");
      html5QrCode = new Html5QrcodeClass(qrCodeId);
      console.log("Html5Qrcode initialized");
    }

    if (html5QrCode) {
      cameraReady.value = false;

      // Konfigurasi kamera dinamis
      const cameraConfig = { facingMode: currentFacingMode.value };

      // Video constraints yang dioptimalkan
      const baseVideoConstraints = {
        facingMode: currentFacingMode.value,
        width: { ideal: 1920, min: 1280 },
        height: { ideal: 1080, min: 720 },
      };

      // Tambahkan advanced constraints hanya jika didukung
      const videoConstraints: any = { ...baseVideoConstraints };

      console.log("Starting QR scanner with config:", {
        isMobile: isMobile.value,
        cameraConfig,
        videoConstraints,
      });

      try {
        await html5QrCode.start(
          cameraConfig,
          {
            fps: 20, // Increased for better responsiveness
            qrbox: (viewfinderWidth: number, viewfinderHeight: number) => {
              const minEdgeSize = Math.min(viewfinderWidth, viewfinderHeight);
              // Set to 72% for optimal balance between target size and quiet zone
              const qrboxSize = Math.floor(minEdgeSize * 0.72);
              return {
                width: Math.max(qrboxSize, 250),
                height: Math.max(qrboxSize, 250),
              };
            },
            aspectRatio: 1.0,
            disableFlip: false,
            videoConstraints: videoConstraints,
            rememberLastUsedCamera: true,
            showTorchButtonIfSupported: true,
            useBarCodeDetectorIfSupported: true, // Native scanning if available
            verbose: false, // Set true for debugging
          },
          (decodedText: string, decodedResult: any) => {
            // QR Code berhasil di-scan
            console.log("✅ QR Code detected:", decodedText);
            console.log("📊 Decoded result:", decodedResult);

            // Validasi dan proses QR code
            if (decodedText && decodedText.trim() !== "") {
              handleQRScanSuccess(decodedText);
            } else {
              console.warn("Empty QR code detected");
            }
          },
          (errorMessage: string) => {
            // Log error untuk debugging - hanya log error penting
            // Error ini biasanya muncul terus menerus saat tidak ada QR code yang terdeteksi
            // Jadi kita filter untuk menghindari spam console
            if (errorMessage) {
              // Filter out common non-critical errors
              const isCriticalError =
                !errorMessage.includes("NotFoundException") &&
                !errorMessage.includes("No QR") &&
                !errorMessage.includes("QR code parse error") &&
                !errorMessage.includes("QR code parse error, error") &&
                !errorMessage.includes("QR code decode error");

              if (isCriticalError) {
                console.warn("QR Scanner warning:", errorMessage);
              }
            }
          },
        );

        // Set camera ready setelah sedikit delay untuk memastikan video sudah dimuat
        setTimeout(() => {
          cameraReady.value = true;
          console.log("Camera ready, scanner is active");
        }, 500);

        showSnackbar(
          "Info",
          "Scanner aktif. Arahkan kamera ke QR code dan pastikan pencahayaan cukup",
          "info",
          "mdi-camera",
        );
      } catch (cameraError: any) {
        console.error("Camera error:", cameraError);

        // Jika kamera belakang tidak tersedia di mobile, coba kamera depan
        if (isMobile.value && cameraError.name === "NotFoundError") {
          try {
            console.log("Trying front camera as fallback...");
            await html5QrCode.start(
              { facingMode: "user" },
              {
                fps: 20,
                qrbox: (viewfinderWidth: number, viewfinderHeight: number) => {
                  const minEdgeSize = Math.min(viewfinderWidth, viewfinderHeight);
                  // Optimized 72%
                  const qrboxSize = Math.floor(minEdgeSize * 0.72);
                  return {
                    width: Math.max(qrboxSize, 250),
                    height: Math.max(qrboxSize, 250),
                  };
                },
                aspectRatio: 1.0,
                disableFlip: false,
                videoConstraints: {
                  facingMode: "user",
                  width: { ideal: 1280, min: 640, max: 1920 },
                  height: { ideal: 720, min: 480, max: 1080 },
                },
                rememberLastUsedCamera: true,
                useBarCodeDetectorIfSupported: true,
                verbose: false,
              },
              (decodedText: string, decodedResult: any) => {
                console.log("✅ QR Code detected (front camera):", decodedText);
                if (decodedText && decodedText.trim() !== "") {
                  handleQRScanSuccess(decodedText);
                }
              },
              (errorMessage: string) => {
                if (errorMessage) {
                  const isCriticalError =
                    !errorMessage.includes("NotFoundException") &&
                    !errorMessage.includes("No QR") &&
                    !errorMessage.includes("QR code parse error") &&
                    !errorMessage.includes("QR code decode error");

                  if (isCriticalError) {
                    console.warn("QR Scanner (front) warning:", errorMessage);
                  }
                }
              },
            );

            setTimeout(() => {
              cameraReady.value = true;
            }, 500);

            showSnackbar(
              "Info",
              "Menggunakan kamera depan. Arahkan QR code ke kamera",
              "info",
              "mdi-camera",
            );
          } catch (fallbackError: any) {
            console.error("Fallback camera also failed:", fallbackError);
            throw cameraError; // Throw original error
          }
        } else {
          // Coba menggunakan deviceId langsung jika facingMode gagal
          try {
            console.log("Trying to get camera devices...");
            const devices = await navigator.mediaDevices.enumerateDevices();
            const videoDevices = devices.filter(
              (device) => device.kind === "videoinput",
            );

            if (videoDevices.length > 0) {
              // Gunakan kamera pertama yang tersedia
              const deviceId = videoDevices[0].deviceId;
              console.log("Using device:", deviceId, videoDevices[0].label);

              await html5QrCode.start(
                { deviceId: { exact: deviceId } },
                {
                  fps: 20,
                  qrbox: (viewfinderWidth: number, viewfinderHeight: number) => {
                    const minEdgeSize = Math.min(viewfinderWidth, viewfinderHeight);
                    // Optimized 72%
                    const qrboxSize = Math.floor(minEdgeSize * 0.85);
                    return {
                      width: Math.max(qrboxSize, 250),
                      height: Math.max(qrboxSize, 250),
                    };
                  },
                  aspectRatio: 1.0,
                  disableFlip: false,
                  videoConstraints: {
                    deviceId: { exact: deviceId },
                    width: { ideal: isMobile.value ? 1280 : 1920 },
                    height: { ideal: isMobile.value ? 720 : 1080 },
                  },
                  rememberLastUsedCamera: true,
                  useBarCodeDetectorIfSupported: true,
                  verbose: false,
                },
                (decodedText: string, decodedResult: any) => {
                  console.log("✅ QR Code detected (deviceId):", decodedText);
                  if (decodedText && decodedText.trim() !== "") {
                    handleQRScanSuccess(decodedText);
                  }
                },
                (errorMessage: string) => {
                  if (errorMessage) {
                    const isCriticalError =
                      !errorMessage.includes("NotFoundException") &&
                      !errorMessage.includes("No QR") &&
                      !errorMessage.includes("QR code parse error") &&
                      !errorMessage.includes("QR code decode error");

                    if (isCriticalError) {
                      console.warn(
                        "QR Scanner (deviceId) warning:",
                        errorMessage,
                      );
                    }
                  }
                },
              );

              setTimeout(() => {
                cameraReady.value = true;
              }, 500);

              showSnackbar(
                "Info",
                "Scanner aktif menggunakan kamera yang tersedia",
                "info",
                "mdi-camera",
              );
            } else {
              throw cameraError;
            }
          } catch (deviceError: any) {
            console.error("DeviceId approach also failed:", deviceError);
            throw cameraError;
          }
        }
      }
    }
  } catch (err: any) {
    console.error("Error starting scanner:", err);
    isScanning.value = false;
    cameraReady.value = false;

    // Don't set hasCamera to false if it was detected, just log the error
    let errorMessage = "Gagal memulai scanner. ";

    if (err.message && err.message.includes("not found")) {
      errorMessage =
        "Element scanner tidak ditemukan. Silakan refresh halaman dan coba lagi.";
      console.error("Element not found error. Element ID:", qrCodeId);
    } else if (err.name === "NotAllowedError") {
      errorMessage =
        "Akses kamera ditolak. Mohon izinkan akses kamera di pengaturan browser.";
    } else if (err.name === "NotFoundError") {
      errorMessage = "Kamera tidak ditemukan. Silakan gunakan input manual.";
      hasCamera.value = false;
    } else if (err.name === "NotReadableError") {
      errorMessage =
        "Kamera sedang digunakan aplikasi lain. Tutup aplikasi lain yang menggunakan kamera.";
    } else {
      errorMessage += err.message || err.name || "Unknown error";
    }

    showSnackbar("Error", errorMessage, "error", "mdi-alert");
  }
};

const stopScanning = async () => {
  try {
    if (html5QrCode) {
      // Immediate state update
      const scanner = html5QrCode;
      html5QrCode = null;
      isScanning.value = false;
      cameraReady.value = false;

      // Stop and clear
      try {
        if (scanner.getState && scanner.getState() > 1) { // 1 is stopped, 2 is scanning, 3 is paused
          await scanner.stop();
        }
        await scanner.clear();
      } catch (err) {
        console.warn("Scanner shutdown error (non-critical):", err);
      }
      
      showSnackbar("Info", "Scanner dihentikan", "info", "mdi-camera-off");
    }
  } catch (err: any) {
    console.error("Error in stopScanning:", err);
    isScanning.value = false;
    cameraReady.value = false;
    html5QrCode = null;
  }
};

const handleQRScanSuccess = (decodedText: string) => {
  console.log("🎯 QR Scan Success! Data:", decodedText);

  // Guard: Jika sedang proses atau dialog sedang terbuka, abaikan scan
  if (isProcessingScan.value || infoDialog.value) {
    console.log("⏭️ Scan diabaikan: Sedang memproses atau dialog terbuka");
    return;
  }

  // Validasi data QR
  if (!decodedText || decodedText.trim() === "") {
    console.warn("QR Code data is empty");
    showSnackbar(
      "Error",
      "QR Code tidak valid atau kosong",
      "error",
      "mdi-alert",
    );
    return;
  }

  // Tandai sedang proses
  isProcessingScan.value = true;

  // CATATAN: Scanner tetap berjalan (tidak di-stop) atas permintaan user,
  // namun guard di atas (isProcessingScan || infoDialog) akan mencegah
  // deteksi ganda selama proses berlangsung atau dialog terbuka.
  console.log("📸 Scanner remains active, guards will handle over-detection");

  // Cek apakah QR code sudah pernah berhasil di-scan (mencegah double antrian)
  // Hanya abaikan jika benar-benar sudah berhasil check-in sebelumnya (status di-loket)
  if (isQRCodeAlreadyScanned(decodedText)) {
    // Verifikasi ulang: cek apakah pasien benar-benar sudah check-in di queueStore
    const cleanInput = String(decodedText).trim();
    const patientInStore = (queueStore.allPatients as any[]).find((p) => {
      const patientBarcode = String(p.barcode || "").trim();
      return (
        patientBarcode === cleanInput ||
        patientBarcode.toUpperCase() === cleanInput.toUpperCase()
      );
    });

    if (patientInStore && patientInStore.status === "di-loket") {
      // Pasien benar-benar sudah check-in, abaikan scan
      console.log(
        "⏭️ Scan diabaikan: QR code sudah pernah berhasil di-scan dan pasien sudah di-loket",
      );
      showSnackbar(
        "Peringatan",
        "QR Code ini sudah pernah berhasil di-scan. Tidak dapat digunakan lagi untuk mencegah double antrian.",
        "warning",
        "mdi-alert-circle",
      );
      // Reset processing flag jika dihentikan di sini
      isProcessingScan.value = false;
      return;
    } else {
      // Pasien belum benar-benar check-in, mungkin ada masalah di data sebelumnya
      // Biarkan scan berlanjut untuk verifikasi ulang
      console.warn(
        "⚠️ QR code marked as scanned but patient not in di-loket status, allowing re-scan for verification",
      );
      // Hapus dari successful scans untuk memungkinkan scan ulang
      if (
        typeof window !== "undefined" &&
        successfulScans.value.has(decodedText)
      ) {
        successfulScans.value.delete(decodedText);
        const scansArray = Array.from(successfulScans.value);
        localStorage.setItem(SUCCESSFUL_SCANS_KEY, JSON.stringify(scansArray));
      }
    }
  }

  // Debounce: cegah scan berulang dalam waktu singkat (fallback jika stopScanning gagal cepat)
  const now = Date.now();
  if (lastScannedQR === decodedText && now - lastScanTime < SCAN_DEBOUNCE_MS) {
    console.log(
      "⏭️ Scan diabaikan (debounce): QR code sama dalam waktu singkat",
    );
    isProcessingScan.value = false;
    return;
  }

  // Update last scan info
  lastScannedQR = decodedText;
  lastScanTime = now;

  // Simpan data QR yang di-scan
  scannedData.value = decodedText;

  // Scanner tetap berjalan untuk memungkinkan scan QR code berikutnya

  // Proses data QR
  try {
    // onDetect is async, so we need to handle it properly
    onDetect(decodedText).catch((error) => {
      console.error("Error processing QR data in onDetect:", error);
      // Reset processing flag jika terjadi error di onDetect
      isProcessingScan.value = false;

      // Hanya tampilkan error message
      showSnackbar(
        "Error",
        `Gagal memproses data QR Code: ${error.message || "Error tidak diketahui"}`,
        "error",
        "mdi-alert",
      );

      // Simpan ke history sebagai failed
      saveToHistory({
        patientId: decodedText,
        queueNumber: null as any,
        klinikQueueNumber: null as any,
        pembayaran: "N/A",
        status: "failed",
        checkInTime: new Date().toISOString(),
        checkInDate: new Date().toISOString(),
        method: "QR Scan",
        klinik: "N/A",
        kodeKlinik: null as any,
      });
    });
  } catch (error) {
    console.error("Error processing QR data:", error);
    // Reset processing flag jika terjadi error sync
    isProcessingScan.value = false;

    showSnackbar(
      "Error",
      `Gagal memproses data QR Code: ${error instanceof Error ? error.message : "Error tidak diketahui"}`,
      "error",
      "mdi-alert",
    );

    // Simpan ke history sebagai failed
    saveToHistory({
      patientId: decodedText,
      queueNumber: null as any,
      klinikQueueNumber: null,
      pembayaran: "N/A",
      status: "failed",
      checkInTime: new Date().toISOString(),
      checkInDate: new Date().toISOString(),
      method: "QR Scan",
      klinik: "N/A",
      kodeKlinik: null,
    });
  }

  // Simpan ke localStorage untuk riwayat (selalu simpan, baik berhasil atau gagal)
  saveScannedQRData(decodedText);
};

// Simpan data QR yang di-scan ke localStorage
const saveScannedQRData = (qrData: string) => {
  if (typeof window !== "undefined") {
    const scannedQRs = JSON.parse(
      localStorage.getItem("scanned_qr_data") || "[]",
    );
    scannedQRs.unshift({
      data: qrData,
      timestamp: new Date().toISOString(),
      date: new Date().toLocaleDateString("id-ID"),
      time: new Date().toLocaleTimeString("id-ID").replace(/\./g, ":"),
    });

    // Simpan maksimal 50 item
    if (scannedQRs.length > 50) {
      scannedQRs.pop();
    }

    localStorage.setItem("scanned_qr_data", JSON.stringify(scannedQRs));
  }
};

// Load successful scans dari localStorage
const loadSuccessfulScans = () => {
  if (typeof window !== "undefined") {
    const stored = localStorage.getItem(SUCCESSFUL_SCANS_KEY);
    if (stored) {
      try {
        const scansArray = JSON.parse(stored);
        successfulScans.value = new Set(scansArray);
      } catch (e) {
        console.error("Error loading successful scans:", e);
        successfulScans.value = new Set();
      }
    }
  }
};

// Simpan successful scan ke localStorage
const saveSuccessfulScan = (qrData: string) => {
  if (typeof window !== "undefined") {
    successfulScans.value.add(qrData);
    const scansArray = Array.from(successfulScans.value);
    localStorage.setItem(SUCCESSFUL_SCANS_KEY, JSON.stringify(scansArray));
  }
};

// Cek apakah QR code sudah pernah berhasil di-scan
const isQRCodeAlreadyScanned = (qrData: string): boolean => {
  return successfulScans.value.has(qrData);
};

// Watch tab changes untuk stop scanner saat pindah tab
watch(tab, (newTab) => {
  if (newTab !== "checkin" && isScanning.value) {
    stopScanning();
  }
  // Check camera when switching to checkin tab
  if (newTab === "checkin" && !hasCamera.value && !cameraChecking.value) {
    checkCameraAvailability();
  }
  // Reset generate data when switching to generate tab
  if (newTab === "generate") {
    // Check and reset daily first
    checkAndResetDaily();
    // Clear generated data
    generateBarcode.value = "";
    generateQueueNumber.value = "";
    generatedQRData.value = "";
    generatedPatient.value = null;
  }
});

// Check camera on mount and initialize patient ID
onMounted(async () => {
  if (typeof window !== "undefined") {
    // Wait for DOM to be ready
    await nextTick();

    // Reset tab to checkin (untuk handle refresh)
    tab.value = "checkin";

    // Wait again to ensure tab is rendered
    await nextTick();

    // Reset state saat mount (untuk handle refresh)
    isScanning.value = false;
    cameraReady.value = false;
    scannedData.value = null;
    manualInput.value = "";

    // Cleanup QR scanner instance jika masih ada dari refresh sebelumnya
    if (html5QrCode) {
      try {
        if (isScanning.value) {
          await html5QrCode.stop();
          await html5QrCode.clear();
        }
        html5QrCode = null;
      } catch (err) {
        console.warn("Error cleaning up QR scanner on mount:", err);
        html5QrCode = null;
      }
    }

    // Clear any existing video streams (cleanup dari refresh sebelumnya)
    // Note: We rely on html5QrCode cleanup to stop media tracks

    // Set default klinik if available
    if (!selectedKlinik.value && klinikOptions.value.length > 0) {
      selectedKlinik.value = klinikOptions.value[0].value;
    }

    // Check camera availability
    if (typeof navigator !== "undefined") {
      if (
        navigator.mediaDevices &&
        typeof navigator.mediaDevices.getUserMedia === "function"
      ) {
        checkCameraAvailability();
      } else {
        console.warn(
          "MediaDevices API not available. Make sure you are using HTTPS or localhost.",
        );
        hasCamera.value = false;
        cameraChecking.value = false;
        showSnackbar(
          "Warning",
          "MediaDevices API tidak tersedia. Pastikan menggunakan HTTPS atau localhost.",
          "warning",
          "mdi-alert",
        );
      }
    } else {
      hasCamera.value = false;
      cameraChecking.value = false;
    }

    // Wait for stores to be hydrated and ready
    await nextTick();

    // Load history untuk ditampilkan di sidebar
    loadHistory();

    // Initial fetch/sync
    await fetchAllData();

    // Initialize WebSocket (Centralized)
    queueStore.initWebSocket(checkInClientId.value);
    
    // Register global interest to receive staggered bulk refreshes on generic WS messages
    queueStore.registerGlobalInterest();

    // Set interval to check every minute for reset time
    const resetCheckInterval = setInterval(() => {
      checkAndResetDaily();
    }, 60000); // Check every minute

    onUnmounted(() => {
      clearInterval(resetCheckInterval);
      // Unregister global interest
      queueStore.unregisterGlobalInterest();
    });
  } else {
    hasCamera.value = false;
    cameraChecking.value = false;
  }
});

// Cleanup saat component unmount
onUnmounted(async () => {
  // Stop scanning jika aktif
  if (html5QrCode) {
    try {
      if (isScanning.value) {
        await html5QrCode.stop();
        await html5QrCode.clear();
      }
      // Destroy instance
      html5QrCode = null;
    } catch (err) {
      console.warn("Error stopping scanner on unmount:", err);
      html5QrCode = null;
    }
  }

  // Note: Media tracks are automatically stopped when html5QrCode.stop() is called
  // No need to manually stop tracks here

  // Clear auto-close timer jika ada
  if (autoCloseTimer) {
    clearTimeout(autoCloseTimer);
    autoCloseTimer = null;
  }

  // WebSocket is now global, we might not want to disconnect here if other tabs use it.
  // if (wsInstance) wsInstance.disconnect(); // Old logic

  // Reset state
  isScanning.value = false;
  cameraReady.value = false;
});

// Helper function untuk extract barcode/patientId dari format QR code
// Handle format: "barcode" atau "patientId|status" (contoh: "P-00001|ALLOWED")
// Returns: { barcode: string, status?: string }
const extractQRData = (
  qrData: string,
): { barcode: string; status?: string } => {
  const cleanData = String(qrData || "").trim();

  // Check jika format "patientId|status" (untuk testing QR code)
  if (cleanData.includes("|")) {
    const parts = cleanData.split("|");
    const patientId = parts[0]?.trim() || "";
    const status = parts[1]?.trim();
    return {
      barcode: patientId,
      status: status,
    };
  }

  // Format thermal print: hanya barcode saja
  return {
    barcode: cleanData,
  };
};

// Helper function untuk extract kode dan angka dari noAntrian
// Contoh: "UM0014 | Onsite - ..." -> { kode: "UM", angka: "0014" }
// Contoh: "F-RA001 | Onsite - ..." -> { kode: "RA", angka: "001" } (handle "F-" prefix)
const extractKodeAndAngka = (
  noAntrian: string,
): { kode: string; angka: string } | null => {
  if (!noAntrian) return null;
  // Handle format "F-RA001" by matching after "F-" prefix if exists
  const match = noAntrian.toUpperCase().match(/^(?:F-)?([A-Z]+)(\d+)/);
  if (match) {
    return { kode: match[1], angka: match[2] };
  }
  return null;
};

// Helper function untuk membandingkan input dengan noAntrian (kode + angka harus match)
// Ini mencegah false positive ketika angka sama tapi kode beda (misalnya UM0014 vs AN0014)
// Handle format "F-RA001" dengan menghapus prefix "F-" untuk comparison
const matchNoAntrian = (input: string, noAntrian: string): boolean => {
  if (!input || !noAntrian) return false;

  const cleanInput = String(input).trim().toUpperCase();
  const noAntrianUpper = String(noAntrian).toUpperCase();

  // Remove "F-" prefix from both input and noAntrian for comparison
  const cleanInputWithoutPrefix = cleanInput.replace(/^F-/, "");
  const noAntrianWithoutPrefix = noAntrianUpper.replace(/^F-/, "");

  // 1. Extract kode + angka dari noAntrian (misalnya "F-RA001 | ..." -> kode: "RA", angka: "001")
  const noAntrianParts = extractKodeAndAngka(noAntrian);
  if (!noAntrianParts) {
    // Jika noAntrian tidak punya format kode+angka, gunakan exact match saja
    // Check both with and without prefix
    return (
      noAntrianUpper === cleanInput ||
      noAntrianWithoutPrefix === cleanInputWithoutPrefix
    );
  }

  // 2. Extract kode + angka dari input (misalnya "F-RA001" atau "RA001" -> kode: "RA", angka: "001")
  const inputParts = extractKodeAndAngka(cleanInput);

  // 3. Jika input punya kode + angka, HARUS match kode dan angka
  if (inputParts) {
    // Kode HARUS sama (case-insensitive sudah di-handle oleh extractKodeAndAngka)
    if (inputParts.kode !== noAntrianParts.kode) {
      return false; // Kode berbeda, tidak match
    }
    // Jika kode sama, bandingkan angka
    return (
      inputParts.angka === noAntrianParts.angka ||
      inputParts.angka ===
        noAntrianParts.angka.padStart(inputParts.angka.length, "0") ||
      noAntrianParts.angka ===
        inputParts.angka.padStart(noAntrianParts.angka.length, "0")
    );
  }

  // 4. Jika input hanya angka (tidak punya kode), JANGAN match
  // Ini mencegah match "002" dengan "UM1002" atau "AN002" dengan "UM1002"
  const inputAngka = cleanInputWithoutPrefix.replace(/[^0-9]/g, "");
  if (inputAngka && inputAngka === cleanInputWithoutPrefix) {
    // Input hanya angka, tidak match karena tidak ada kode
    return false;
  }

  // 5. Exact match untuk kasus lain (jika input mengandung kode tapi tidak ter-extract)
  // Check both with and without prefix
  if (
    noAntrianUpper === cleanInput ||
    noAntrianWithoutPrefix === cleanInputWithoutPrefix
  ) {
    return true;
  }

  // 6. Check jika noAntrian dimulai dengan input + spasi atau pipe (untuk partial match yang aman)
  // Contoh: "F-RA001" match dengan "F-RA001 | ..." atau "RA001" match dengan "F-RA001 | ..."
  // Tapi TIDAK match dengan "UM1002" karena kode berbeda
  if (noAntrianParts && inputParts) {
    // Jika kedua-duanya punya kode+angka, hanya match jika kode sama
    if (inputParts.kode === noAntrianParts.kode) {
      // Check jika noAntrian dimulai dengan format "F-KODEANGKA |" atau "KODEANGKA | ..."
      const noAntrianPrefix = `${noAntrianParts.kode}${noAntrianParts.angka}`;
      const inputPrefix = `${inputParts.kode}${inputParts.angka}`;

      // Pastikan input prefix sama dengan noAntrian prefix
      if (inputPrefix === noAntrianPrefix) {
        // Check jika noAntrian dimulai dengan prefix ini (with or without "F-") diikuti spasi, pipe, atau end of string
        if (noAntrianWithoutPrefix.startsWith(noAntrianPrefix)) {
          const nextChar = noAntrianWithoutPrefix[noAntrianPrefix.length];
          if (!nextChar || nextChar === " " || nextChar === "|") {
            return true;
          }
        }
        // Also check with "F-" prefix
        if (noAntrianUpper.startsWith(`F-${noAntrianPrefix}`)) {
          const nextChar = noAntrianUpper[`F-${noAntrianPrefix}`.length];
          if (!nextChar || nextChar === " " || nextChar === "|") {
            return true;
          }
        }
      }
    }
  }

  return false;
};

// --- FUNGSI TAMBAHAN SCANNER ---

/**
 * Berpindah antara kamera depan dan belakang
 */
const switchCamera = async () => {
  if (!isScanning.value) return;

  const newMode = currentFacingMode.value === "user" ? "environment" : "user";
  console.log(`Switching camera to: ${newMode}`);

  // Stop scanner dulu
  if (html5QrCode) {
    try {
      await html5QrCode.stop();
    } catch (err) {
      console.warn("Error stopping for camera switch:", err);
    }
  }

  // Update mode dan restart
  currentFacingMode.value = newMode;
  cameraReady.value = false;
  await startScanning();
};

/**
 * Trigger pemilih file (Photo Mode)
 */
const triggerFileSelect = () => {
  if (fileInput.value) {
    fileInput.value.click();
  }
};

/**
 * Handle scan dari file gambar (Photo Mode)
 */
const handleFileSelect = async (event: Event) => {
  const input = event.target as HTMLInputElement;
  if (!input.files || input.files.length === 0) return;

  const file = input.files[0];
  isProcessingFile.value = true;

  try {
    // Pastikan scanner ter-inisialisasi
    if (!html5QrCode) {
      const { Html5Qrcode: Html5QrcodeClass } = await import("html5-qrcode");
      html5QrCode = new Html5QrcodeClass(qrCodeId);
    }

    console.log("Processing file scan...");
    const decodedText = await html5QrCode.scanFile(file, true);

    if (decodedText) {
      console.log("✅ QR Code detected from file:", decodedText);
      handleQRScanSuccess(decodedText);
    }
  } catch (err) {
    console.error("Error scanning file:", err);
    showSnackbar(
      "Error",
      "Gagal mendeteksi QR code dari foto. Pastikan foto jelas dan terang.",
      "error",
      "mdi-alert-circle",
    );
  } finally {
    isProcessingFile.value = false;
    // Reset input agar bisa pilih file yang sama lagi jika perlu
    if (input) input.value = "";
  }
};

const onDetect = async (decodedText: string) => {
  // Guard tambahan: Jika sedang proses, abaikan
  if (!isProcessingScan.value && !infoDialog.value) {
    // Jika dipanggil langsung bukan dari handleQRScanSuccess, set processing flag
    isProcessingScan.value = true;
    console.log("📸 onDetect: Processing started (scanner remains active)...");
  }

  // Format QR Code yang didukung:
  // 1. Format thermal print: hanya BARCODE saja (contoh: 250811100163)
  // 2. Format testing: "patientId|status" (contoh: P-00001|ALLOWED)
  // Status akan dicek real-time dari queueStore saat scan QR

  console.log("🔍 onDetect called with QR data:", decodedText);

  // Extract barcode/patientId dari QR data (handle format testing dengan pipe)
  const qrData = extractQRData(decodedText);
  const searchBarcode = qrData.barcode; // Barcode/patientId untuk dicari di queueStore

  // Clean input - remove whitespace and normalize
  const cleanInput = String(searchBarcode).trim();
  const cleanInputUpper = cleanInput.toUpperCase();

  console.log("🔍 Extracted barcode/patientId:", searchBarcode);
  console.log("🔍 Cleaned input:", cleanInput);
  console.log("📊 Total patients in store:", queueStore.allPatients.length);

  // IMPORTANT: Hanya cari dengan EXACT barcode match untuk menghindari false positive
  // Format barcode: YYMMDD + 5 digit (contoh: 26011500001)
  // Jangan gunakan fallback ke noAntrian atau no karena bisa menyebabkan false positive
  // Contoh masalah: RA020 dengan barcode 26011500001 terdeteksi sebagai RA002 dengan barcode 26011500198
  const foundPatient = (queueStore.allPatients as any[]).find((p) => {
    if (!p) return false;

    // Normalize barcode untuk comparison (remove whitespace, case-insensitive)
    const patientBarcode = String(p.barcode || "").trim();

    // EXACT barcode match (case-insensitive, whitespace-insensitive)
    // Ini adalah satu-satunya cara yang aman untuk match pasien
    if (
      patientBarcode === cleanInput ||
      patientBarcode.toLowerCase() === cleanInput.toLowerCase()
    ) {
      console.log(
        "✅ Found by exact barcode match:",
        patientBarcode,
        "===",
        cleanInput,
      );
      return true;
    }

    return false;
  });

  if (!foundPatient) {
    // Tiket belum di-generate (tidak ada di queueStore)
    console.error("❌ Patient not found. QR data:", decodedText);
    console.error("🔍 Extracted barcode/patientId:", searchBarcode);
    console.error(
      "📋 Available barcodes (first 10):",
      queueStore.allPatients.slice(0, 10).map((p) => ({
        no: p.no,
        barcode: p.barcode,
        noAntrian: p.noAntrian?.split(" |")[0],
      })),
    );

    saveToHistory({
      patientId: searchBarcode || decodedText,
      queueNumber: null,
      klinikQueueNumber: null,
      pembayaran: "N/A",
      status: "failed",
      checkInTime: new Date().toISOString(),
      checkInDate: new Date().toISOString(),
      method: "QR Scan",
    });

    const errorMsg = `❌ Tiket Belum Di-generate!\n\nQR Code: ${decodedText}\nBarcode/Patient ID: ${searchBarcode}\n\nTiket belum terdaftar di sistem. Pastikan tiket sudah di-generate terlebih dahulu.`;
    infoMessage.value = errorMsg;
    infoAction.value = "checkin";
    infoDialog.value = true;
    showSnackbar(
      "Error",
      "Tiket belum terdaftar di sistem. Pastikan tiket sudah di-generate.",
      "error",
      "mdi-alert-circle",
    );
    return;
  }

  // CATATAN: Validasi processStage dihapus karena terlalu ketat
  // Yang penting adalah status pasien (waiting/pending), bukan processStage
  // Pasien yang sudah dipanggil (status: waiting) harus bisa check-in
  // meskipun processStage-nya bukan 'loket' (bisa 'klinik' atau 'penunjang')
  // Validasi processStage akan dilakukan di checkInPatient() di queueStore
  // yang akan mengecek status pasien secara real-time

  // IMPORTANT: Refresh data pasien dari queueStore untuk mendapatkan status REAL-TIME
  // Jangan gunakan foundPatient.status karena mungkin sudah stale
  // Cari ulang pasien dari queueStore dengan EXACT barcode match
  const freshPatient = (queueStore.allPatients as any[]).find((p) => {
    const patientBarcode = String(p.barcode || "").trim();
    // Hanya exact barcode match untuk menghindari false positive
    return (
      patientBarcode === foundPatient.barcode ||
      patientBarcode === searchBarcode ||
      patientBarcode === cleanInput
    );
  });

  if (!freshPatient) {
    console.error("❌ Patient not found in queueStore after refresh");
    saveToHistory({
      patientId: foundPatient.barcode,
      queueNumber: foundPatient.noAntrian,
      klinikQueueNumber:
        foundPatient.noAntrian?.split(" |")[0] || foundPatient.noAntrian,
      pembayaran: foundPatient.pembayaran || "N/A",
      status: "failed",
      checkInTime: new Date().toISOString(),
      checkInDate: new Date().toISOString(),
      method: "QR Scan",
      klinik: foundPatient.klinik || "N/A",
      kodeKlinik: foundPatient.kodeKlinik || null,
    });

    const errorMsg = `❌ Pasien tidak ditemukan di sistem setelah refresh data.`;
    infoMessage.value = errorMsg;
    infoAction.value = "checkin";
    infoDialog.value = true;
    showSnackbar(
      "Error",
      "Pasien tidak ditemukan di sistem",
      "error",
      "mdi-alert-circle",
    );
    return;
  }

  // Gunakan data pasien yang fresh untuk validasi
  const patientStatus = freshPatient.status;
  const klinikQueueNumber =
    freshPatient.noAntrian?.split(" |")[0] || freshPatient.noAntrian || "N/A";

  console.log("🔍 Fresh patient status:", {
    barcode: freshPatient.barcode,
    noAntrian: freshPatient.noAntrian,
    status: patientStatus,
    processStage: freshPatient.processStage,
  });

  // Cek apakah sudah check-in (status === 'di-loket') - gunakan data fresh
  if (patientStatus === "di-loket") {
    // Sudah check-in sebelumnya
    saveToHistory({
      patientId: freshPatient.barcode,
      queueNumber: freshPatient.noAntrian,
      klinikQueueNumber: klinikQueueNumber,
      pembayaran: freshPatient.pembayaran || "N/A",
      status: "failed",
      checkInTime: new Date().toISOString(),
      checkInDate: new Date().toISOString(),
      method: "QR Scan",
      klinik: freshPatient.klinik || "N/A",
      kodeKlinik: freshPatient.kodeKlinik || null,
    });

    lastCheckInResult.value = {
      success: false,
      patientId: freshPatient.barcode,
      status: "ALREADY_CHECKED_IN",
    };

    const errorMsg = `⚠️ Sudah Check-in!\n\nNomor Antrean ${klinikQueueNumber} sudah melakukan check-in sebelumnya.`;
    infoMessage.value = errorMsg;
    infoAction.value = "checkin";
    infoDialog.value = true;
    showSnackbar(
      "Warning",
      `Tiket ${klinikQueueNumber} sudah check-in sebelumnya`,
      "warning",
      "mdi-check-circle",
    );
    return;
  }

  if (patientStatus === "menunggu") {
    // Status "menunggu" = belum dipanggil oleh admin loket, belum muncul di AntrianLoket
    // TIDAK BOLEH check-in
    saveToHistory({
      patientId: freshPatient.barcode,
      queueNumber: freshPatient.noAntrian,
      klinikQueueNumber: klinikQueueNumber,
      pembayaran: freshPatient.pembayaran || "N/A",
      status: "NOT_ALLOWED",
      checkInTime: new Date().toISOString(),
      checkInDate: new Date().toISOString(),
      method: "QR Scan",
      klinik: freshPatient.klinik || "N/A",
      kodeKlinik: freshPatient.kodeKlinik || null,
    });

    lastCheckInResult.value = {
      success: false,
      patientId: freshPatient.barcode,
      status: "NOT_ALLOWED",
    };

    const errorMsg = `⏳ Belum Diizinkan Check-in\n\nNomor Antrean ${klinikQueueNumber} belum dipanggil oleh admin loket. Mohon menunggu hingga nomor antrean Anda dipanggil dan muncul di layar Antrian Loket.`;
    infoMessage.value = errorMsg;
    infoAction.value = "kembali";
    infoDialog.value = true;
    showSnackbar(
      "Info",
      `Tiket ${klinikQueueNumber} belum dipanggil. Mohon menunggu.`,
      "info",
      "mdi-clock-alert",
    );
    return;
  }

  // Status "waiting" atau "pending" → BOLEH check-in
  // Panggil checkInPatient untuk validasi dan update status ke "di-loket"
  // Gunakan barcode pasien yang fresh, bukan decodedText (untuk memastikan format benar)
  const patientBarcodeForCheckIn =
    freshPatient.barcode || searchBarcode || decodedText;
  console.log(
    "🔍 Calling checkInPatient with barcode (fresh):",
    patientBarcodeForCheckIn,
  );
  console.log(
    "🔍 Original QR data:",
    decodedText,
    "| Extracted barcode:",
    searchBarcode,
  );
  const checkInResult = await queueStore.checkInPatient(
    patientBarcodeForCheckIn,
  );

  if (checkInResult.success && checkInResult.patient) {
    // Check-in berhasil
    const successKlinikQueueNumber =
      checkInResult.patient.noAntrian?.split(" |")[0] ||
      checkInResult.patient.noAntrian ||
      "N/A";

    lastCheckInResult.value = {
      success: true,
      patientId: checkInResult.patient.barcode,
      status: "ALLOWED",
    };

    saveToHistory({
      patientId: checkInResult.patient.barcode,
      queueNumber: checkInResult.patient.noAntrian,
      klinikQueueNumber: successKlinikQueueNumber,
      pembayaran: checkInResult.patient.pembayaran || "N/A",
      status: "success",
      checkInTime: new Date().toISOString(),
      checkInDate: new Date().toISOString(),
      method: "QR Scan",
      klinik: checkInResult.patient.klinik || "N/A",
      kodeKlinik: checkInResult.patient.kodeKlinik || null,
    });

    saveSuccessfulScan(decodedText);
    const successMsg = `✅ Check-in Berhasil!\n\nPasien ${successKlinikQueueNumber} berhasil melakukan check-in dan status berubah menjadi di loket.`;
    infoMessage.value = successMsg;
    infoAction.value = "checkin";
    infoDialog.value = true;
    showSnackbar(
      "Berhasil",
      `Check-in berhasil. Tiket ${successKlinikQueueNumber} siap diproses.`,
      "success",
      "mdi-check-circle",
    );
  } else {
    // Check-in gagal (misalnya validasi di checkInPatient gagal)
    saveToHistory({
      patientId: foundPatient.barcode,
      queueNumber: foundPatient.noAntrian,
      klinikQueueNumber: klinikQueueNumber,
      pembayaran: foundPatient.pembayaran || "N/A",
      status: "failed",
      checkInTime: new Date().toISOString(),
      checkInDate: new Date().toISOString(),
      method: "QR Scan",
      klinik: foundPatient.klinik || "N/A",
      kodeKlinik: foundPatient.kodeKlinik || null,
    });

    lastCheckInResult.value = {
      success: false,
      patientId: foundPatient.barcode,
      status: "FAILED",
    };

    const errorMsg = `❌ Check-in Gagal!\n\n${checkInResult.message || "Status pasien tidak memungkinkan untuk check-in."}`;
    infoMessage.value = errorMsg;
    infoAction.value = "checkin";
    infoDialog.value = true;
    showSnackbar(
      "Gagal",
      checkInResult.message || "Check-in gagal dilakukan",
      "error",
      "mdi-close-circle",
    );
  }
};

const handleInfoAction = async () => {
  // Clear auto-close timer jika ada
  if (autoCloseTimer) {
    clearTimeout(autoCloseTimer);
    autoCloseTimer = null;
  }

  infoDialog.value = false;
  
  // Reset processing flag agar bisa scan lagi
  isProcessingScan.value = false;

  // Scanner sudah berjalan (tidak dihentikan), jadi tidak perlu startScanning() lagi
};

// Watch infoDialog untuk auto-close setelah 3 detik
watch(infoDialog, (isOpen: boolean) => {
  // Clear timer yang ada jika dialog ditutup
  if (autoCloseTimer) {
    clearTimeout(autoCloseTimer);
    autoCloseTimer = null;
  }

  // Jika dialog dibuka, set timer untuk auto-close setelah 3 detik
  if (isOpen) {
    autoCloseTimer = setTimeout(() => {
      infoDialog.value = false;
      autoCloseTimer = null;
    }, 5000); // 5   detik
  }
});

const showSnackbar = (
  title: string,
  message: string,
  color: string,
  icon: string,
) => {
  snackbar.value.title = title;
  snackbar.value.message = message;
  snackbar.value.color = color;
  snackbar.value.icon = icon;
  snackbar.value.show = true;
};

const checkInManual = async () => {
  if (!manualInput.value) {
    showSnackbar(
      "Error",
      "Mohon isi nomor antrean, barcode, atau ID pasien",
      "error",
      "mdi-alert",
    );
    return;
  }

  const inputValue = manualInput.value.trim();

  // Extract barcode/patientId dari input (handle format testing dengan pipe)
  const qrData = extractQRData(inputValue);
  const searchBarcode = qrData.barcode; // Barcode/patientId untuk dicari di queueStore

  const cleanInput = String(searchBarcode).trim();
  const cleanInputUpper = cleanInput.toUpperCase();
  const originalInput = inputValue.toUpperCase().trim();

  console.log("🔍 checkInManual called with:", inputValue);
  console.log("🔍 Extracted barcode/patientId:", searchBarcode);
  console.log("🔍 Cleaned input:", cleanInput);
  console.log("🔍 Original input:", originalInput);
  console.log("📊 Total patients in store:", queueStore.allPatients.length);

  let foundPatient: any = null;
  let freshPatient: any = null;

  try {
    // Cari pasien dengan dua metode:
    // ...
    foundPatient = queueStore.allPatients.find((p) => {
      try {
        if (!p) return false;

        // Normalize barcode untuk comparison (remove whitespace, case-insensitive)
        const patientBarcode = String(p.barcode || "").trim();

        // 1. EXACT barcode match (case-insensitive, whitespace-insensitive) - PRIORITAS TERTINGGI
        if (
          patientBarcode === cleanInput ||
          patientBarcode.toLowerCase() === cleanInput.toLowerCase()
        ) {
          console.log(
            "✅ Found by exact barcode match:",
            patientBarcode,
            "===",
            cleanInput,
          );
          return true;
        }

        // 2. EXACT nomor antrean match (untuk manual input)
        // Menggunakan matchNoAntrian helper untuk memastikan kode + angka match dengan benar
        if (p.noAntrian && typeof matchNoAntrian === "function") {
          if (matchNoAntrian(originalInput, p.noAntrian)) {
            console.log(
              "✅ Found by exact nomor antrean match:",
              p.noAntrian,
              "===",
              originalInput,
            );
            return true;
          }
        }
      } catch (innerErr) {
        console.warn("⚠️ Error in patient find loop for patient:", p, innerErr);
      }
      return false;
    });

    if (!foundPatient) {
      // Tiket belum di-generate (tidak ada di queueStore)
      console.error("❌ Patient not found. Input:", inputValue);
      console.error("🔍 Extracted barcode/patientId:", searchBarcode);
      console.error(
        "📋 Available patients (first 10):",
        queueStore.allPatients.slice(0, 10).map((p) => ({
          no: p.no,
          barcode: p.barcode,
          noAntrian: p.noAntrian?.split(" |")[0],
        })),
      );

      saveToHistory({
        patientId: searchBarcode || inputValue,
        queueNumber: null,
        klinikQueueNumber: null,
        pembayaran: "N/A",
        status: "failed",
        checkInTime: new Date().toISOString(),
        checkInDate: new Date().toISOString(),
        method: "Manual",
        klinik: "N/A",
        kodeKlinik: null,
      });

      // RESET lastCheckInResult for failure to avoid success color bleed
      lastCheckInResult.value = {
        success: false,
        patientId: searchBarcode || inputValue,
        status: "NOT_FOUND",
      };

      const errorMsg = `❌ Tiket Tidak Ditemukan!\n\nInput: ${inputValue}\n\nTiket dengan nomor antrean atau barcode tersebut tidak ditemukan di sistem.\n\nPastikan:\n- Nomor antrean atau barcode sudah benar\n- Tiket sudah di-generate terlebih dahulu\n- Format input: RA020, F-RA001, atau 26011500001`;
      infoMessage.value = errorMsg;
      infoAction.value = "checkin";
      infoDialog.value = true;
      showSnackbar(
        "Error",
        "Tiket tidak ditemukan. Pastikan nomor antrean atau barcode sudah benar.",
        "error",
        "mdi-alert-circle",
      );
      return;
    }

    // CATATAN: Validasi processStage dihapus karena terlalu ketat
    // Yang penting adalah status pasien (waiting/pending), bukan processStage
    // Pasien yang sudah dipanggil (status: waiting) harus bisa check-in
    // meskipun processStage-nya bukan 'loket' (bisa 'klinik' atau 'penunjang')
    // Validasi processStage akan dilakukan di checkInPatient() di queueStore
    // yang akan mengecek status pasien secara real-time

    // IMPORTANT: Refresh data pasien dari queueStore untuk mendapatkan status REAL-TIME
    // Jangan gunakan foundPatient.status karena mungkin sudah stale
    // Cari ulang pasien dari queueStore dengan EXACT match (barcode atau nomor antrean)
    freshPatient = queueStore.allPatients.find((p) => {
      if (!p) return false;

      // Match by barcode
      const patientBarcode = String(p.barcode || "").trim();
      if (
        foundPatient && (
          patientBarcode === foundPatient.barcode ||
          patientBarcode === searchBarcode ||
          patientBarcode === cleanInput
        )
      ) {
        return true;
      }

      // Match by nomor antrean (jika input adalah nomor antrean)
      if (foundPatient && p.noAntrian && p.no === foundPatient.no) {
        return true;
      }

      return false;
    });

    if (!freshPatient) {
      console.error("❌ Patient not found in queueStore after refresh");
      saveToHistory({
        patientId: foundPatient.barcode,
        queueNumber: foundPatient.noAntrian,
        klinikQueueNumber:
          foundPatient.noAntrian?.split(" |")[0] || foundPatient.noAntrian,
        pembayaran: foundPatient.pembayaran || "N/A",
        status: "failed",
        checkInTime: new Date().toISOString(),
        checkInDate: new Date().toISOString(),
        method: "Manual",
        klinik: foundPatient.klinik || "N/A",
        kodeKlinik: foundPatient.kodeKlinik || null,
      });

      // RESET lastCheckInResult for failure
      lastCheckInResult.value = {
        success: false,
        patientId: foundPatient.barcode,
        status: "REFRESH_NOT_FOUND",
      };

      const errorMsg = `❌ Pasien tidak ditemukan di sistem setelah refresh data.`;
      infoMessage.value = errorMsg;
      infoAction.value = "checkin";
      infoDialog.value = true;
      showSnackbar(
        "Error",
        "Pasien tidak ditemukan di sistem",
        "error",
        "mdi-alert-circle",
      );
      return;
    }

    // Gunakan data pasien yang fresh untuk validasi
    const patientStatus = freshPatient.status;
    const klinikQueueNumber =
      freshPatient.noAntrian?.split(" |")[0] || freshPatient.noAntrian || "N/A";

    console.log("🔍 Fresh patient status:", {
      barcode: freshPatient.barcode,
      noAntrian: freshPatient.noAntrian,
      status: patientStatus,
      processStage: freshPatient.processStage,
    });

    // Cek apakah sudah check-in (status === 'di-loket') - gunakan data fresh
    if (patientStatus === "di-loket") {
      // Sudah check-in sebelumnya
      saveToHistory({
        patientId: freshPatient.barcode,
        queueNumber: freshPatient.noAntrian,
        klinikQueueNumber: klinikQueueNumber,
        pembayaran: freshPatient.pembayaran || "N/A",
        status: "failed",
        checkInTime: new Date().toISOString(),
        checkInDate: new Date().toISOString(),
        method: "Manual",
        klinik: freshPatient.klinik || "N/A",
        kodeKlinik: freshPatient.kodeKlinik || null,
      });

      lastCheckInResult.value = {
        success: false,
        patientId: freshPatient.barcode,
        status: "ALREADY_CHECKED_IN",
      };

      const errorMsg = `⚠️ Sudah Check-in!\n\nNomor Antrean ${klinikQueueNumber} sudah melakukan check-in sebelumnya.`;
      infoMessage.value = errorMsg;
      infoAction.value = "checkin";
      infoDialog.value = true;
      showSnackbar(
        "Warning",
        `Tiket ${klinikQueueNumber} sudah check-in sebelumnya`,
        "warning",
        "mdi-check-circle",
      );
      return;
    }

    if (patientStatus === "menunggu") {
      // Status "menunggu" = belum dipanggil oleh admin loket, belum muncul di AntrianLoket
      // TIDAK BOLEH check-in
      saveToHistory({
        patientId: freshPatient.barcode,
        queueNumber: freshPatient.noAntrian,
        klinikQueueNumber: klinikQueueNumber,
        pembayaran: freshPatient.pembayaran || "N/A",
        status: "NOT_ALLOWED",
        checkInTime: new Date().toISOString(),
        checkInDate: new Date().toISOString(),
        method: "Manual",
        klinik: freshPatient.klinik || "N/A",
        kodeKlinik: freshPatient.kodeKlinik || null,
      });

      lastCheckInResult.value = {
        success: false,
        patientId: freshPatient.barcode,
        status: "NOT_ALLOWED",
      };

      const errorMsg = `⏳ Belum Diizinkan Check-in\n\nNomor Antrean ${klinikQueueNumber} belum dipanggil oleh admin loket. Mohon menunggu hingga nomor antrean Anda dipanggil dan muncul di layar Antrian Loket.`;
      infoMessage.value = errorMsg;
      infoAction.value = "kembali";
      infoDialog.value = true;
      showSnackbar(
        "Info",
        `Tiket ${klinikQueueNumber} belum dipanggil. Mohon menunggu.`,
        "info",
        "mdi-clock-alert",
      );
      return;
    }

    // Status "waiting" atau "pending" → BOLEH check-in
    // Panggil checkInPatient untuk validasi dan update status ke "di-loket"
    // Gunakan barcode pasien yang fresh, bukan inputValue (untuk memastikan format benar)
    const patientBarcodeForCheckIn =
      freshPatient.barcode || searchBarcode || inputValue;
    console.log(
      "🔍 Calling checkInPatient with barcode (fresh):",
      patientBarcodeForCheckIn,
    );
    console.log(
      "🔍 Original input:",
      inputValue,
      "| Extracted barcode:",
      searchBarcode,
    );
    const checkInResult = await queueStore.checkInPatient(
      patientBarcodeForCheckIn,
    );

    if (checkInResult.success && checkInResult.patient) {
      // Check-in berhasil
      const successKlinikQueueNumber =
        checkInResult.patient.noAntrian?.split(" |")[0] ||
        checkInResult.patient.noAntrian ||
        "N/A";

      lastCheckInResult.value = {
        success: true,
        patientId: checkInResult.patient.barcode,
        status: "ALLOWED",
      };

      saveToHistory({
        patientId: checkInResult.patient.barcode,
        queueNumber: checkInResult.patient.noAntrian,
        klinikQueueNumber: successKlinikQueueNumber,
        pembayaran: checkInResult.patient.pembayaran || "N/A",
        status: "success",
        checkInTime: new Date().toISOString(),
        checkInDate: new Date().toISOString(),
        method: "Manual",
        klinik: checkInResult.patient.klinik || "N/A",
        kodeKlinik: checkInResult.patient.kodeKlinik || null,
      });

      const successMsg = `✅ Check-in Berhasil!\n\nPasien ${successKlinikQueueNumber} berhasil melakukan check-in dan status berubah menjadi di loket.`;
      infoMessage.value = successMsg;
      infoAction.value = "checkin";
      infoDialog.value = true;
      showSnackbar(
        "Berhasil",
        `Check-in manual berhasil. Tiket ${successKlinikQueueNumber} siap diproses.`,
        "success",
        "mdi-check-circle",
      );

      manualInput.value = "";
      if (manualForm.value) {
        (manualForm.value as any).reset();
      }
    } else {
      // Check-in gagal (misalnya validasi di checkInPatient gagal)
      saveToHistory({
        patientId: foundPatient.barcode,
        queueNumber: foundPatient.noAntrian,
        klinikQueueNumber: klinikQueueNumber,
        pembayaran: foundPatient.pembayaran || "N/A",
        status: "failed",
        checkInTime: new Date().toISOString(),
        checkInDate: new Date().toISOString(),
        method: "Manual",
        klinik: foundPatient.klinik || "N/A",
        kodeKlinik: foundPatient.kodeKlinik || null,
      });

      lastCheckInResult.value = {
        success: false,
        patientId: foundPatient.barcode,
        status: "FAILED",
      };

      const errorMsg = `❌ Check-in Gagal!\n\n${checkInResult?.message || "Status pasien tidak memungkinkan untuk check-in."}`;
      infoMessage.value = errorMsg;
      infoAction.value = "checkin";
      infoDialog.value = true;
      showSnackbar(
        "Gagal",
        checkInResult?.message || "Check-in manual gagal dilakukan",
        "error",
        "mdi-close-circle",
      );
    }
  } catch (error) {
    console.error("❌ Fatal Error in checkInManual:", error);
    showSnackbar(
      "Fatal Error",
      "Terjadi kesalahan sistem saat check-in manual",
      "error",
      "mdi-alert-octagon",
    );
  }
};

// Quick generate QR for testing
const generateQuickQR = (status: string) => {
  // Check and reset daily first (before generating)
  checkAndResetDaily();

  // Use first klinik if none selected
  if (!selectedKlinik.value && klinikOptions.value.length > 0) {
    selectedKlinik.value = klinikOptions.value[0].value;
  }

  generateStatus.value = status;
  generateQRCode();
};

// Generate QR Code function - Similar to Anjungan/[id].vue
const generateQRCode = async () => {
  if (!selectedKlinik.value) {
    showSnackbar("Error", "Mohon pilih Klinik/Poli", "error", "mdi-alert");
    return;
  }

  try {
    // Debug: Check if functions are available
    console.log("🔍 Checking queueStore functions:", {
      generateBarcode: typeof queueStore.generateBarcode,
      generateQueueNumber: typeof queueStore.generateQueueNumber,
      incrementBarcodeCounter: typeof queueStore.incrementBarcodeCounter,
      allPatients: typeof queueStore.allPatients,
    });

    // Get clinic data
    const clinicData = masterStore.klinikList.find(
      (k: any) => k.kode === selectedKlinik.value,
    );
    if (!clinicData) {
      showSnackbar("Error", "Klinik tidak ditemukan", "error", "mdi-alert");
      return;
    }

    // Format clinic object untuk generateQueueNumber (same as Anjungan)
    const clinic = {
      name: clinicData.nama || clinicData.name || clinicData.kode,
      kode: clinicData.kode,
    };

    // Generate barcode using queueStore (same as Anjungan)
    // Note: allPatients is a ref, so we pass it directly
    if (
      !queueStore.generateBarcode ||
      typeof queueStore.generateBarcode !== "function"
    ) {
      console.error("❌ generateBarcode is not available in queueStore");
      console.error("Available methods:", Object.keys(queueStore));
      showSnackbar(
        "Error",
        "Fungsi generateBarcode tidak tersedia. Silakan refresh halaman atau restart dev server",
        "error",
        "mdi-alert",
      );
      return;
    }

    const barcode = queueStore.generateBarcode([], queueStore.allPatients);
    console.log("✅ Generated barcode:", barcode);

    // Generate queue number using queueStore (same as Anjungan)
    // Format: R/E + Loket (A-N) + 3 digit
    const isEksekutif = false; // Default to reguler

    if (
      !queueStore.generateQueueNumber ||
      typeof queueStore.generateQueueNumber !== "function"
    ) {
      console.error("❌ generateQueueNumber is not available in queueStore");
      showSnackbar(
        "Error",
        "Fungsi generateQueueNumber tidak tersedia. Silakan refresh halaman atau restart dev server",
        "error",
        "mdi-alert",
      );
      return;
    }

    const queueNumber = queueStore.generateQueueNumber(
      clinic,
      selectedPembayaran.value,
      isEksekutif,
    );
    console.log("✅ Generated queue number:", queueNumber);
    const noAntrian = `${queueNumber} | Onsite - ${barcode}`;

    // Save generated data
    generateBarcode.value = barcode;
    generateQueueNumber.value = queueNumber;

    // QR code hanya berisi barcode saja (sama seperti di thermal print)
    generatedQRData.value = barcode;

    // Create patient object for printing (similar to Anjungan)
    const timestamp = new Date();
    generatedPatient.value = {
      barcode: barcode,
      noAntrian: noAntrian,
      klinik:
        clinic.name || clinicData.nama || clinicData.name || clinicData.kode,
      kodeKlinik: clinic.kode || clinicData.kode,
      pembayaran: selectedPembayaran.value,
      status: "menunggu", // Status awal seperti di Anjungan
      processStage: "loket",
      visitType: "SEKARANG",
      visitDate: timestamp.toISOString().substring(0, 10),
      shift: "Shift 1",
      createdAt: timestamp.toISOString(),
      registrationType: "onsite",
      fastTrack: "TIDAK",
      jamPanggil: `${String(timestamp.getHours()).padStart(2, "0")}:${String(timestamp.getMinutes()).padStart(2, "0")}`,
    };

    // Increment barcode counter (same as Anjungan)
    queueStore.incrementBarcodeCounter();

    await nextTick();

    // Clear previous QR code
    const qrContainer = document.getElementById("qrcode");
    if (qrContainer) {
      qrContainer.innerHTML = "";

      // Use qrcode package
      const QRCode = (await import("qrcode")).default;

      // Create QR code as data URL (same settings as useThermalPrint)
      const qrDataUrl = await QRCode.toDataURL(generatedQRData.value, {
        errorCorrectionLevel: "M",
        type: "image/png",
        quality: 1,
        margin: 2,
        width: 400, // Larger preview size
        color: {
          dark: "#000000",
          light: "#FFFFFF",
        },
      });

      // Create img element and append to container
      const img = document.createElement("img");
      img.src = qrDataUrl;
      img.alt = "QR Code";
      img.style.width = "100%";
      img.style.maxWidth = "300px";
      img.style.height = "auto";
      img.style.display = "block";
      img.style.margin = "0 auto";
      qrContainer.appendChild(img);

      console.log("QR Code created successfully:", generatedQRData.value);
      console.log("Generated patient:", generatedPatient.value);
      showSnackbar(
        "Berhasil!",
        "QR Code berhasil di-generate. Silakan scan untuk testing atau cetak tiket",
        "success",
        "mdi-check-circle",
      );
    } else {
      showSnackbar(
        "Error",
        "Container QR Code tidak ditemukan",
        "error",
        "mdi-alert",
      );
    }
  } catch (error) {
    console.error("Error creating QR code:", error);
    showSnackbar(
      "Error",
      "Gagal membuat QR Code. Silakan coba lagi",
      "error",
      "mdi-alert",
    );
  }
};

// Handle print ticket (similar to Anjungan/[id].vue)
const handlePrintTicket = async () => {
  if (!generatedPatient.value) {
    showSnackbar(
      "Error",
      "Data pasien tidak ditemukan. Silakan generate QR code terlebih dahulu",
      "error",
      "mdi-alert",
    );
    return;
  }

  try {
    await printTicketFromPatient(generatedPatient.value);
    showSnackbar(
      "Berhasil!",
      "Tiket berhasil dicetak",
      "success",
      "mdi-printer",
    );
  } catch (error) {
    console.error("Error printing ticket:", error);
    showSnackbar(
      "Error",
      "Gagal mencetak tiket. Silakan coba lagi",
      "error",
      "mdi-alert",
    );
  }
};

const downloadQR = async () => {
  const img = document.querySelector("#qrcode img") as HTMLImageElement;
  if (img && img.src) {
    try {
      // Convert img src (data URL) to blob
      const response = await fetch(img.src);
      const blob = await response.blob();
      const url = URL.createObjectURL(blob);
      const link = document.createElement("a");
      const klinikCode = selectedKlinik.value || "UNKNOWN";
      const fileName = `QR-Test-${klinikCode}-${generateQueueNumber.value}-${generateStatus.value}-${Date.now()}.png`;
      link.download = fileName;
      link.href = url;
      link.style.display = "none";
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      URL.revokeObjectURL(url);
      showSnackbar(
        "Berhasil!",
        `QR Code berhasil didownload: ${fileName}`,
        "success",
        "mdi-download",
      );
    } catch (error) {
      console.error("Download error:", error);
      // Fallback: use img src directly
      const link = document.createElement("a");
      const klinikCode = selectedKlinik.value || "UNKNOWN";
      link.download = `QR-Test-${klinikCode}-${generateQueueNumber.value}-${generateStatus.value}.png`;
      link.href = img.src;
      link.click();
      showSnackbar(
        "Berhasil!",
        "QR Code berhasil didownload",
        "success",
        "mdi-download",
      );
    }
  } else {
    showSnackbar(
      "Error",
      "QR Code belum di-generate. Silakan generate terlebih dahulu",
      "error",
      "mdi-alert",
    );
  }
};

const copyQRToClipboard = async () => {
  const img = document.querySelector("#qrcode img") as HTMLImageElement;
  if (img && img.src) {
    try {
      // Convert img src to blob
      const response = await fetch(img.src);
      const blob = await response.blob();

      try {
        await navigator.clipboard.write([
          new ClipboardItem({
            "image/png": blob,
          }),
        ]);
        showSnackbar(
          "Berhasil!",
          "QR Code berhasil disalin ke clipboard",
          "success",
          "mdi-content-copy",
        );
      } catch (err: any) {
        console.error("Clipboard error:", err);
        // Fallback: download instead
        showSnackbar(
          "Info",
          "Copy ke clipboard tidak didukung. Gunakan tombol Download.",
          "info",
          "mdi-information",
        );
      }
    } catch (error) {
      console.error("Copy error:", error);
      showSnackbar("Error", "Gagal menyalin QR Code", "error", "mdi-alert");
    }
  } else {
    showSnackbar(
      "Error",
      "QR Code belum di-generate. Silakan generate terlebih dahulu",
      "error",
      "mdi-alert",
    );
  }
};

const shareQR = async () => {
  const img = document.querySelector("#qrcode img") as HTMLImageElement;
  if (img && img.src) {
    try {
      // Convert img src to blob
      const response = await fetch(img.src);
      const blob = await response.blob();
      const klinikCode = selectedKlinik.value || "UNKNOWN";
      const file = new File(
        [blob],
        `QR-Test-${klinikCode}-${generateQueueNumber.value}-${generateStatus.value}.png`,
        { type: "image/png" },
      );

      if (navigator.share && navigator.canShare({ files: [file] })) {
        try {
          await navigator.share({
            files: [file],
            title: "QR Code Check-in Test",
            text: `QR Code untuk testing: ${generatedQRData.value}`,
          });
          showSnackbar(
            "Berhasil!",
            "QR Code berhasil dibagikan",
            "success",
            "mdi-share",
          );
        } catch (err: any) {
          if (err.name !== "AbortError") {
            // Fallback to copy or download
            copyQRToClipboard();
          }
        }
      } else {
        // Fallback: try copy to clipboard
        copyQRToClipboard();
      }
    } catch (error) {
      console.error("Share error:", error);
      showSnackbar("Error", "Gagal membagikan QR Code", "error", "mdi-alert");
    }
  } else {
    showSnackbar(
      "Error",
      "QR Code belum di-generate. Silakan generate terlebih dahulu",
      "error",
      "mdi-alert",
    );
  }
};

// History Functions
const loadHistory = () => {
  if (typeof window !== "undefined") {
    const stored = localStorage.getItem(HISTORY_STORAGE_KEY);
    if (stored) {
      try {
        checkInHistory.value = JSON.parse(stored);
      } catch (e) {
        console.error("Error loading history:", e);
        checkInHistory.value = [];
      }
    }
  }
};

const saveToHistory = (item: {
  patientId: string;
  queueNumber?: string;
  klinikQueueNumber?: string;
  pembayaran?: string;
  status: string;
  checkInTime: string;
  checkInDate: string;
  method: string;
  kodeKlinik?: string;
  klinik?: string;
}) => {
  // JANGAN generate nomor antrean baru - selalu gunakan nomor dari pasien yang ditemukan
  // Jika queueNumber tidak ada, gunakan klinikQueueNumber atau patientId sebagai fallback
  // Tapi jangan generate nomor baru karena itu akan mengubah nomor antrean yang sebenarnya
  let queueNumber = item.queueNumber;
  if (!queueNumber && item.klinikQueueNumber) {
    // Jika queueNumber tidak ada tapi ada klinikQueueNumber, gunakan itu
    queueNumber = item.klinikQueueNumber;
  } else if (!queueNumber && item.patientId) {
    // Jika masih tidak ada, gunakan patientId (barcode) sebagai fallback
    queueNumber = item.patientId;
  }
  // Jangan generate nomor baru - biarkan null/undefined jika memang tidak ada
  // Ini memastikan nomor antrean yang ditampilkan sesuai dengan yang ada di tiket

  const historyItem = {
    ...item,
    queueNumber:
      queueNumber || item.klinikQueueNumber || item.patientId || null,
  };

  // Jika status baru adalah "success" atau "ALLOWED", cek apakah ada history lama dengan patientId yang sama
  // yang masih berstatus "NOT_ALLOWED", "pending", atau "failed"
  // Jika ada, hapus entry lama tersebut agar tidak terhitung sebagai "menunggu"
  if (item.status === "success" || item.status === "ALLOWED") {
    // Cari dan hapus entry lama dengan patientId yang sama yang masih menunggu
    const waitingStatuses = ["NOT_ALLOWED", "pending", "failed"];
    const indexToRemove = checkInHistory.value.findIndex(
      (history: {
        patientId: string;
        queueNumber?: string;
        klinikQueueNumber?: string;
        pembayaran?: string;
        status: string;
        checkInTime: string;
        checkInDate: string;
        method: string;
        kodeKlinik?: string;
      }) =>
        history.patientId === item.patientId &&
        waitingStatuses.includes(history.status),
    );

    if (indexToRemove !== -1) {
      // Hapus entry lama yang masih menunggu
      checkInHistory.value.splice(indexToRemove, 1);
      console.log(
        `✅ Menghapus entry lama untuk pasien ${item.patientId} yang masih menunggu`,
      );
    }
  }

  checkInHistory.value.unshift(historyItem);

  // Simpan maksimal 100 item
  if (checkInHistory.value.length > 100) {
    checkInHistory.value = checkInHistory.value.slice(0, 100);
  }

  if (typeof window !== "undefined") {
    localStorage.setItem(
      HISTORY_STORAGE_KEY,
      JSON.stringify(checkInHistory.value),
    );
  }
};

const deleteHistoryItem = (index: number) => {
  // Index dari paginatedHistory, perlu dikonversi ke index di checkInHistory
  const paginatedItem = paginatedHistory.value[index];
  if (!paginatedItem) return;

  // Cari index sebenarnya di checkInHistory
  const actualIndex = checkInHistory.value.findIndex(
    (h) =>
      h.patientId === paginatedItem.patientId &&
      h.checkInTime === paginatedItem.checkInTime &&
      h.method === paginatedItem.method,
  );

  if (actualIndex !== -1) {
    checkInHistory.value.splice(actualIndex, 1);
    if (typeof window !== "undefined") {
      localStorage.setItem(
        HISTORY_STORAGE_KEY,
        JSON.stringify(checkInHistory.value),
      );
    }
    showSnackbar(
      "Berhasil",
      "Riwayat berhasil dihapus",
      "success",
      "mdi-check",
    );

    // Reset ke halaman sebelumnya jika halaman saat ini kosong
    if (paginatedHistory.value.length === 0 && historyPage.value > 1) {
      historyPage.value = Math.max(1, historyPage.value - 1);
    }
  }
};

const clearHistory = () => {
  checkInHistory.value = [];
  if (typeof window !== "undefined") {
    localStorage.removeItem(HISTORY_STORAGE_KEY);
  }
  showSnackbar(
    "Berhasil",
    "Semua riwayat berhasil dihapus",
    "success",
    "mdi-check",
  );
};

const openHistoryDialog = () => {
  // Pastikan history dimuat ulang saat dialog dibuka
  loadHistory();
  // Reset filter dan pagination saat membuka dialog
  historySearch.value = "";
  historyStatusFilter.value = "";
  historyPage.value = 1;
  historyDialog.value = true;
};

const openQRHistoryDialog = () => {
  loadScannedQRHistory();
  qrHistoryDialog.value = true;
};

const loadScannedQRHistory = () => {
  if (typeof window !== "undefined") {
    const stored = localStorage.getItem("scanned_qr_data");
    if (stored) {
      try {
        scannedQRHistory.value = JSON.parse(stored);
      } catch (e) {
        console.error("Error loading QR history:", e);
        scannedQRHistory.value = [];
      }
    } else {
      scannedQRHistory.value = [];
    }
  }
};

const clearQRHistory = () => {
  scannedQRHistory.value = [];
  if (typeof window !== "undefined") {
    localStorage.removeItem("scanned_qr_data");
  }
  showSnackbar(
    "Berhasil",
    "Semua riwayat QR scan berhasil dihapus",
    "success",
    "mdi-check",
  );
};

const deleteQRHistoryItem = (index: number) => {
  scannedQRHistory.value.splice(index, 1);
  if (typeof window !== "undefined") {
    localStorage.setItem(
      "scanned_qr_data",
      JSON.stringify(scannedQRHistory.value),
    );
  }
  showSnackbar(
    "Berhasil",
    "Riwayat QR scan berhasil dihapus",
    "success",
    "mdi-check",
  );
};

const useQRData = (qrData: string) => {
  qrHistoryDialog.value = false;
  scannedData.value = qrData;
  onDetect(qrData);
};

const filteredQRHistory = computed(() => {
  let filtered = [...scannedQRHistory.value];

  // Filter by search
  if (historySearch.value) {
    const search = historySearch.value.toLowerCase();
    filtered = filtered.filter((item) =>
      item.data.toLowerCase().includes(search),
    );
  }

  return filtered;
});

const filteredHistory = computed(() => {
  // Pastikan history sudah dimuat
  if (checkInHistory.value.length === 0 && typeof window !== "undefined") {
    loadHistory();
  }

  let filtered = [...checkInHistory.value];

  // Sort by checkInTime (terbaru di atas)
  filtered.sort((a, b) => {
    const timeA = new Date(a.checkInTime || a.checkInDate || 0).getTime();
    const timeB = new Date(b.checkInTime || b.checkInDate || 0).getTime();
    return timeB - timeA; // Descending order (newest first)
  });

  // Filter by search
  if (historySearch.value) {
    const search = historySearch.value.toLowerCase();
    filtered = filtered.filter(
      (item) =>
        item.patientId.toLowerCase().includes(search) ||
        (item.queueNumber && item.queueNumber.toLowerCase().includes(search)) ||
        (item.klinikQueueNumber &&
          item.klinikQueueNumber.toLowerCase().includes(search)) ||
        (item.method && item.method.toLowerCase().includes(search)) ||
        (item.klinik && item.klinik.toLowerCase().includes(search)),
    );
  }

  // Filter by status
  if (historyStatusFilter.value) {
    filtered = filtered.filter((item) => {
      if (historyStatusFilter.value === "success") {
        return item.status === "ALLOWED" || item.status === "success";
      } else if (historyStatusFilter.value === "failed") {
        return item.status === "NOT_ALLOWED" || item.status === "failed";
      }
      return true;
    });
  }

  return filtered;
});

// Paginated history
const paginatedHistory = computed(() => {
  const start = (historyPage.value - 1) * historyItemsPerPage.value;
  const end = start + historyItemsPerPage.value;
  return filteredHistory.value.slice(start, end);
});

// Total pages untuk pagination
const totalHistoryPages = computed(() => {
  return Math.ceil(filteredHistory.value.length / historyItemsPerPage.value);
});

// Reset page saat filter berubah
watch([historySearch, historyStatusFilter], () => {
  historyPage.value = 1;
});

// Recent history untuk ditampilkan di sidebar
// Hanya menampilkan riwayat dari hari ini setelah reset (setelah jam 10 malam)
const recentHistory = computed(() => {
  const todayAfterReset = getTodayAfterReset();

  // Filter hanya riwayat dari hari ini setelah reset
  const todayHistory = checkInHistory.value.filter((item) => {
    const itemDate = new Date(item.checkInDate || item.checkInTime);
    const itemDateStr = itemDate.toISOString().split("T")[0];
    return itemDateStr === todayAfterReset;
  });

  // Sort by checkInTime (terbaru di atas)
  return todayHistory.sort((a, b) => {
    const timeA = new Date(a.checkInTime || a.checkInDate || 0).getTime();
    const timeB = new Date(b.checkInTime || b.checkInDate || 0).getTime();
    return timeB - timeA; // Descending order (newest first)
  });
});

// Pagination untuk recent history
const recentHistoryPage = ref(1);
const recentHistoryItemsPerPage = ref(10);

// Paginated recent history
const paginatedRecentHistory = computed(() => {
  const start = (recentHistoryPage.value - 1) * recentHistoryItemsPerPage.value;
  const end = start + recentHistoryItemsPerPage.value;
  return recentHistory.value.slice(start, end);
});

// Total pages untuk recent history pagination
const totalRecentHistoryPages = computed(() => {
  return Math.ceil(
    recentHistory.value.length / recentHistoryItemsPerPage.value,
  );
});

const getStatusColor = (status: string) => {
  if (status === "ALLOWED" || status === "success") return "success";
  if (status === "NOT_ALLOWED") return "warning";
  if (status === "failed") return "error";
  return "warning";
};

const getStatusIcon = (status: string) => {
  if (status === "ALLOWED" || status === "success") return "mdi-check-circle";
  if (status === "NOT_ALLOWED") return "mdi-clock-alert";
  if (status === "failed") return "mdi-close-circle";
  return "mdi-clock-alert";
};

const getStatusText = (status: string) => {
  if (status === "ALLOWED" || status === "success") return "Berhasil";
  if (status === "NOT_ALLOWED") return "Menunggu";
  if (status === "failed") return "Gagal";
  return "Pending";
};

const getStatusClass = (status: string) => {
  if (status === "ALLOWED" || status === "success") return "history-success";
  if (status === "NOT_ALLOWED") return "history-pending";
  if (status === "failed") return "history-failed";
  return "history-pending";
};

const formatDateTime = (dateString: string) => {
  const date = new Date(dateString);
  // Format jam dengan titik dua (HH:MM:SS)
  const timeString = date.toLocaleTimeString("id-ID", {
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit",
  });
  return timeString.replace(/\./g, ":");
};

const formatTime = (dateString: string) => {
  const date = new Date(dateString);
  // Format: HH:MM:SS (menggunakan titik dua)
  const timeString = date.toLocaleTimeString("id-ID", {
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit",
  });
  return timeString.replace(/\./g, ":");
};

const getCurrentTime = () => {
  // Format jam dengan titik dua (HH:MM:SS)
  const timeString = new Date().toLocaleTimeString("id-ID", {
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit",
  });
  return timeString.replace(/\./g, ":");
};

const formatDate = (dateString: string) => {
  const date = new Date(dateString);
  return date.toLocaleDateString("id-ID", {
    day: "2-digit",
    month: "short",
    year: "numeric",
  });
};

// Statistics computed properties
const statsToday = computed(() => {
  const todayAfterReset = getTodayAfterReset();

  return checkInHistory.value.filter((item) => {
    const itemDate = new Date(item.checkInDate || item.checkInTime);
    const itemDateStr = itemDate.toISOString().split("T")[0];

    // Only count items from today (after reset time consideration)
    if (itemDateStr !== todayAfterReset) return false;

    // Only count successful check-ins
    return item.status === "success" || item.status === "ALLOWED";
  }).length;
});

// Get today's date after reset (after 2 AM)
const getTodayAfterReset = (): string => {
  const now = new Date();
  const currentHour = now.getHours();

  // If it's before 2 AM, it's still technically "yesterday" operationally
  if (currentHour < RESET_HOUR) {
    const yesterday = new Date(now);
    yesterday.setDate(yesterday.getDate() - 1);
    return yesterday.toISOString().split("T")[0];
  }

  // If it's 2 AM or later, it's "today"
  return now.toISOString().split("T")[0];
};

const statsCompleted = computed(() => {
  const todayAfterReset = getTodayAfterReset();

  return checkInHistory.value.filter((item) => {
    const itemDate = new Date(item.checkInDate || item.checkInTime);
    const itemDateStr = itemDate.toISOString().split("T")[0];

    // Only count items from today (after reset time consideration)
    if (itemDateStr !== todayAfterReset) return false;

    return item.status === "success" || item.status === "ALLOWED";
  }).length;
});

// Today stats object for sidebar
const todayStats = computed(() => {
  const todayAfterReset = getTodayAfterReset();
  const todayItems = checkInHistory.value.filter((item) => {
    const itemDate = new Date(item.checkInDate || item.checkInTime);
    const itemDateStr = itemDate.toISOString().split("T")[0];
    return itemDateStr === todayAfterReset;
  });

  const successItems = todayItems.filter(
    (item) => item.status === "success" || item.status === "ALLOWED",
  );

  const failedItems = todayItems.filter(
    (item) =>
      item.status === "failed" ||
      item.status === "NOT_ALLOWED" ||
      item.status === "error",
  );

  const qrItems = todayItems.filter((item) => item.method === "QR");
  const manualItems = todayItems.filter((item) => item.method === "Manual");

  return {
    total: todayItems.length,
    success: successItems.length,
    failed: failedItems.length,
    qr: qrItems.length,
    manual: manualItems.length,
  };
});

const statsWaiting = computed(() => {
  // Ambil data menunggu dari queueStore untuk stage 'loket'
  // Menghitung pasien dengan status 'menunggu' (belum dipanggil) atau 'anjungan' (sudah dipanggil tapi belum check-in)
  // Di halaman CheckInPasien, kita menghitung total yang masih menunggu check-in (belum + sudah dipanggil)
  try {
    const loketPatients = queueStore.getPatientsByStage("loket");
    const menungguPatients = loketPatients.value.menunggu || [];
    const anjunganPatients = loketPatients.value.anjungan || [];

    // Total pasien yang masih menunggu check-in (belum dipanggil + sudah dipanggil tapi belum check-in)
    return menungguPatients.length + anjunganPatients.length;
  } catch (error) {
    console.error("Error calculating statsWaiting:", error);
    return 0;
  }
});

// Load history on mount
if (typeof window !== "undefined") {
  loadHistory();
  loadScannedQRHistory();
  loadSuccessfulScans();
}

// Calculate sticky top offset based on header height (from AdminLoket.vue pattern)
const stickyTopOffset = ref(100);

const updateStickyOffset = () => {
  const header = document.querySelector(".page-header") as HTMLElement;
  if (header) {
    const headerHeight = header.offsetHeight;
    const containerPadding = 16;
    stickyTopOffset.value = headerHeight + containerPadding + 8; // header + padding + minimal space
  }
};

onMounted(() => {
  updateStickyOffset();
  window.addEventListener("resize", updateStickyOffset);
  // Use nextTick to ensure DOM is fully rendered
  setTimeout(updateStickyOffset, 100);
});

onUnmounted(() => {
  window.removeEventListener("resize", updateStickyOffset);
});
</script>

<style scoped lang="scss">
@use "@/assets/scss/colors" as *;

/* Page Container - Same pattern as AdminLoket.vue */
.checkin-page-container {
  background: $neutral-100;
  min-height: 100vh;
  max-height: 100vh;
  padding: 0 24px;
  max-width: 100vw;
  box-sizing: border-box;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* Header Full Width - No padding from edges */
.checkin-page-container :deep(.page-header) {
  margin-left: -4px;
  margin-right: -4px;
  border-radius: 0 !important;
  width: calc(100% + 8px);
}

.checkin-page-container::before {
  content: "";
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background:
    radial-gradient(
      circle at 20% 50%,
      rgba(21, 101, 192, 0.05) 0%,
      transparent 50%
    ),
    radial-gradient(
      circle at 80% 80%,
      rgba(21, 101, 192, 0.05) 0%,
      transparent 50%
    );
  pointer-events: none;
  z-index: 0;
}

/* Removed main-card - now using separate cards like AdminLoket.vue */

/* Header Modern Minimalis */
.header-modern {
  background: linear-gradient(135deg, $primary-600 0%, $primary-700 100%);
  padding: 8px 20px 6px;
  position: relative;
  overflow: hidden;
}

/* Remove rounded edges from PageHeader component */
:deep(.page-header) {
  border-radius: 0 !important;
}

/* Replace icon with logo like in AntreanMasuk */
:deep(.header-icon) {
  background: rgba(255, 255, 255, 0.95) !important;
  border-radius: 50% !important;
  width: 60px !important;
  height: 60px !important;
  padding: 4px !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  backdrop-filter: blur(10px) !important;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important;
  overflow: visible !important;
}

:deep(.header-logo) {
  width: 52px !important;
  height: 52px !important;
  object-fit: contain !important;
  border-radius: 50% !important;
  max-width: 100% !important;
  max-height: 100% !important;
}

.header-modern::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: radial-gradient(
    circle at 50% 0%,
    rgba(255, 255, 255, 0.1) 0%,
    transparent 70%
  );
  pointer-events: none;
}

.header-content {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-bottom: 0;
}

.icon-circle {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.2);
  backdrop-filter: blur(10px);
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid rgba(255, 255, 255, 0.3);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
}

.header-text {
  text-align: left;
}

.title-modern {
  font-size: 18px;
  font-weight: 700;
  color: $neutral-100;
  margin: 0;
  letter-spacing: -0.5px;
}

.subtitle-modern {
  font-size: 12px;
  color: rgba(255, 255, 255, 0.85);
  margin: 1px 0 0;
  font-weight: 400;
}

/* Tabs Modern */
.tabs-modern {
  position: relative;
  z-index: 1;
}

.tabs-modern :deep(.v-tab) {
  text-transform: none;
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.2px;
  color: rgba(255, 255, 255, 0.8);
  min-width: auto;
  padding: 0 16px;
  transition: all 0.3s ease;
}

.tabs-modern :deep(.v-tab--selected) {
  color: $secondary-500 !important;
  background: rgba($secondary-500, 0.2);
  border-radius: 12px;
  backdrop-filter: blur(10px);
}

.tabs-modern :deep(.v-tab--selected .v-icon) {
  color: $secondary-500 !important;
}

.tabs-modern :deep(.v-tab--selected span) {
  color: $secondary-500 !important;
}

.tabs-modern :deep(.v-slider) {
  display: none;
}

.tab-modern {
  display: flex;
  align-items: center;
  gap: 6px;
}

.tab-modern .v-icon {
  font-size: 18px !important;
}

/* Content Area */
.content-modern {
  background: $neutral-100;
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  min-height: 0;
}

.content-modern::-webkit-scrollbar {
  width: 4px;
}

.content-modern::-webkit-scrollbar-track {
  background: transparent;
}

.content-modern::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, 0.2);
  border-radius: 2px;
}

.tab-content {
  animation: fadeIn 0.4s ease-out;
  min-height: 100%;
  width: 100%;
}

/* Removed old two-column layout - now using AdminLoket.vue pattern */

/* History Section Styling - Modern Design */
.history-section {
  border-top: 2px solid rgba($primary-600, 0.1);
  padding-top: 24px;
  margin-top: 32px;
  background: linear-gradient(to bottom, transparent, rgba($primary-50, 0.3));
  border-radius: 16px 16px 0 0;
  padding: 24px 20px 20px;
  margin-left: -20px;
  margin-right: -20px;
  margin-bottom: -20px;
}

.recent-history-list {
  max-height: 650px;
  overflow-y: auto;
  overflow-x: hidden;
  padding-right: 4px;
  min-height: 0;
}

.recent-history-list::-webkit-scrollbar {
  width: 4px;
}

.recent-history-list::-webkit-scrollbar-track {
  background: transparent;
}

.recent-history-list::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, 0.2);
  border-radius: 2px;
}

.history-item-content {
  width: 100%;
  position: relative;
  padding-left: 0;
}

.history-item-compact :deep(.v-card-text) {
  padding: 16px 20px !important;
  border-left: none !important;
  position: relative;
  z-index: 0;
}

.history-item-compact {
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  overflow: hidden;
  background: $neutral-100 !important;
  border: 1px solid rgba(0, 0, 0, 0.08) !important;
  border-radius: 12px !important;
  border-left: 4px solid transparent !important;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04) !important;
  margin-bottom: 12px !important;
}

.history-item-compact::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: transparent;
  z-index: 1;
  border-radius: 8px 0 0 8px;
}

.history-item-compact :deep(.v-card__underlay) {
  display: none;
}

.history-item-compact :deep(.v-card__border) {
  border: none !important;
}

.history-item-compact:hover {
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.1) !important;
  transform: translateY(-2px);
  border-color: rgba(0, 0, 0, 0.12) !important;
}

.history-item-compact.history-success::before {
  background: $success-500 !important;
}

.history-item-compact.history-success {
  background: rgba($success-100, 0.5) !important;
  border-left-color: $success-500 !important;
}

.history-item-compact.history-success :deep(.v-card-text) {
  background: transparent !important;
}

.history-item-compact.history-failed::before {
  background: $danger-500 !important;
}

.history-item-compact.history-failed {
  background: rgba($danger-100, 0.5) !important;
  border-left-color: $danger-500 !important;
}

.history-item-compact.history-failed :deep(.v-card-text) {
  background: transparent !important;
}

.history-item-compact.history-pending::before {
  background: $secondary-500 !important;
}

.history-item-compact.history-pending {
  background: rgba($secondary-100, 0.5) !important;
  border-left-color: $secondary-500 !important;
}

.history-item-compact.history-pending :deep(.v-card-text) {
  background: transparent !important;
}

/* Status Badge */
.history-status-badge {
  width: 24px;
  height: 24px;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.history-status-badge.status-success {
  background: rgba($success-500, 0.15);
  color: $success-600;
}

.history-status-badge.status-error,
.history-status-badge.status-warning {
  background: rgba($danger-500, 0.15);
  color: $danger-600;
}

.history-status-badge.status-warning {
  background: rgba($secondary-500, 0.15);
  color: $secondary-600;
}

.history-status-text {
  font-size: 12px;
  font-weight: 600;
  line-height: 1.2;
  margin-bottom: 0;
}

.history-status-text.text-success {
  color: $success-600;
}

.history-status-text.text-error {
  color: $danger-600;
}

.history-status-text.text-warning {
  color: $secondary-600;
}

.history-method-text {
  font-size: 10px;
  color: $neutral-600;
  font-weight: 400;
}

/* Time Badge */
.history-time-badge {
  display: flex;
  align-items: center;
  padding: 2px 6px;
  background: $neutral-300;
  border-radius: 4px;
  font-size: 10px;
  color: $neutral-700;
  font-weight: 500;
}

/* Klinik Badge */
.history-klinik-badge {
  display: flex;
  align-items: center;
  padding: 2px 6px;
  background: rgba($primary-500, 0.1);
  color: $primary-600;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 500;
}

/* Queue Badge */
.history-queue-badge {
  display: flex;
  align-items: center;
  padding: 2px 6px;
  background: rgba($secondary-500, 0.1);
  color: $secondary-600;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 500;
}

/* Info Badge (Patient ID & Payment) */
.history-info-badge {
  display: flex;
  align-items: center;
  padding: 2px 6px;
  background: $neutral-300;
  color: $neutral-700;
  border-radius: 4px;
  font-size: 10px;
  font-weight: 500;
}

.border-top-history {
  border-top: 1px solid $neutral-400 !important;
  margin-top: 2px;
}

/* Gap utility untuk flex-wrap */
.gap-1 {
  gap: 4px;
}

.gap-2 {
  gap: 8px;
}

/* Removed old responsive layout - now handled by content-grid */

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Status Header - Modern Design */
.status-header {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-start;
  gap: 12px;
  padding: 14px 16px;
  background: linear-gradient(
    135deg,
    rgba($primary-50, 0.8) 0%,
    rgba($primary-100, 0.6) 100%
  );
  border-radius: 12px;
  border: 1px solid rgba($primary-600, 0.12);
  box-shadow:
    0 4px 12px rgba($primary-600, 0.08),
    inset 0 1px 0 rgba(255, 255, 255, 0.8);
  text-align: left;
  position: relative;
  overflow: hidden;
  transition: all 0.3s ease;
  min-height: 72px;
  max-height: 72px;
  flex-shrink: 0;
}

.status-header::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: linear-gradient(90deg, $primary-600 0%, $primary-400 100%);
  opacity: 0.6;
}

.status-header:hover {
  box-shadow:
    0 6px 16px rgba($primary-600, 0.12),
    inset 0 1px 0 rgba(255, 255, 255, 0.8);
  transform: translateY(-1px);
}

.status-icon-wrapper {
  width: 40px;
  height: 40px;
  min-width: 40px;
  min-height: 40px;
  max-width: 40px;
  max-height: 40px;
  border-radius: 10px;
  background: linear-gradient(135deg, $primary-600 0%, $primary-700 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 12px rgba($primary-600, 0.25);
  flex-shrink: 0;
  position: relative;
}

.status-icon-wrapper::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 12px;
  padding: 1px;
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.3), transparent);
  -webkit-mask:
    linear-gradient(#fff 0 0) content-box,
    linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
}

.status-icon-wrapper .v-icon {
  color: white !important;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.2));
}

.status-text {
  flex: 1;
  text-align: left;
}

.status-title {
  font-size: 15px !important;
  font-weight: 700 !important;
  color: $neutral-900 !important;
  margin: 0 0 2px !important;
  letter-spacing: -0.2px !important;
  line-height: 1.3 !important;
}

.status-subtitle {
  font-size: 12px;
  color: $neutral-700;
  margin: 0;
  line-height: 1.5;
  font-weight: 400;
}

/* QR Scanner Modern */
.qr-scanner-container {
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 24px 0;
  padding: 6px;
}

.qr-placeholder {
  width: 100%;
  max-width: 320px;
  min-height: 200px;
  aspect-ratio: 1 / 1;
  background: linear-gradient(
    135deg,
    rgba($primary-50, 0.8) 0%,
    rgba($primary-100, 0.6) 100%
  );
  border-radius: 20px;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border: 3px dashed rgba($primary-600, 0.3);
  box-shadow:
    0 8px 24px rgba($primary-600, 0.15),
    inset 0 2px 8px rgba(255, 255, 255, 0.5);
  margin: 0 auto;
  transition: all 0.3s ease;
}

.qr-placeholder:hover {
  border-color: rgba($primary-600, 0.5);
  box-shadow:
    0 12px 32px rgba($primary-600, 0.2),
    inset 0 2px 8px rgba(255, 255, 255, 0.5);
  transform: translateY(-2px);
}

.qr-reader-container {
  width: 100%;
  max-width: 320px;
  margin: 0 auto;
  position: relative;
  overflow: visible;
}

.qr-reader-wrapper {
  width: 100%;
  max-width: 320px;
  aspect-ratio: 1 / 1;
  border-radius: 20px;
  overflow: hidden;
  box-shadow:
    0 12px 40px rgba(0, 0, 0, 0.2),
    0 4px 16px rgba($primary-600, 0.15);
  background: #000;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 3px solid rgba(21, 101, 192, 0.3);
  margin: 0 auto;
  transition: all 0.3s ease;
}

.qr-reader-wrapper:hover {
  box-shadow:
    0 16px 48px rgba(0, 0, 0, 0.25),
    0 6px 20px rgba($primary-600, 0.2);
  border-color: rgba(21, 101, 192, 0.5);
}

.qr-reader-wrapper :deep(video) {
  width: 100% !important;
  height: 100% !important;
  border-radius: 16px;
  display: block !important;
  object-fit: contain;
  background: #000;
  aspect-ratio: 1 / 1;
}

.qr-reader-wrapper.is-front :deep(video) {
  transform: scaleX(-1); /* Mirror effect only for front camera */
  -webkit-transform: scaleX(-1);
}

.qr-reader-wrapper :deep(canvas) {
  display: none !important;
}

.qr-reader-wrapper :deep(#qr-reader__dashboard) {
  display: none !important;
}

.qr-reader-wrapper :deep(#qr-reader__scan_region) {
  border-radius: 16px;
  border: 3px solid rgba($primary-600, 0.8) !important;
  box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.4) !important;
  position: relative;
}

.qr-reader-wrapper :deep(#qr-reader__scan_region::before) {
  content: "";
  position: absolute;
  top: -3px;
  left: -3px;
  right: -3px;
  bottom: -3px;
  border: 3px solid rgba(21, 101, 192, 0.8);
  border-radius: 16px;
  animation: pulse-border 2s ease-in-out infinite;
}

@keyframes pulse-border {
  0%,
  100% {
    opacity: 1;
    transform: scale(1);
  }
  50% {
    opacity: 0.7;
    transform: scale(1.02);
  }
}

.qr-reader-wrapper :deep(#qr-reader__scan_region video) {
  border-radius: 16px;
  width: 100% !important;
  height: 100% !important;
  aspect-ratio: 1 / 1;
  object-fit: contain;
}

.qr-reader-wrapper.is-front :deep(#qr-reader__scan_region video) {
  transform: scaleX(-1); /* Mirror effect only for front camera */
  -webkit-transform: scaleX(-1);
}

.scanner-status {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 6px;
  font-size: 12px;
}

.scanner-instruction {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  margin-top: 8px;
  padding: 6px 10px;
  background: linear-gradient(
    135deg,
    rgba($primary-600, 0.1) 0%,
    rgba($primary-700, 0.1) 100%
  );
  border-radius: 8px;
  color: $primary-600;
  font-weight: 500;
  font-size: 11px;
  line-height: 1.4;
  text-align: left;
  border: 1px solid rgba($primary-600, 0.2);
  max-width: 320px;
  margin-left: auto;
  margin-right: auto;
}

.scanner-instruction .v-icon {
  flex-shrink: 0;
  margin-right: 8px;
}

.scanner-loading-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.7);
  border-radius: 16px;
  z-index: 10;
}

.scanner-overlay {
  position: absolute;
  width: 80%;
  height: 80%;
}

.corner {
  position: absolute;
  width: 40px;
  height: 40px;
  border: 3px solid $primary-600;
}

.corner-tl {
  top: 0;
  left: 0;
  border-right: none;
  border-bottom: none;
  border-radius: 8px 0 0 0;
}

.corner-tr {
  top: 0;
  right: 0;
  border-left: none;
  border-bottom: none;
  border-radius: 0 8px 0 0;
}

.corner-bl {
  bottom: 0;
  left: 0;
  border-right: none;
  border-top: none;
  border-radius: 0 0 0 8px;
}

.corner-br {
  bottom: 0;
  right: 0;
  border-left: none;
  border-top: none;
  border-radius: 0 0 8px 0;
}

.scan-line {
  position: absolute;
  width: 100%;
  height: 2px;
  background: linear-gradient(90deg, transparent, $primary-600, transparent);
  top: 0;
  animation: scan 2s linear infinite;
  box-shadow: 0 0 10px $primary-600;
}

@keyframes scan {
  0% {
    top: 0;
  }
  100% {
    top: 100%;
  }
}

.qr-icon {
  position: relative;
  z-index: 1;
  animation: breathe 2s ease-in-out infinite;
}

@keyframes breathe {
  0%,
  100% {
    opacity: 0.6;
  }
  50% {
    opacity: 1;
  }
}

/* Modern Buttons */
.btn-primary-modern {
  background: linear-gradient(135deg, #1565c0 0%, #0d47a1 100%) !important;
  color: $neutral-100 !important;
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0.5px;
  border-radius: 12px !important;
  padding: 14px 28px !important;
  min-height: 50px !important;
  min-width: 44px !important;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow:
    0 6px 20px rgba($primary-600, 0.35),
    0 2px 8px rgba($primary-600, 0.2) !important;
  position: relative;
  overflow: hidden;
}

.btn-primary-modern::before {
  content: "";
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(
    90deg,
    transparent,
    rgba(255, 255, 255, 0.2),
    transparent
  );
  transition: left 0.5s;
}

.btn-primary-modern:hover::before {
  left: 100%;
}

.btn-primary-modern:hover {
  transform: translateY(-3px);
  box-shadow:
    0 10px 28px rgba($primary-600, 0.45),
    0 4px 12px rgba($primary-600, 0.25) !important;
}

.btn-primary-modern:active {
  transform: translateY(-1px);
  box-shadow: 0 4px 16px rgba($primary-600, 0.3) !important;
}

.btn-primary-modern:disabled {
  opacity: 0.6;
  transform: none !important;
  cursor: not-allowed;
}

.btn-primary-modern:focus-visible,
.btn-stop-modern:focus-visible {
  outline: 3px solid $primary-600;
  outline-offset: 3px;
  border-radius: 4px;
}

.btn-stop-modern {
  background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%) !important;
  color: $neutral-100 !important;
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0.5px;
  border-radius: 12px !important;
  padding: 14px 28px !important;
  min-height: 50px !important;
  min-width: 44px !important;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow:
    0 6px 20px rgba($danger-500, 0.35),
    0 2px 8px rgba($danger-500, 0.2) !important;
  position: relative;
  overflow: hidden;
}

.btn-stop-modern::before {
  content: "";
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(
    90deg,
    transparent,
    rgba(255, 255, 255, 0.2),
    transparent
  );
  transition: left 0.5s;
}

.btn-stop-modern:hover::before {
  left: 100%;
}

.btn-stop-modern:hover {
  transform: translateY(-3px);
  box-shadow:
    0 10px 28px rgba($danger-500, 0.45),
    0 4px 12px rgba($danger-500, 0.25) !important;
}

.btn-stop-modern:active {
  transform: translateY(-1px);
  box-shadow: 0 4px 16px rgba($danger-500, 0.3) !important;
}

.action-buttons {
  margin-top: 24px;
  margin-bottom: 8px;
  display: flex;
  justify-content: center;
}

.btn-centered {
  width: auto !important;
  min-width: 240px !important;
  max-width: 320px !important;
  margin: 0 auto !important;
  display: block !important;
}

.btn-centered-small {
  width: auto !important;
  min-width: 180px !important;
  margin: 0 auto;
  display: block;
}

.btn-test-camera {
  border-color: #1565c0 !important;
  color: #1565c0 !important;
}

.btn-test-camera :deep(.v-btn__content) {
  color: #1565c0 !important;
}

.btn-test-camera :deep(.v-icon) {
  color: #1565c0 !important;
  opacity: 1 !important;
}

/* Focus Indicators for Accessibility */
.v-btn:focus-visible,
.v-text-field:focus-within,
.v-select:focus-within {
  outline: 3px solid $primary-600;
  outline-offset: 2px;
  border-radius: 4px;
}

/* Modern Inputs - Enhanced Design */
.input-modern :deep(.v-field) {
  border-radius: 14px;
  font-size: 15px;
  background: $neutral-100;
  border: 2px solid rgba($primary-600, 0.15);
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}

.input-modern :deep(.v-field:hover) {
  border-color: rgba($primary-600, 0.3);
  box-shadow: 0 4px 12px rgba($primary-600, 0.08);
}

.input-modern :deep(.v-field--focused) {
  background: $neutral-100;
  border-color: $primary-600;
  box-shadow:
    0 0 0 4px rgba(21, 101, 192, 0.12),
    0 4px 16px rgba($primary-600, 0.15);
  transform: translateY(-1px);
}

.input-modern :deep(.v-field__input) {
  padding-top: 12px;
  padding-bottom: 12px;
}

.input-modern :deep(.v-label) {
  font-weight: 500;
  color: $neutral-700;
}

.info-card {
  display: flex;
  justify-content: center;
  margin-top: 20px;
}

.info-alert-centered {
  width: 100%;
}

.info-alert-centered :deep(.v-alert__content) {
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  width: 100% !important;
}

.info-alert-centered {
  border-radius: 12px !important;
  border: 1px solid rgba($primary-600, 0.15) !important;
  background: linear-gradient(
    135deg,
    rgba($primary-50, 0.6),
    rgba($primary-100, 0.4)
  ) !important;
}

.history-header-icon {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  background: linear-gradient(
    135deg,
    rgba($primary-600, 0.1),
    rgba($primary-400, 0.1)
  );
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 8px rgba($primary-600, 0.1);
}

.empty-history-icon {
  opacity: 0.6;
  filter: grayscale(0.3);
}

.empty-history-state {
  background: linear-gradient(to bottom, rgba($primary-50, 0.2), transparent);
  border-radius: 12px;
  padding: 32px 20px !important;
}

.quick-actions {
  background: linear-gradient(to bottom, rgba($primary-50, 0.3), transparent);
  border-radius: 16px;
  padding: 20px;
  margin-top: 24px;
}

.quick-actions .v-btn {
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  border-radius: 12px !important;
  border: 2px solid rgba($primary-600, 0.2) !important;
  background: $neutral-100 !important;
  font-weight: 500 !important;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04) !important;
}

.quick-actions .v-btn:hover {
  transform: translateY(-2px);
  border-color: $primary-600 !important;
  background: linear-gradient(
    135deg,
    rgba($primary-50, 0.8),
    rgba($primary-100, 0.6)
  ) !important;
  box-shadow: 0 6px 16px rgba($primary-600, 0.2) !important;
  color: $primary-700 !important;
}

.quick-actions .v-btn :deep(.v-icon) {
  opacity: 1 !important;
  color: inherit !important;
}

.quick-actions .v-btn[color="primary"] {
  color: #1565c0 !important;
  border-color: #1565c0 !important;
}

.quick-actions .v-btn[color="primary"] :deep(.v-icon) {
  color: #1565c0 !important;
}

.qr-code-container {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 16px;
  background: $neutral-100;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.qr-code-container :deep(canvas) {
  border-radius: 8px;
}

.qr-display {
  animation: slideUp 0.5s ease-out;
}

.blur-dialog :deep(.v-overlay__scrim) {
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

.dialog-card {
  overflow: hidden;
  animation: popIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
  border-radius: 16px !important;
}

@keyframes popIn {
  0% {
    opacity: 0;
    transform: scale(0.8) translateY(20px);
  }
  100% {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
}

.dialog-header {
  position: relative;
  overflow: hidden;
  border-radius: 16px 16px 0 0;
}

.dialog-header::before {
  display: none;
}

.icon-wrapper {
  display: inline-block;
}

.dialog-icon {
  filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.3));
}

.success-header {
  background: linear-gradient(135deg, $success-400 0%, $success-600 100%);
}

.warning-header {
  background: linear-gradient(135deg, $secondary-400 0%, $secondary-500 100%);
}

.error-header {
  background: linear-gradient(135deg, $danger-400 0%, $danger-600 100%);
}

.icon-bg {
  width: 80px;
  height: 80px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
}

.icon-bg-success {
  background: linear-gradient(135deg, $success-400 0%, $success-600 100%);
}

.icon-bg-warning {
  background: linear-gradient(135deg, $secondary-400 0%, $secondary-500 100%);
}

.icon-bg-error {
  background: linear-gradient(135deg, $danger-400 0%, $danger-600 100%);
}

.instruction-box {
  border: 1px solid transparent;
}

.instruction-success {
  background: rgba($success-100, 0.5) !important;
  border-color: rgba($success-500, 0.2) !important;
}

.instruction-warning {
  background: rgba($secondary-100, 0.5) !important;
  border-color: rgba($secondary-500, 0.2) !important;
}

.dialog-button {
  text-transform: none;
  letter-spacing: 0.5px;
  font-weight: 600;
  transition: all 0.3s ease;
}

.dialog-button:hover {
  transform: translateY(-2px);
}

/* Patient Info Card Styling */
.patient-info-card {
  background: rgba($neutral-300, 0.8) !important;
  border-color: rgba(0, 0, 0, 0.08) !important;
}

.patient-info-label {
  color: $neutral-600 !important;
  font-weight: 500;
  opacity: 0.9;
}

.patient-info-value {
  color: $neutral-700 !important;
  font-weight: 500 !important;
  opacity: 0.85;
}

.patient-info-icon {
  opacity: 0.7;
}

/* Stats Footer Modern */
.stats-footer-modern {
  animation: slideUp 0.5s ease-out 0.3s both;
}

/* Content Grid - Same pattern as AdminLoket.vue */
.content-grid {
  margin: 0;
  flex: 1;
  min-height: 0;
  overflow: visible;
  align-items: stretch;
  flex-wrap: nowrap !important;
}

@media (max-width: 1263px) {
  .content-grid {
    flex-wrap: wrap !important;
  }
}

.content-grid > .v-col {
  padding: 6px;
}

.content-grid > .v-col:first-child {
  padding-left: 6px;
}

.content-grid > .v-col:last-child {
  padding-right: 6px;
}

/* Ensure proper column order */

.sticky-column {
  position: relative;
}

/* Manual Input Column */
.content-grid > .v-col:nth-child(2) {
}

/* QR Scan Card */
.qr-scan-card {
  background: rgba(255, 255, 255, 0.95) !important;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba($primary-300, 0.2);
  border-radius: 12px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
  display: flex;
  flex-direction: column;
  height: 100%;
}

/* Manual Input Card */
.manual-input-card {
  background: rgba(255, 255, 255, 0.95) !important;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba($primary-300, 0.2);
  border-radius: 12px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
  display: flex;
  flex-direction: column;
  height: 100%;
}

/* Column classes for equal height */
.sticky-column,
.manual-input-column {
  display: flex;
  flex-direction: column;
}

.sticky-wrapper {
  display: flex;
  flex-direction: column;
  flex: 1;
  width: 100%;
}

/* Hide right sidebar on all screens */
.stats-sidebar-right {
  display: none !important;
}

/* Content Grid */
.content-grid {
  flex: 1;
  min-height: 0;
  overflow: visible;
}

:deep(.stats-sidebar-right) {
  overflow: visible !important;
}

@media (min-width: 1264px) {
  .stats-sidebar-right {
    display: flex !important;
    visibility: visible !important;
    opacity: 1 !important;
    align-items: flex-end;
    justify-content: flex-end;
    flex-shrink: 0 !important;
    flex-grow: 0 !important;
    width: auto !important;
    max-width: 160px !important;
    min-width: 140px !important;
    z-index: 10;
    margin-left: auto;
  }

  .stats-sidebar-enhanced {
    display: flex !important;
    visibility: visible !important;
    opacity: 1 !important;
    margin-left: auto;
  }
}

@media (min-width: 1264px) {
  .content-grid {
    flex-wrap: nowrap !important;
  }

  .stats-sidebar-right {
    display: flex !important;
  }
}

/* Sticky Wrapper (from AdminLoket.vue pattern) */
.sticky-wrapper {
  position: -webkit-sticky; /* Safari */
  position: sticky;
  top: 16px;
  z-index: 10;
  align-self: flex-start;
}

@media (min-width: 1264px) {
  .sticky-wrapper {
    top: 20px;
  }
}

/* Compact Alert for Camera Warning */
.compact-alert {
  padding: 4px 8px !important;
  font-size: 10px !important;
  min-height: 48px !important;
  max-height: 48px !important;
  border-radius: 8px !important;

  :deep(.v-alert__prepend) {
    margin-right: 4px !important;
  }

  :deep(.v-icon) {
    font-size: 16px !important;
  }

  :deep(p) {
    font-size: 9px !important;
    line-height: 1.2 !important;
    margin-bottom: 0 !important;
  }

  :deep(.font-weight-bold) {
    font-size: 11px !important;
    margin-bottom: 2px !important;
  }

  :deep(.text-body-2) {
    font-size: 9px !important;
  }

  :deep(.v-alert__content) {
    padding: 0 !important;
  }
}

@media (max-width: 960px) {
  .checkin-page-container {
    padding: 0 8px 8px 8px;
    max-height: none !important;
    overflow-y: auto !important;
  }

  .checkin-page-container :deep(.page-header) {
    margin-left: -8px;
    margin-right: -8px;
    width: calc(100% + 16px);
  }

  .content-grid {
    flex-direction: column !important;
    margin: 0 4px !important;
  }

  .sticky-column,
  .manual-input-column {
    width: 100% !important;
    max-width: 100% !important;
    margin-bottom: 8px;
  }

  .qr-scan-card,
  .manual-input-card {
    max-height: 40vh !important;
    overflow-y: auto !important;
    padding: 12px;
  }

  /* Alert box mobile styles */
  :deep(.v-alert) {
    font-size: 12px !important;
    padding: 10px 12px !important;
  }

  :deep(.v-alert .v-alert__prepend) {
    margin-right: 8px !important;
  }

  :deep(.v-alert .v-icon) {
    font-size: 20px !important;
  }

  :deep(.v-alert p) {
    font-size: 11px !important;
    line-height: 1.4 !important;
  }

  :deep(.v-alert .font-weight-bold) {
    font-size: 13px !important;
  }

  /* QR Scanner mobile */
  .qr-scanner-container {
    margin: 12px 0;
  }

  .qr-placeholder {
    max-width: 280px !important;
    min-height: 180px !important;
  }

  /* Buttons mobile */
  :deep(.v-btn) {
    font-size: 13px !important;
    min-height: 44px !important;
  }

  /* Input fields mobile */
  :deep(.v-text-field) {
    font-size: 14px !important;
  }

  :deep(.v-text-field .v-field__input) {
    min-height: 44px !important;
    padding: 8px 12px !important;
  }

  .sticky-wrapper {
    position: relative;
    top: 0;
    max-height: none;
  }

  .stats-footer-horizontal {
    flex-wrap: wrap !important;
    gap: 6px;
    padding: 8px;
  }

  .stat-item-footer-enhanced {
    min-width: calc(50% - 6px);
    flex: 1 1 calc(50% - 6px);
    padding: 8px 6px;
  }

  .stat-value-footer-enhanced {
    font-size: 13px;
  }

  .stat-label-footer-enhanced {
    font-size: 9px;
  }

  .stat-icon-footer-enhanced .v-icon {
    font-size: 18px !important;
  }
}

/* Enhanced Sidebar Design */
.stats-sidebar-enhanced {
  display: flex !important;
  flex-direction: column;
  width: 100%;
  max-width: 170px;
  min-width: 160px;
  height: fit-content;
  background: linear-gradient(
    180deg,
    rgba($primary-50, 0.98) 0%,
    rgba($primary-100, 0.92) 100%
  );
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-radius: 16px;
  box-shadow:
    0 4px 20px rgba($primary-600, 0.15),
    0 2px 8px rgba($primary-400, 0.1),
    inset 0 1px 0 rgba(255, 255, 255, 0.95);
  border: 1px solid rgba($primary-300, 0.4);
  overflow: visible;
  position: relative;
  visibility: visible !important;
  opacity: 1 !important;

  &::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 4px;
    background: linear-gradient(
      90deg,
      $primary-600 0%,
      $primary-500 50%,
      $primary-400 100%
    );
    opacity: 0.9;
  }

  &::after {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: radial-gradient(
      circle at 50% 10%,
      rgba($primary-200, 0.4) 0%,
      transparent 60%
    );
    pointer-events: none;
  }
}

/* Sidebar Header */
.sidebar-header {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px 6px 6px;
  border-bottom: 1px solid rgba($primary-300, 0.3);
  position: relative;
  z-index: 2;

  .sidebar-title {
    font-size: 8px;
    font-weight: 700;
    color: $primary-700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
  }
}

/* Stats Container */
.stats-container {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 8px 6px;
  position: relative;
  z-index: 2;
}

.stats-sidebar-discord {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 12px 8px;
  width: 100%;
  max-width: 100px;
  height: fit-content;
  background: linear-gradient(
    180deg,
    rgba($primary-50, 0.95) 0%,
    rgba($primary-100, 0.85) 100%
  );
  border-radius: 12px;
  box-shadow:
    0 2px 8px rgba(0, 0, 0, 0.08),
    inset 0 1px 0 rgba(255, 255, 255, 0.9);
  border: 1px solid rgba($primary-600, 0.1);
  position: relative;
  overflow: hidden;

  &::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    background: linear-gradient(90deg, $primary-600 0%, $primary-400 100%);
  }
}

@media (min-width: 1264px) {
  .stats-sidebar-discord {
    position: -webkit-sticky;
    position: sticky;
    top: 20px;
    align-self: flex-start;
  }

  .stats-sidebar-enhanced {
    max-height: calc(100vh - 40px);
    overflow-y: auto;
    overflow-x: visible;

    &::-webkit-scrollbar {
      width: 3px;
    }

    &::-webkit-scrollbar-track {
      background: transparent;
    }

    &::-webkit-scrollbar-thumb {
      background: rgba($primary-400, 0.3);
      border-radius: 10px;

      &:hover {
        background: rgba($primary-500, 0.5);
      }
    }
  }
}

/* Enhanced Stat Item Design */
.stat-item-enhanced {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  width: 100%;
  padding: 8px 5px;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.7);
  border: 1px solid rgba($primary-300, 0.25);
  overflow: hidden;

  &::before {
    content: "";
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 3px;
    height: 0;
    background: currentColor;
    border-radius: 0 3px 3px 0;
    transition: height 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    opacity: 0;
  }

  &:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba($primary-600, 0.2);

    &::before {
      height: 40px;
      opacity: 1;
    }
  }
}

.stat-item-enhanced.stat-item-primary {
  background: linear-gradient(
    135deg,
    rgba($primary-100, 0.8) 0%,
    rgba($primary-50, 0.6) 100%
  );
  border-color: rgba($primary-400, 0.3);

  &::before {
    background: linear-gradient(180deg, $primary-600 0%, $primary-500 100%);
  }

  &:hover {
    background: linear-gradient(
      135deg,
      rgba($primary-200, 0.9) 0%,
      rgba($primary-100, 0.7) 100%
    );
    border-color: rgba($primary-500, 0.5);
  }
}

.stat-item-enhanced.stat-item-success {
  background: linear-gradient(
    135deg,
    rgba($success-100, 0.8) 0%,
    rgba($success-200, 0.6) 100%
  );
  border-color: rgba($success-400, 0.3);

  &::before {
    background: linear-gradient(180deg, $success-600 0%, $success-500 100%);
  }

  &:hover {
    background: linear-gradient(
      135deg,
      rgba($success-200, 0.9) 0%,
      rgba($success-100, 0.7) 100%
    );
    border-color: rgba($success-500, 0.5);
  }
}

.stat-item-enhanced.stat-item-warning {
  background: linear-gradient(
    135deg,
    rgba($secondary-100, 0.8) 0%,
    rgba($secondary-50, 0.6) 100%
  );
  border-color: rgba($secondary-400, 0.3);

  &::before {
    background: linear-gradient(180deg, $secondary-600 0%, $secondary-500 100%);
  }

  &:hover {
    background: linear-gradient(
      135deg,
      rgba($secondary-200, 0.9) 0%,
      rgba($secondary-100, 0.7) 100%
    );
    border-color: rgba($secondary-500, 0.5);
  }
}

.stat-item-enhanced.stat-item-error {
  background: linear-gradient(
    135deg,
    rgba($danger-100, 0.8) 0%,
    rgba($danger-200, 0.5) 100%
  );
  border-color: rgba($danger-400, 0.3);

  &::before {
    background: linear-gradient(180deg, $danger-600 0%, $danger-500 100%);
  }

  &:hover {
    background: linear-gradient(
      135deg,
      rgba($danger-200, 0.9) 0%,
      rgba($danger-100, 0.7) 100%
    );
    border-color: rgba($danger-500, 0.5);
  }
}

.stat-icon-enhanced {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.95);
  border: 1px solid rgba($primary-300, 0.3);
  box-shadow: 0 2px 6px rgba($primary-200, 0.3);
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  margin: 0 auto 8px;
}

.stat-item-enhanced:hover .stat-icon-enhanced {
  transform: scale(1.08);
  box-shadow: 0 4px 12px rgba($primary-400, 0.4);
}

.stat-content-enhanced {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}

.stat-value-enhanced {
  font-size: 16px;
  font-weight: 700;
  color: $primary-700;
  line-height: 1.2;
  margin-bottom: 2px;
}

.stat-item-success .stat-value-enhanced {
  color: $success-700;
}

.stat-item-warning .stat-value-enhanced {
  color: $secondary-700;
}

.stat-item-error .stat-value-enhanced {
  color: $danger-700;
}

.stat-label-enhanced {
  font-size: 8px;
  color: $neutral-700;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  line-height: 1.2;
}

/* Sidebar Info Section */
.sidebar-info {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 0 8px 10px;
  position: relative;
  z-index: 2;
}

.info-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px 6px;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.6);
  border: 1px solid rgba($primary-300, 0.2);
  transition: all 0.2s ease;

  &:hover {
    background: rgba(255, 255, 255, 0.9);
    border-color: rgba($primary-400, 0.4);
    transform: translateX(2px);
  }

  .text-caption {
    font-size: 9px;
    color: $neutral-700;
    font-weight: 500;
  }
}

.stat-item-discord {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  width: 100%;
  max-width: 84px;
  margin: 0 auto;
  padding: 8px 4px;
  border-radius: 10px;
  border: 1px solid transparent;

  &:hover {
    transform: translateY(-1px);
    box-shadow: 0 2px 8px rgba($primary-600, 0.15);
  }
}

.stat-item-discord::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 0;
  background: linear-gradient(180deg, $primary-600 0%, $primary-400 100%);
  border-radius: 0 3px 3px 0;
  transition: height 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  opacity: 0;
}

.stat-item-discord:hover::before {
  height: 36px;
  opacity: 1;
}

.stat-item-primary {
  color: #5865f2;
}

.stat-item-success {
  color: #57f287;
}

.stat-item-secondary {
  color: #faa61a;
}

.stat-item-discord:hover {
  background: rgba(0, 0, 0, 0.04);
  transform: translateX(2px);
}

.stat-icon-discord {
  width: 36px;
  height: 36px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid rgba($primary-600, 0.1);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
  overflow: hidden;
  flex-shrink: 0;
  margin: 0 auto;
}

.stat-icon-discord::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  padding: 2px;
  background: linear-gradient(135deg, currentColor, transparent);
  -webkit-mask:
    linear-gradient(#fff 0 0) content-box,
    linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  opacity: 0;
  transition: opacity 0.25s ease;
}

.stat-item-discord:hover .stat-icon-discord::after {
  opacity: 1;
}

.stat-icon-discord .v-icon {
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  z-index: 1;
}

.stat-item-primary .stat-icon-discord {
  background: rgba(88, 101, 242, 0.1);
  border-color: rgba(88, 101, 242, 0.3);
}

.stat-item-primary:hover .stat-icon-discord {
  background: #5865f2;
  border-color: #5865f2;
  border-radius: 18px;
  box-shadow:
    0 4px 16px rgba(88, 101, 242, 0.4),
    inset 0 1px 0 rgba(255, 255, 255, 0.2);
}

.stat-item-primary:hover .stat-icon-discord .v-icon {
  color: $neutral-100 !important;
  transform: scale(1.1) rotate(5deg);
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
}

.stat-item-success .stat-icon-discord {
  background: rgba(87, 242, 135, 0.1);
  border-color: rgba(87, 242, 135, 0.3);
}

.stat-item-success:hover .stat-icon-discord {
  background: #57f287;
  border-color: #57f287;
  border-radius: 18px;
  box-shadow:
    0 4px 16px rgba(87, 242, 135, 0.4),
    inset 0 1px 0 rgba(255, 255, 255, 0.2);
}

.stat-item-success:hover .stat-icon-discord .v-icon {
  color: $neutral-100 !important;
  transform: scale(1.1) rotate(-5deg);
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
}

.stat-item-secondary .stat-icon-discord {
  background: rgba(250, 166, 26, 0.1);
  border-color: rgba(250, 166, 26, 0.3);
}

.stat-item-secondary:hover .stat-icon-discord {
  background: #faa61a;
  border-color: #faa61a;
  border-radius: 18px;
  box-shadow:
    0 4px 16px rgba(250, 166, 26, 0.4),
    inset 0 1px 0 rgba(255, 255, 255, 0.2);
}

.stat-item-secondary:hover .stat-icon-discord .v-icon {
  color: $neutral-100 !important;
  transform: scale(1.1) rotate(5deg);
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
}

.stat-content-discord {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  margin-top: 6px;
  opacity: 0.9;
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  width: 100%;
}

.stat-item-discord:hover .stat-content-discord {
  opacity: 1;
  transform: translateY(-1px);
}

.stat-value-discord {
  font-size: 16px;
  font-weight: 700;
  color: $neutral-900;
  letter-spacing: -0.2px;
  line-height: 1.2;
  text-align: center;
}

.stat-label-discord {
  font-size: 8px;
  color: $neutral-700;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  line-height: 1.2;
  text-align: center;
  margin-top: 1px;
}

@keyframes slideUp {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.stat-card-modern {
  background: $neutral-100;
  border-radius: 12px;
  padding: 16px 12px;
  text-align: center;
  border: 1px solid #e5e7eb;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  overflow: hidden;
}

.stat-card-modern::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: linear-gradient(90deg, $primary-600 0%, $primary-700 100%);
  transform: scaleX(0);
  transition: transform 0.3s ease;
}

.stat-card-modern:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
  border-color: $primary-600;
}

.stat-card-modern:hover::before {
  transform: scaleX(1);
}

.stat-icon-modern {
  margin-bottom: 12px;
  display: inline-flex;
  padding: 8px;
  background: $primary-100;
  border-radius: 10px;
}

.stat-value {
  font-size: 20px;
  font-weight: 700;
  color: #1a1a1a;
  margin-bottom: 4px;
  letter-spacing: -0.5px;
}

.stat-label {
  font-size: 11px;
  color: $neutral-700;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.custom-snackbar {
  margin-bottom: 16px;
  margin-right: 16px;
}

.custom-snackbar :deep(.v-snackbar__wrapper) {
  min-width: 300px;
}

/* History Dialog Styles */
.history-list {
  max-height: 500px;
  overflow-y: auto;
  overflow-x: hidden;
  padding-right: 8px;
  min-height: 0;
}

.history-list::-webkit-scrollbar {
  width: 6px;
}

.history-list::-webkit-scrollbar-track {
  background: $neutral-300;
  border-radius: 10px;
}

.history-list::-webkit-scrollbar-thumb {
  background: $neutral-600;
  border-radius: 10px;
}

.history-list::-webkit-scrollbar-thumb:hover {
  background: $neutral-700;
}

.history-item {
  transition: all 0.3s ease;
  border-left: 4px solid transparent;
}

.history-item:hover {
  transform: translateX(4px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.history-success {
  border-left-color: $success-500;
  background: rgba($success-500, 0.05);
}

.history-failed {
  border-left-color: $danger-500;
  background: rgba($danger-500, 0.05);
}

.history-pending {
  border-left-color: $secondary-500;
  background: rgba($secondary-500, 0.05);
}

/* History Item Dialog Styling */
.history-item-dialog {
  transition: all 0.2s ease;
  position: relative;
  overflow: hidden;
  background: $neutral-100 !important;
  border: 1px solid $neutral-400 !important;
  border-radius: 10px !important;
  border-left: 3px solid transparent !important;
}

.history-item-dialog::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: transparent;
  z-index: 1;
  border-radius: 10px 0 0 10px;
}

.history-item-dialog:hover {
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  transform: translateY(-1px);
  border-color: $neutral-500 !important;
}

.history-item-dialog.history-success::before {
  background: $success-500 !important;
}

.history-item-dialog.history-success {
  background: rgba($success-100, 0.5) !important;
  border-left-color: $success-500 !important;
}

.history-item-dialog.history-failed::before {
  background: $danger-500 !important;
}

.history-item-dialog.history-failed {
  background: rgba($danger-100, 0.5) !important;
  border-left-color: $danger-500 !important;
}

.history-item-dialog.history-pending::before {
  background: $secondary-500 !important;
}

.history-item-dialog.history-pending {
  background: rgba($secondary-100, 0.5) !important;
  border-left-color: $secondary-500 !important;
}

.history-item-dialog.history-item-qr {
  border-left-color: $secondary-500 !important;
  background: rgba($secondary-100, 0.3) !important;
}

.history-item-dialog.history-item-qr::before {
  background: $secondary-500 !important;
}

/* Status Badge Dialog */
.history-status-badge-dialog {
  width: 24px;
  height: 24px;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.history-status-badge-dialog.status-success {
  background: rgba($success-500, 0.15);
  color: $success-600;
}

.history-status-badge-dialog.status-error,
.history-status-badge-dialog.status-warning {
  background: rgba($danger-500, 0.15);
  color: $danger-600;
}

.history-status-badge-dialog.status-warning {
  background: rgba($secondary-500, 0.15);
  color: $secondary-600;
}

.history-status-text-dialog {
  font-size: 12px;
  font-weight: 600;
  line-height: 1.2;
  margin-bottom: 0;
}

.history-status-text-dialog.text-success {
  color: $success-600;
}

.history-status-text-dialog.text-error {
  color: $danger-600;
}

.history-status-text-dialog.text-warning {
  color: $secondary-600;
}

.history-method-text-dialog {
  font-size: 10px;
  color: $neutral-600;
  font-weight: 400;
}

/* Queue Badge Dialog */
.history-queue-badge-dialog {
  display: flex;
  align-items: center;
  padding: 3px 8px;
  background: rgba($secondary-500, 0.1);
  color: $secondary-600;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 500;
}

/* Info Badge Dialog */
.history-info-badge-dialog {
  display: flex;
  align-items: center;
  padding: 2px 6px;
  background: $neutral-300;
  color: $neutral-700;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 500;
}

.history-klinik-badge-dialog {
  display: flex;
  align-items: center;
  padding: 2px 6px;
  background: rgba($primary-500, 0.1);
  color: $primary-600;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 500;
}

.history-payment-badge-dialog {
  display: flex;
  align-items: center;
  padding: 2px 6px;
  background: rgba($primary-500, 0.1);
  color: $primary-600;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 500;
}

.history-qr-badge-dialog {
  display: flex;
  align-items: center;
  padding: 3px 8px;
  background: rgba($primary-500, 0.1);
  color: $primary-600;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 500;
}

/* Time Badge Dialog */
.history-time-badge-dialog {
  display: flex;
  align-items: center;
  padding: 2px 6px;
  background: $neutral-300;
  border-radius: 4px;
  font-size: 10px;
  color: $neutral-700;
  font-weight: 500;
}

/* Action Buttons */
.history-delete-btn,
.history-action-btn {
  opacity: 0.7;
  transition: all 0.2s ease;
}

.history-item-dialog:hover .history-delete-btn,
.history-item-dialog:hover .history-action-btn {
  opacity: 1;
}

/* History Header Stats */
.history-header-stats {
  padding: 12px;
  background: $neutral-100;
  border-radius: 12px;
  border: 1px solid $neutral-400;
}

.history-header-title {
  padding-bottom: 6px;
  border-bottom: 1px solid $neutral-400;
}

.history-header-title h3 {
  color: $neutral-900;
  margin: 0;
}

.stat-card-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px;
  background: $neutral-100;
  border-radius: 8px;
  border: 1px solid $neutral-400;
  transition: all 0.2s ease;
  height: 100%;
}

.stat-card-header:hover {
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  transform: translateY(-1px);
}

.stat-icon-header {
  width: 36px;
  height: 36px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.stat-icon-total {
  background: rgba($primary-500, 0.15);
  color: $primary-600;
}

.stat-icon-success {
  background: rgba($success-500, 0.15);
  color: $success-600;
}

.stat-icon-failed {
  background: rgba($danger-500, 0.15);
  color: $danger-600;
}

.stat-icon-filtered {
  background: rgba($secondary-500, 0.15);
  color: $secondary-600;
}

.stat-content-header {
  flex: 1;
  min-width: 0;
}

.stat-value-header {
  font-size: 16px;
  font-weight: 700;
  color: $neutral-900;
  line-height: 1.2;
  margin-bottom: 1px;
}

.stat-label-header {
  font-size: 10px;
  color: $neutral-600;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

/* Mobile Optimization */
@media (max-width: 600px) {
  .checkin-page-container {
    padding: 0 12px 12px 12px !important;
  }

  .checkin-page-container :deep(.page-header) {
    margin-left: -8px !important;
    margin-right: -8px !important;
    width: calc(100% + 16px) !important;
  }

  /* Removed main-card styles */

  .header-modern {
    padding: 6px 16px 4px !important;
  }

  .content-modern {
    padding: 16px !important;
    flex: 1;
    min-height: 0;
  }

  .header-content {
    flex-direction: column;
    text-align: center;
    gap: 12px;
  }

  .header-text {
    text-align: center;
  }

  .icon-circle {
    width: 40px;
    height: 40px;
  }

  .title-modern {
    font-size: 16px;
  }

  .subtitle-modern {
    font-size: 11px;
  }

  .content-modern {
    padding: 20px 16px !important;
  }

  .status-header {
    padding: 12px 16px;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: 8px;
  }

  .status-icon-wrapper {
    margin: 0 auto;
    width: 32px;
    height: 32px;
  }

  .status-text {
    text-align: center;
    width: 100%;
  }

  .status-title {
    font-size: 14px;
  }

  .status-subtitle {
    font-size: 11px;
  }

  // Sembunyikan elemen sekunder di mobile
  .quick-actions {
    display: none;
  }

  .test-camera-section {
    display: none;
  }

  // Pastikan touch target size
  .v-btn {
    min-height: 44px !important;
    min-width: 44px !important;
  }

  .v-btn--icon {
    width: 44px !important;
    height: 44px !important;
  }

  .qr-placeholder {
    max-width: 100%;
    min-height: 200px;
    aspect-ratio: 1 / 1;
  }

  .qr-reader-container {
    max-width: 100%;
    overflow: visible;
  }

  .qr-reader-wrapper {
    max-width: 100%;
    aspect-ratio: 1 / 1;
    border-radius: 16px;
  }

  .qr-reader-wrapper :deep(video) {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
  }

  .scanner-instruction {
    font-size: 10px;
    padding: 6px 8px;
    margin-top: 6px;
    max-width: 100%;
  }

  .scanner-instruction .v-icon {
    font-size: 14px !important;
    margin-right: 6px !important;
  }

  .stats-footer-modern {
    margin-top: 8px;
  }

  .stat-card-modern {
    padding: 12px 8px;
  }

  .stat-value {
    font-size: 18px;
  }

  .stat-label {
    font-size: 10px;
  }

  .stat-icon-modern {
    margin-bottom: 8px;
    padding: 6px;
  }

  .tabs-modern :deep(.v-tab) {
    font-size: 12px;
    padding: 0 12px;
  }

  .tabs-modern :deep(.v-tab .v-icon) {
    font-size: 18px;
  }

  .btn-primary-modern,
  .btn-stop-modern {
    padding: 12px 24px !important;
    font-size: 14px;
    min-width: 200px !important;
  }

  .btn-centered {
    min-width: 200px !important;
    max-width: 280px !important;
  }

  .qr-placeholder {
    max-width: 100%;
    min-height: 180px;
    aspect-ratio: 1 / 1;
  }

  .qr-reader-wrapper {
    max-width: 100%;
    aspect-ratio: 1 / 1;
  }

  /* Hide stats sidebar on mobile */
  .stats-sidebar-right {
    display: none !important;
  }
}

/* Additional sidebar positioning fixes */
@media (min-width: 1264px) {
  .stats-sidebar-right {
    display: flex !important;
    visibility: visible !important;
    opacity: 1 !important;
  }
}

/* Desktop - Large screens */
@media (min-width: 1264px) {
  .content-grid {
    align-items: stretch;
    justify-content: center;
    flex-wrap: nowrap !important;
  }

  .qr-scan-card,
  .manual-input-card {
    max-height: calc(100vh - 200px) !important;
    overflow-y: auto;
  }

  .stats-sidebar-right {
    margin-top: 0;
    padding-top: 0;
    align-self: flex-start;
    order: 3 !important;
    flex-shrink: 0 !important;
    flex-grow: 0 !important;
    display: flex !important;
    visibility: visible !important;
    opacity: 1 !important;
  }

  .sticky-column {
    flex-shrink: 0;
    flex-basis: auto;
  }

  .content-grid > .v-col:nth-child(2) {
    flex-shrink: 0;
    flex-basis: auto;
  }

  .stats-sidebar-enhanced,
  .stats-sidebar-discord {
    margin: 0;
  }
}

/* Tablet - Medium screens (961px to 1263px) */
@media (min-width: 961px) and (max-width: 1263px) {
  .checkin-page-container {
    max-height: none !important;
    overflow-y: auto !important;
    height: auto !important;
    padding-bottom: 20px !important;
  }

  .qr-scan-card,
  .manual-input-card {
    max-height: none !important;
    overflow-y: visible !important;
    height: auto !important;
  }

  .content-grid {
    align-items: stretch;
  }
}

/* Small tablets and large phones (721px to 960px) */
@media (min-width: 721px) and (max-width: 960px) {
  .checkin-page-container {
    max-height: none !important;
    overflow-y: auto !important;
    height: auto !important;
    padding-bottom: 20px !important;
  }

  .qr-scan-card,
  .manual-input-card {
    max-height: none !important;
    overflow-y: visible !important;
    height: auto !important;
  }
}

/* Very small screens (up to 720px) */
@media (max-width: 720px) {
  .checkin-page-container {
    max-height: none !important;
    overflow-y: auto !important;
    height: auto !important;
    padding-bottom: 16px !important;
  }

  .qr-scan-card,
  .manual-input-card {
    max-height: none !important;
    overflow-y: visible !important;
    height: auto !important;
  }

  .stats-footer-horizontal {
    padding: 6px 8px;
    gap: 4px;
    margin-bottom: 8px !important;
  }
}

/* Extra small screens (phones in portrait, up to 480px) */
@media (max-width: 480px) {
  .checkin-page-container {
    padding: 0 8px 8px 8px !important;
  }

  .content-grid {
    margin: 0 2px !important;
  }

  .qr-scan-card,
  .manual-input-card {
    max-height: 38vh !important;
    border-radius: 8px;
    padding: 8px;
  }

  /* Alert box extra small */
  :deep(.v-alert) {
    font-size: 11px !important;
    padding: 8px 10px !important;
    border-radius: 8px !important;
  }

  :deep(.v-alert .v-alert__prepend) {
    margin-right: 6px !important;
  }

  :deep(.v-alert .v-icon) {
    font-size: 18px !important;
  }

  :deep(.v-alert p) {
    font-size: 10px !important;
  }

  :deep(.v-alert .font-weight-bold) {
    font-size: 12px !important;
  }

  .stats-footer-horizontal {
    padding: 4px 6px;
    gap: 3px;
    border-radius: 8px;
    max-width: calc(100vw - 12px) !important;
  }

  .stat-item-footer-enhanced {
    min-width: calc(50% - 3px);
    flex: 1 1 calc(50% - 3px);
    padding: 6px 4px;
  }

  .stat-value-footer-enhanced {
    font-size: 11px;
  }

  .stat-label-footer-enhanced {
    font-size: 8px;
  }

  .stat-icon-footer-enhanced .v-icon {
    font-size: 14px !important;
  }
}

/* Smooth sticky animation */
@media (min-width: 1264px) {
  .stats-sidebar-enhanced {
    animation: slideInRight 0.4s ease-out;
  }
}

@keyframes slideInRight {
  from {
    opacity: 0;
    transform: translateX(20px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

/* Stats Footer Horizontal - Permanent Footer for All Screens */
.stats-footer-row {
  margin-top: 0px !important;
  margin-bottom: 2px !important;
  flex-shrink: 0;
  display: flex;
  justify-content: center;
}

.stats-footer-horizontal {
  display: flex !important;
  width: 100%;
  max-width: calc(100vw - 32px);
  gap: 5px;
  padding: 6px 8px;
  background: linear-gradient(
    180deg,
    rgba($primary-50, 0.98) 0%,
    rgba($primary-100, 0.92) 100%
  );
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-radius: 10px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  border: 1px solid rgba($primary-300, 0.2);
  justify-content: center;
  align-items: center;
  flex-wrap: nowrap;
  overflow-x: auto;
  margin: 0 auto;
}

.stat-item-footer-enhanced {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  padding: 5px 4px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.6);
  min-width: 65px;
  gap: 2px;
}

.stat-item-footer-enhanced:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  background: rgba(255, 255, 255, 0.9);
}

.stat-icon-footer-enhanced {
  margin-bottom: 4px;
}

.stat-content-footer-enhanced {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}

.stat-value-footer-enhanced {
  font-size: 13px;
  font-weight: 700;
  color: $primary-700;
  line-height: 1.2;
  margin-bottom: 2px;
}

.stat-item-footer-success .stat-value-footer-enhanced {
  color: $success-700;
}

.stat-item-footer-warning .stat-value-footer-enhanced {
  color: $secondary-700;
}

.stat-item-footer-error .stat-value-footer-enhanced {
  color: $danger-700;
}

.stat-item-footer-info .stat-value-footer-enhanced {
  color: $primary-700;
}

.stat-label-footer-enhanced {
  font-size: 7px;
  color: $neutral-700;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

/* Footer enhanced item colors - match sidebar */
.stat-item-footer-enhanced.stat-item-footer-primary {
  background: linear-gradient(
    135deg,
    rgba($primary-100, 0.8) 0%,
    rgba($primary-50, 0.6) 100%
  );
  border-color: rgba($primary-400, 0.3);
}

.stat-item-footer-enhanced.stat-item-footer-primary:hover {
  background: linear-gradient(
    135deg,
    rgba($primary-200, 0.9) 0%,
    rgba($primary-100, 0.7) 100%
  );
  border-color: rgba($primary-500, 0.5);
}

.stat-item-footer-enhanced.stat-item-footer-success {
  background: linear-gradient(
    135deg,
    rgba($success-100, 0.8) 0%,
    rgba($success-200, 0.6) 100%
  );
  border-color: rgba($success-400, 0.3);
}

.stat-item-footer-enhanced.stat-item-footer-success:hover {
  background: linear-gradient(
    135deg,
    rgba($success-200, 0.9) 0%,
    rgba($success-100, 0.7) 100%
  );
  border-color: rgba($success-500, 0.5);
}

.stat-item-footer-enhanced.stat-item-footer-error {
  background: linear-gradient(
    135deg,
    rgba($danger-100, 0.8) 0%,
    rgba($danger-200, 0.5) 100%
  );
  border-color: rgba($danger-400, 0.3);
}

.stat-item-footer-enhanced.stat-item-footer-error:hover {
  background: linear-gradient(
    135deg,
    rgba($danger-200, 0.9) 0%,
    rgba($danger-100, 0.7) 100%
  );
  border-color: rgba($danger-500, 0.5);
}

.stat-item-footer-enhanced.stat-item-footer-info {
  background: linear-gradient(
    135deg,
    rgba($primary-100, 0.8) 0%,
    rgba($primary-50, 0.6) 100%
  );
  border-color: rgba($primary-400, 0.3);
}

.stat-item-footer-enhanced.stat-item-footer-info:hover {
  background: linear-gradient(
    135deg,
    rgba($primary-200, 0.9) 0%,
    rgba($primary-100, 0.7) 100%
  );
  border-color: rgba($primary-500, 0.5);
}

.stat-item-footer-enhanced.stat-item-footer-warning {
  background: linear-gradient(
    135deg,
    rgba($secondary-100, 0.8) 0%,
    rgba($secondary-50, 0.6) 100%
  );
  border-color: rgba($secondary-400, 0.3);
}

.stat-item-footer-enhanced.stat-item-footer-warning:hover {
  background: linear-gradient(
    135deg,
    rgba($secondary-200, 0.9) 0%,
    rgba($secondary-100, 0.7) 100%
  );
  border-color: rgba($secondary-500, 0.5);
}

/* Mobile Landscape */
@media (max-width: 900px) and (orientation: landscape) {
  .qr-reader-wrapper {
    max-width: 100%;
    aspect-ratio: 1 / 1;
  }

  .qr-reader-wrapper :deep(video) {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
  }
}

.qr-code-container {
  background: white;
  padding: 12px;
  border-radius: 12px;
  display: inline-block;
  margin: 0 auto;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
}

.qr-code-container img {
  display: block;
  margin: 0 auto;
}

/* Padding Consistency Overrides for Tablet/Intermediate */
@media (min-width: 601px) and (max-width: 1263px) {
  .checkin-page-container {
    padding: 0 16px !important;
  }
}
</style>
