// stores/queueStore.js
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
import { useClinicStore } from './clinicStore';
import { usePenunjangStore } from './penunjangStore';
import { useLoketStore } from './loketStore';

export const useQueueStore = defineStore('queue', () => {
  const clinicStore = useClinicStore();
  const penunjangStore = usePenunjangStore();
  const loketStore = useLoketStore();

  // Helper function untuk mendapatkan loket default (Loket A)
  const getDefaultLoket = () => {
    const allLokets = loketStore.loketData?.value || loketStore.loketData || [];
    const loket1 = allLokets.find(l => l.id === 1 || l.no === 1);
    return loket1 ? loket1.namaLoket : 'Loket A';
  };

  // Helper function untuk increment barcode counter setelah barcode digunakan
  const incrementBarcodeCounter = () => {
    if (typeof window === 'undefined' || typeof localStorage === 'undefined') return;
    
    const now = new Date();
    const year = String(now.getFullYear()).slice(-2);
    const month = String(now.getMonth() + 1).padStart(2, '0');
    const day = String(now.getDate()).padStart(2, '0');
    const datePrefix = `${year}${month}${day}`;
    const STORAGE_KEY = `barcode_counter_${datePrefix}`;
    const LAST_DATE_KEY = 'barcode_last_date';
    
    const storedCounter = localStorage.getItem(STORAGE_KEY);
    if (storedCounter) {
      const currentCounter = parseInt(storedCounter, 10) || 1;
      localStorage.setItem(STORAGE_KEY, String(currentCounter + 1));
      localStorage.setItem(LAST_DATE_KEY, datePrefix);
    }
  };

  // Helper function untuk generate barcode dengan format: YYMMDD + 5 digit sequential
  // Format: YY (tahun 2 digit terakhir) + MM (bulan 2 digit) + DD (tanggal 2 digit) + XXXXX (5 digit sequential)
  // Contoh: 26011400001, 26011400002, dst
  // Counter akan reset setiap ganti tanggal (mulai dari 00001 lagi)
  // IMPORTANT: Memastikan barcode selalu UNIQUE dan sequential per tanggal
  // NOTE: allPatientsRef adalah optional parameter untuk menghindari TDZ error saat seed initialization
  const generateBarcode = (existingBarcodes = [], allPatientsRef = null) => {
    const now = new Date();
    const year = String(now.getFullYear()).slice(-2); // 2 digit tahun terakhir
    const month = String(now.getMonth() + 1).padStart(2, '0'); // 2 digit bulan
    const day = String(now.getDate()).padStart(2, '0'); // 2 digit tanggal
    const datePrefix = `${year}${month}${day}`; // YYMMDD
    
    // Check if localStorage is available (browser environment)
    if (typeof window !== 'undefined' && typeof localStorage !== 'undefined') {
      // Key untuk localStorage berdasarkan tanggal
      const STORAGE_KEY = `barcode_counter_${datePrefix}`;
      const LAST_DATE_KEY = 'barcode_last_date';
      
      // Cek apakah tanggal sudah berubah (reset counter)
      const lastDate = localStorage.getItem(LAST_DATE_KEY);
      const currentDate = datePrefix;
      
      let counter = 1; // Default mulai dari 1
      
      if (lastDate === currentDate) {
        // Tanggal sama, lanjutkan counter dari localStorage
        const storedCounter = localStorage.getItem(STORAGE_KEY);
        if (storedCounter) {
          counter = parseInt(storedCounter, 10) || 1;
        }
      } else {
        // Tanggal berbeda, reset counter ke 1
        counter = 1;
        // Hapus counter lama untuk tanggal sebelumnya (cleanup)
        if (lastDate) {
          localStorage.removeItem(`barcode_counter_${lastDate}`);
        }
      }
      
      // Generate barcode dengan counter saat ini
      let barcode = `${datePrefix}${String(counter).padStart(5, '0')}`;
      
      // Cek apakah barcode sudah ada di existingBarcodes atau allPatientsRef
      const checkExists = (b) => {
        if (existingBarcodes.includes(b)) return true;
        // Hanya cek allPatientsRef jika diberikan (tidak null/undefined)
        if (allPatientsRef && allPatientsRef.value && allPatientsRef.value.some(p => p.barcode === b)) return true;
        return false;
      };
      
      let attempts = 0;
      const maxAttempts = 1000; // Maksimal 1000 pasien per hari
      
      // Cek uniqueness dan increment jika duplikat
      while (checkExists(barcode) && attempts < maxAttempts) {
        counter++;
        barcode = `${datePrefix}${String(counter).padStart(5, '0')}`;
        attempts++;
      }
      
      // IMPORTANT: JANGAN tulis counter ke localStorage di sini!
      // Counter hanya di-increment dan di-save setelah barcode benar-benar digunakan
      // Ini mencegah counter naik meskipun barcode tidak digunakan (misalnya saat refresh)
      // Counter akan di-increment oleh incrementBarcodeCounter() setelah pasien dibuat
      // Hanya update LAST_DATE_KEY untuk tracking tanggal
      localStorage.setItem(LAST_DATE_KEY, currentDate);
      
      return barcode;
    } else {
      // Fallback untuk SSR atau environment tanpa localStorage
      // Gunakan counter berdasarkan existing barcodes atau allPatientsRef
      const existingCount = existingBarcodes.filter(b => b && b.startsWith(datePrefix)).length;
      const allCount = allPatientsRef && allPatientsRef.value 
        ? allPatientsRef.value.filter(p => p.barcode && p.barcode.startsWith(datePrefix)).length 
        : 0;
      const counter = Math.max(existingCount, allCount) + 1;
      const counterCode = String(counter).padStart(5, '0');
      return `${datePrefix}${counterCode}`;
    }
  };
  // Seed data for easy reset during dev
  // IMPORTANT: Setiap pasien HARUS memiliki barcode UNIK untuk menghindari konflik
  // Format barcode menggunakan generateBarcode() untuk konsistensi dengan format baru
  // Generate barcode dengan memastikan uniqueness menggunakan existingBarcodes array
  // NOTE: Seed data menggunakan barcode statis untuk menghindari increment counter saat refresh
  // Counter hanya di-increment ketika pasien baru benar-benar dibuat dari Anjungan
  
  // Gunakan barcode statis untuk seed data (tidak memanggil generateBarcode)
  // Format: YYMMDD + 5 digit sequential dimulai dari 00001
  // Ini mencegah counter naik setiap kali halaman di-refresh
  const getSeedBarcode = (index) => {
    if (typeof window !== 'undefined' && typeof localStorage !== 'undefined') {
      const now = new Date();
      const year = String(now.getFullYear()).slice(-2);
      const month = String(now.getMonth() + 1).padStart(2, '0');
      const day = String(now.getDate()).padStart(2, '0');
      const datePrefix = `${year}${month}${day}`;
      
      // Gunakan barcode statis berdasarkan index (1-16)
      // Format: YYMMDD + 5 digit (contoh: 26011500001, 26011500002, dst)
      return `${datePrefix}${String(index).padStart(5, '0')}`;
    }
    // Fallback untuk SSR
    const now = new Date();
    const year = String(now.getFullYear()).slice(-2);
    const month = String(now.getMonth() + 1).padStart(2, '0');
    const day = String(now.getDate()).padStart(2, '0');
    const datePrefix = `${year}${month}${day}`;
    return `${datePrefix}${String(index).padStart(5, '0')}`;
  };
  
  const seedBarcode1 = getSeedBarcode(1);
  const seedBarcode2 = getSeedBarcode(2);
  const seedBarcode3 = getSeedBarcode(3);
  const seedBarcode4 = getSeedBarcode(4);
  const seedBarcode5 = getSeedBarcode(5);
  const seedBarcode6 = getSeedBarcode(6);
  const seedBarcode7 = getSeedBarcode(7);
  const seedBarcode8 = getSeedBarcode(8);
  const seedBarcode9 = getSeedBarcode(9);
  const seedBarcode10 = getSeedBarcode(10);
  const seedBarcode11 = getSeedBarcode(11);
  const seedBarcode12 = getSeedBarcode(12);
  // Barcode untuk pasien Eksekutif
  const seedBarcodeE1 = getSeedBarcode(13);
  const seedBarcodeE2 = getSeedBarcode(14);
  const seedBarcodeE3 = getSeedBarcode(15);
  const seedBarcodeE4 = getSeedBarcode(16);
  
  // IMPORTANT: Set counter ke nilai yang sesuai dengan jumlah seed data
  // Ini mencegah counter naik tidak terkendali saat seed data di-generate
  // Counter akan di-set ke jumlah seed data (16) + 1 untuk next barcode
  // Hanya set jika counter belum ada atau lebih kecil dari jumlah seed data
  if (typeof window !== 'undefined' && typeof localStorage !== 'undefined') {
    const now = new Date();
    const year = String(now.getFullYear()).slice(-2);
    const month = String(now.getMonth() + 1).padStart(2, '0');
    const day = String(now.getDate()).padStart(2, '0');
    const datePrefix = `${year}${month}${day}`;
    const STORAGE_KEY = `barcode_counter_${datePrefix}`;
    const LAST_DATE_KEY = 'barcode_last_date';
    const storedCounter = localStorage.getItem(STORAGE_KEY);
    const seedDataCount = 16; // Jumlah seed data
    
    // Hanya set counter jika belum ada atau lebih kecil dari jumlah seed data
    // Jangan overwrite counter yang sudah lebih besar (berarti sudah ada pasien baru)
    if (!storedCounter || parseInt(storedCounter, 10) < seedDataCount) {
      localStorage.setItem(STORAGE_KEY, String(seedDataCount + 1));
      localStorage.setItem(LAST_DATE_KEY, datePrefix);
    }
  }
  
  const seedPatients = [
    {
      no: 1,
      jamPanggil: "12:49",
      barcode: seedBarcode1, // Barcode unik untuk setiap pasien
      noAntrian: `F-RA001 | Online - ${seedBarcode1}`, // Counter 1: Fast Track BPJS
      shift: "Shift 1",
      klinik: "KANDUNGAN",
      fastTrack: "YA", // Fast Track Patient
      pembayaran: "BPJS",
      status: "waiting",
      processStage: "loket",
      createdAt: new Date().toISOString(),
      registrationType: 'online',
      visitType: 'SEKARANG',
      visitDate: new Date().toISOString().substring(0, 10),
      namaDokter: null,
      penanggungJawab: "Dr. Ahmad Wijaya", // Fast Track data
      alasanFastTrack: "Pasien prioritas", // Fast Track data
    },
    {
      no: 2,
      jamPanggil: "10:52",
      barcode: seedBarcode2,
      noAntrian: `RA002 | Online - ${seedBarcode2}`, // Counter 2: Non-fast track UMUM
      shift: "Shift 1",
      klinik: "IPD",
      fastTrack: "TIDAK",
      pembayaran: "UMUM",
      status: "waiting",
      processStage: "loket",
      createdAt: new Date().toISOString(),
      registrationType: 'online',
      visitType: 'SEKARANG',
      visitDate: new Date().toISOString().substring(0, 10),
      namaDokter: null,
      penanggungJawab: null,
      alasanFastTrack: null,
    },
    {
      no: 3,
      jamPanggil: "09:30",
      barcode: seedBarcode3,
      noAntrian: `F-RA003 | Online - ${seedBarcode3}`, // Counter 3: Fast Track BPJS
      shift: "Shift 1",
      klinik: "SARAF",
      fastTrack: "YA", // Fast Track Patient
      pembayaran: "BPJS",
      status: "waiting",
      processStage: "loket",
      createdAt: new Date().toISOString(),
      registrationType: 'online',
      visitType: 'SEKARANG',
      visitDate: new Date().toISOString().substring(0, 10),
      namaDokter: null,
      penanggungJawab: "Dr. Budi Santoso", // Fast Track data
      alasanFastTrack: "Kondisi darurat", // Fast Track data
    },
    {
      no: 4,
      jamPanggil: "14:15",
      barcode: seedBarcode4,
      noAntrian: `RA004 | Online - ${seedBarcode4}`, // Counter 4: Non-fast track UMUM
      shift: "Shift 1",
      klinik: "THT",
      fastTrack: "TIDAK",
      pembayaran: "UMUM",
      status: "waiting",
      processStage: "loket",
      createdAt: new Date().toISOString(),
      registrationType: 'online',
      visitType: 'SEKARANG',
      visitDate: new Date().toISOString().substring(0, 10),
      namaDokter: null,
      penanggungJawab: null,
      alasanFastTrack: null,
    },
    {
      no: 5,
      jamPanggil: "12:49",
      barcode: seedBarcode5,
      noAntrian: `RA005 | Online - ${seedBarcode5}`, // Counter 5: Non-fast track UMUM
      shift: "Shift 2",
      klinik: "KANDUNGAN",
      fastTrack: "TIDAK",
      pembayaran: "UMUM",
      status: "waiting",
      processStage: "loket",
      createdAt: new Date().toISOString(),
      registrationType: 'online',
      visitType: 'SEKARANG',
      visitDate: new Date().toISOString().substring(0, 10),
      namaDokter: null,
      penanggungJawab: null,
      alasanFastTrack: null,
    },
    {
      no: 6,
      jamPanggil: "10:52",
      barcode: seedBarcode6,
      noAntrian: `F-RA006 | Online - ${seedBarcode6}`, // Counter 6: Fast Track BPJS
      shift: "Shift 1",
      klinik: "IPD",
      fastTrack: "YA", // Fast Track Patient
      pembayaran: "BPJS",
      status: "waiting",
      processStage: "loket",
      createdAt: new Date().toISOString(),
      registrationType: 'online',
      visitType: 'SEKARANG',
      visitDate: new Date().toISOString().substring(0, 10),
      namaDokter: null,
      penanggungJawab: "Dr. Citra Dewi", // Fast Track data
      alasanFastTrack: "Rujukan darurat", // Fast Track data
    },
    {
      no: 7,
      jamPanggil: "09:30",
      barcode: seedBarcode7,
      noAntrian: `RA007 | Online - ${seedBarcode7}`, // Counter 7: Non-fast track UMUM
      shift: "Shift 1",
      klinik: "SARAF",
      fastTrack: "TIDAK",
      pembayaran: "UMUM",
      status: "waiting",
      processStage: "loket",
      createdAt: new Date().toISOString(),
      registrationType: 'online',
      visitType: 'SEKARANG',
      visitDate: new Date().toISOString().substring(0, 10),
      namaDokter: null,
      penanggungJawab: null,
      alasanFastTrack: null,
    },
    {
      no: 8,
      jamPanggil: "14:15",
      barcode: seedBarcode8,
      noAntrian: `RA008 | Online - ${seedBarcode8}`, // Counter 8: Non-fast track UMUM
      shift: "Shift 1",
      klinik: "THT",
      fastTrack: "TIDAK",
      pembayaran: "UMUM",
      status: "waiting",
      processStage: "loket",
      createdAt: new Date().toISOString(),
      registrationType: 'online',
      visitType: 'SEKARANG',
      visitDate: new Date().toISOString().substring(0, 10),
      namaDokter: null,
      penanggungJawab: null,
      alasanFastTrack: null,
    },
    {
      no: 9,
      jamPanggil: "12:49",
      barcode: seedBarcode9,
      noAntrian: `F-RA009 | Online - ${seedBarcode9}`, // Counter 9: Fast Track BPJS
      shift: "Shift 2",
      klinik: "KANDUNGAN",
      fastTrack: "YA", // Fast Track Patient
      pembayaran: "BPJS",
      status: "waiting",
      processStage: "loket",
      createdAt: new Date().toISOString(),
      registrationType: 'online',
      visitType: 'SEKARANG',
      visitDate: new Date().toISOString().substring(0, 10),
      namaDokter: null,
      penanggungJawab: "Dr. Dedi Kurniawan", // Fast Track data
      alasanFastTrack: "Pasien VIP", // Fast Track data
    },
    {
      no: 10,
      jamPanggil: "10:52",
      barcode: seedBarcode10,
      noAntrian: `RA010 | Online - ${seedBarcode10}`, // Counter 10: Non-fast track UMUM
      shift: "Shift 1",
      klinik: "IPD",
      fastTrack: "TIDAK",
      pembayaran: "UMUM",
      status: "waiting",
      processStage: "loket",
      createdAt: new Date().toISOString(),
      registrationType: 'online',
      visitType: 'SEKARANG',
      visitDate: new Date().toISOString().substring(0, 10),
      namaDokter: null,
      penanggungJawab: null,
      alasanFastTrack: null,
    },
    {
      no: 11,
      jamPanggil: "09:30",
      barcode: seedBarcode11,
      noAntrian: `RA011 | Online - ${seedBarcode11}`, // Counter 11: Non-fast track UMUM
      shift: "Shift 1",
      klinik: "SARAF",
      fastTrack: "TIDAK",
      pembayaran: "UMUM",
      status: "waiting",
      processStage: "loket",
      createdAt: new Date().toISOString(),
      registrationType: 'online',
      visitType: 'SEKARANG',
      visitDate: new Date().toISOString().substring(0, 10),
      namaDokter: null,
      penanggungJawab: null,
      alasanFastTrack: null,
    },
    {
      no: 12,
      jamPanggil: "14:15",
      barcode: seedBarcode12,
      noAntrian: `F-RA012 | Online - ${seedBarcode12}`, // Counter 12: Fast Track BPJS
      shift: "Shift 2",
      klinik: "THT",
      fastTrack: "YA", // Fast Track Patient
      pembayaran: "BPJS",
      status: "waiting",
      processStage: "loket",
      createdAt: new Date().toISOString(),
      registrationType: 'online',
      visitType: 'SEKARANG',
      visitDate: new Date().toISOString().substring(0, 10),
      namaDokter: null,
      penanggungJawab: "Dr. Eka Putri", // Fast Track data
      alasanFastTrack: "Kondisi kritis", // Fast Track data
    },
    {
      no: 13,
      jamPanggil: "11:20",
      barcode: seedBarcodeE1, // Barcode unik untuk pasien Eksekutif
      noAntrian: `EA013 | Online - ${seedBarcodeE1}`, // Counter 13: Non-fast track Eksekutif
      shift: "Shift 1",
      klinik: "KANDUNGAN",
      fastTrack: "TIDAK",
      pembayaran: "Eksekutif",
      status: "waiting",
      processStage: "loket",
      createdAt: new Date().toISOString(),
      registrationType: 'online',
      visitType: 'SEKARANG',
      visitDate: new Date().toISOString().substring(0, 10),
      namaDokter: "Dr. Ahmad Wijaya, Sp.OG",
      penanggungJawab: null,
      alasanFastTrack: null,
    },
    {
      no: 14,
      jamPanggil: "13:45",
      barcode: seedBarcodeE2,
      noAntrian: `EA014 | Online - ${seedBarcodeE2}`, // Counter 14: Non-fast track Eksekutif
      shift: "Shift 1",
      klinik: "IPD",
      fastTrack: "TIDAK",
      pembayaran: "Eksekutif",
      status: "waiting",
      processStage: "loket",
      createdAt: new Date().toISOString(),
      registrationType: 'online',
      visitType: 'SEKARANG',
      visitDate: new Date().toISOString().substring(0, 10),
      namaDokter: "Dr. Budi Santoso, Sp.PD",
      penanggungJawab: null,
      alasanFastTrack: null,
    },
    {
      no: 15,
      jamPanggil: "15:10",
      barcode: seedBarcodeE3,
      noAntrian: `F-EA015 | Online - ${seedBarcodeE3}`, // Counter 15: Fast Track Eksekutif
      shift: "Shift 2",
      klinik: "SARAF",
      fastTrack: "YA", // Fast Track Patient
      pembayaran: "Eksekutif",
      status: "waiting",
      processStage: "loket",
      createdAt: new Date().toISOString(),
      registrationType: 'online',
      visitType: 'SEKARANG',
      visitDate: new Date().toISOString().substring(0, 10),
      namaDokter: "Dr. Citra Dewi, Sp.S",
      penanggungJawab: "Dr. Citra Dewi", // Fast Track data
      alasanFastTrack: "Pasien Eksekutif prioritas", // Fast Track data
    },
    {
      no: 16,
      jamPanggil: "16:30",
      barcode: seedBarcodeE4,
      noAntrian: `EA016 | Online - ${seedBarcodeE4}`, // Counter 16: Non-fast track Eksekutif
      shift: "Shift 1",
      klinik: "THT",
      fastTrack: "TIDAK",
      pembayaran: "Eksekutif",
      status: "waiting",
      processStage: "loket",
      createdAt: new Date().toISOString(),
      registrationType: 'online',
      visitType: 'SEKARANG',
      visitDate: new Date().toISOString().substring(0, 10),
      namaDokter: "Dr. Dedi Kurniawan, Sp.THT",
      penanggungJawab: null,
      alasanFastTrack: null,
    },
  ];

  const cloneSeed = () => seedPatients.map(p => ({ ...p }));

  // Initialize counters from seed data to ensure numbering continues correctly
  // Counter SHARED untuk semua payment group dan semua jenis pasien
  const initializeCountersFromSeed = () => {
    if (typeof window === 'undefined') return; // Skip in SSR
    
    const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
    
    // Parse seed data to find max counter (SHARED untuk semua)
    let maxCounter = 0;
    
    seedPatients.forEach(patient => {
      if (!patient.noAntrian) return;
      
      // Extract queue number from noAntrian (format: "F-RA001 | ..." or "RA001 | ..." or "EA001 | ...")
      // Remove "F-" prefix untuk mendapatkan nomor asli
      const queueNumberMatch = patient.noAntrian.match(/^(?:F-)?([RE])([A-N])(\d+)/);
      if (!queueNumberMatch) return;
      
      const loketLetter = queueNumberMatch[2]; // A-N
      const number = parseInt(queueNumberMatch[3], 10); // 001-999
      
      // Calculate counter from loket and number
      // Loket A = 1-999, Loket B = 1000-1998, etc.
      const loketIndex = loketLetter.charCodeAt(0) - 65; // A=0, B=1, etc.
      const counter = (loketIndex * 999) + number;
      
      // Update max counter (shared untuk semua)
      if (counter > maxCounter) {
        maxCounter = counter;
      }
    });
    
    // Initialize localStorage counter (SHARED untuk semua payment group)
    if (maxCounter > 0) {
      const counterKey = `queue_counter_loket_shared_${today}`;
      const existing = localStorage.getItem(counterKey);
      if (!existing || parseInt(existing, 10) < maxCounter) {
        localStorage.setItem(counterKey, maxCounter.toString());
      }
    }
  };

  // Initialize counters from seed data
  initializeCountersFromSeed();

  // Initialize state - will be automatically hydrated from localStorage by pinia-plugin-persistedstate
  // If localStorage has data, it will override these defaults
  const allPatients = ref(cloneSeed());
  const quotaUsed = ref(5);
  const currentProcessingPatient = ref({
    loket: null,
    klinik: null,
    penunjang: null,
  });

  // Daftar klinik untuk dropdown diambil 1 pintu dari clinicStore
  const kliniks = computed(() => {
    const baseList = typeof clinicStore.getClinicsForDropdown === 'function'
      ? clinicStore.getClinicsForDropdown()
      : [];

    // Bentuk objek disesuaikan dengan yang dipakai di useQueue (id, name, kode)
    return baseList.map((c) => ({
      id: c.id,
      name: c.name,
      kode: c.kode,
      icon: c.icon,
      available: c.available,
    }));
  });

  // Penunjang data - reference dari penunjangStore (single source of truth)
  // Menggunakan computed untuk reactive reference
  const penunjangs = computed(() => {
    // Get penunjang list from penunjangStore dan map ke format yang diharapkan
    const penunjangList = penunjangStore.penunjangList || [];
    return penunjangList.map(p => ({
      id: p.id,
      name: p.nama || p.name, // Support both nama and name for backward compatibility
      kode: p.kode
    }));
  });

  // Computed - Filter berdasarkan process stage dan status
  const getPatientsByStage = (stage) => {
    return computed(() => {
      const patients = allPatients.value.filter(p => p.processStage === stage);
      
      // Debug log
      console.log(`getPatientsByStage(${stage}):`, patients.length, 'patients');
      if (patients.length > 0) {
        console.log('Sample patient properties:', Object.keys(patients[0]));
        console.log('Sample fastTrack values:', patients.map(p => p.fastTrack));
      }
      
      return {
        all: patients,
        waiting: patients.filter(p => p.status === 'waiting'), // Pasien yang sudah dipanggil, menunggu check-in
        menunggu: patients.filter(p => p.status === 'menunggu'), // Pasien yang belum dipanggil
        diLoket: patients.filter(p => p.status === 'di-loket'),
        terlambat: patients.filter(p => p.status === 'terlambat'),
        pending: patients.filter(p => p.status === 'pending'),
      };
    });
  };

  // Total pasien per stage
  const getTotalPasienByStage = (stage) => {
    return computed(() => 
      allPatients.value.filter(p => p.processStage === stage).length
    );
  };

  const totalPasien = computed(() => allPatients.value.length);

  const resetPatients = () => {
    allPatients.value = cloneSeed();
    quotaUsed.value = 5;
    currentProcessingPatient.value = { loket: null, klinik: null, penunjang: null };
  };

  // Actions
  const callNext = (adminType = 'loket') => {
    const stageMap = {
      'loket': 'loket',
      'klinik': 'klinik',
      'penunjang': 'penunjang'
    };
    
    const targetStage = stageMap[adminType];
    // Prioritaskan pasien dengan status 'menunggu' (yang belum dipanggil)
    const nextPatient = allPatients.value.find(p => 
      p.status === 'menunggu' && p.processStage === targetStage
    ) || allPatients.value.find(p => 
      p.status === 'waiting' && p.processStage === targetStage
    );

    if (!nextPatient) {
      return { success: false, message: "Tidak ada pasien selanjutnya" };
    }

    // Hitung kuota yang tersedia
    const menungguCount = allPatients.value.filter(p => 
      p.status === 'menunggu' && p.processStage === targetStage
    ).length;
    const diLoketCount = allPatients.value.filter(p => 
      p.status === 'di-loket' && p.processStage === targetStage
    ).length;
    const availableQuota = 150 - diLoketCount;

    if (availableQuota <= 0) {
      return { success: false, message: "Kuota sudah penuh" };
    }
    
    if (menungguCount === 0) {
      return { success: false, message: "Tidak ada pasien yang menunggu untuk dipanggil" };
    }

    // Langsung update status menjadi 'waiting' (sudah dipanggil, bisa check-in)
    const callTimestamp = new Date().toISOString();
    const index = allPatients.value.findIndex(p => p.no === nextPatient.no);
    if (index !== -1) {
      allPatients.value[index] = { 
        ...allPatients.value[index], 
        status: "waiting", // Status "waiting" = sudah dipanggil, bisa check-in
        lastCalledAt: callTimestamp // Track waktu panggilan untuk multiple calls
      };
    }

    return {
      success: true,
      message: `Memanggil pasien ${nextPatient.noAntrian.split(" |")[0]}`,
    };
  };

  const callMultiplePatients = (count, adminType = 'loket') => {
    const stageMap = {
      'loket': 'loket',
      'klinik': 'klinik',
      'penunjang': 'penunjang'
    };
    
    const targetStage = stageMap[adminType];
    // Prioritaskan pasien dengan status 'menunggu' (yang belum dipanggil)
    const menungguList = allPatients.value.filter(p => 
      p.status === 'menunggu' && p.processStage === targetStage
    );
    const waitingList = allPatients.value.filter(p => 
      p.status === 'waiting' && p.processStage === targetStage
    );
    
    // Gabungkan: menunggu dulu, baru waiting
    const combinedList = [...menungguList, ...waitingList];

    if (combinedList.length === 0) {
      return { success: false, message: "Tidak ada pasien yang menunggu" };
    }

    // Hitung kuota yang tersedia
    const diLoketCount = allPatients.value.filter(p => 
      p.status === 'di-loket' && p.processStage === targetStage
    ).length;
    const availableQuota = 150 - diLoketCount;

    // Kuota yang bisa dipanggil = min(count yang diminta, jumlah pasien menunggu, kuota tersedia)
    const maxCallable = Math.min(count, menungguList.length, availableQuota);
    
    if (maxCallable <= 0) {
      if (menungguList.length === 0) {
        return { success: false, message: "Tidak ada pasien yang menunggu untuk dipanggil" };
      }
      if (availableQuota <= 0) {
        return { success: false, message: "Kuota sudah penuh. Tidak bisa memanggil pasien lagi" };
      }
    }

    const patientsToCall = combinedList.slice(0, maxCallable);

    // Langsung update status menjadi 'waiting'
    const callTimestamp = new Date().toISOString();
    patientsToCall.forEach((patient) => {
      const index = allPatients.value.findIndex(p => p.no === patient.no);
      if (index !== -1) {
        allPatients.value[index] = { 
          ...allPatients.value[index], 
          status: "waiting",
          lastCalledAt: callTimestamp // Track waktu panggilan untuk multiple calls
        };
      }
    });

    return {
      success: true,
      message: `Memanggil ${patientsToCall.length} pasien`,
    };
  };

  const processPatient = (patient, action, adminType = 'loket') => {
    const patientCode = patient.noAntrian.split(" |")[0];
    let message = "";
    
    // Find patient index for reactive update
    const patientIndex = allPatients.value.findIndex(p => p.no === patient.no);
    
    if (patientIndex === -1) {
      return { success: false, message: "Pasien tidak ditemukan" };
    }

    switch (action) {
      case "check-in":
        // Jika check-in di loket, pindahkan ke klinik dengan status di-loket
        if (adminType === 'loket') {
          allPatients.value[patientIndex] = {
            ...allPatients.value[patientIndex],
            status: "di-loket",
            processStage: "klinik"
          };
          message = `Pasien ${patientCode} berhasil check in dan masuk ke Tabel Loket Klinik`;
        } 
        // Jika check-in di klinik, selesai
        else if (adminType === 'klinik') {
          allPatients.value[patientIndex] = {
            ...allPatients.value[patientIndex],
            status: "processed"
          };
          message = `Pasien ${patientCode} berhasil check in di Klinik`;
        }
        // Jika check-in di penunjang, selesai
        else if (adminType === 'penunjang') {
          allPatients.value[patientIndex] = {
            ...allPatients.value[patientIndex],
            status: "processed"
          };
          message = `Pasien ${patientCode} berhasil check in di Penunjang`;
        }
        
        // Clear current processing di admin yang melakukan check-in
        if (currentProcessingPatient.value[adminType]?.no === patient.no) {
          currentProcessingPatient.value[adminType] = null;
        }
        break;

      case "terlambat":
        allPatients.value[patientIndex] = {
          ...allPatients.value[patientIndex],
          status: "terlambat"
        };
        if (currentProcessingPatient.value[adminType]?.no === patient.no) {
          currentProcessingPatient.value[adminType] = null;
        }
        message = `Pasien ${patientCode} ditandai terlambat`;
        break;

      case "pending":
        allPatients.value[patientIndex] = {
          ...allPatients.value[patientIndex],
          status: "pending"
        };
        if (currentProcessingPatient.value[adminType]?.no === patient.no) {
          currentProcessingPatient.value[adminType] = null;
        }
        message = `Pasien ${patientCode} di-pending`;
        break;

      case "aktifkan": {
        const currentStatus = allPatients.value[patientIndex].status;
        if (currentStatus === "terlambat" || currentStatus === "pending") {
          // PERBAIKAN: Update dengan cara yang Vue reactive
          allPatients.value[patientIndex] = {
            ...allPatients.value[patientIndex],
            status: "di-loket"
          };
          message = `Pasien ${patientCode} diaktifkan kembali dan masuk ke tabel Di Loket`;
        } else {
          message = `Pasien ${patientCode} tidak dapat diaktifkan (status: ${currentStatus})`;
        }
        break;
      }

      case "proses": {
        // Ambil data terbaru dari array
        const patient = allPatients.value[patientIndex];
        
        // Jika pasien memiliki status "pending" atau "terlambat", ubah menjadi "di-loket"
        // agar pasien masuk ke kategori diLoketPatients dan ditampilkan sebagai "diproses"
        const currentStatus = patient.status;
        const shouldUpdateStatus = currentStatus === "pending" || currentStatus === "terlambat";
        
        // Jika adminType adalah 'loket', pastikan ada loket assignment
        if (adminType === 'loket') {
          // Pastikan antrian yang diproses memiliki loket assignment
          const currentLoket = patient.loket || getDefaultLoket();
          const currentLoketId = patient.loketId || 1;
          
          // Update patient dengan loket assignment dan status (jika perlu)
          const updatedPatient = {
            ...patient,
            loket: patient.loket || currentLoket,
            loketId: patient.loketId || currentLoketId,
            // Ubah status menjadi "di-loket" jika sebelumnya "pending" atau "terlambat"
            ...(shouldUpdateStatus && { status: "di-loket" })
          };
          
          allPatients.value[patientIndex] = updatedPatient;
          // Set currentProcessingPatient dengan data terbaru
          currentProcessingPatient.value[adminType] = updatedPatient;
        } else {
          // Untuk adminType selain loket, update status jika perlu
          if (shouldUpdateStatus) {
            const updatedPatient = {
              ...patient,
              status: "di-loket"
            };
            allPatients.value[patientIndex] = updatedPatient;
            currentProcessingPatient.value[adminType] = updatedPatient;
          } else {
            currentProcessingPatient.value[adminType] = patient;
          }
        }
        message = `Memproses pasien ${patientCode}`;
        break;
      }
    }

    return { success: true, message };
  };

  const processNextQueue = (adminType = 'loket') => {
    const stageMap = {
      'loket': 'loket',
      'klinik': 'klinik',
      'penunjang': 'penunjang'
    };
    
    const targetStage = stageMap[adminType];
    const nextPatient = allPatients.value.find(p => 
      p.status === 'di-loket' && p.processStage === targetStage
    );

    if (!nextPatient) {
      return { success: false, message: "Tidak ada pasien di loket yang dapat diproses" };
    }

    // Set sebagai current processing patient
    currentProcessingPatient.value[adminType] = nextPatient;

    return {
      success: true,
      message: `Memproses pasien ${nextPatient.noAntrian.split(" |")[0]}`,
    };
  };

  const createAntreanKlinik = (klinik, patient = null, adminType = 'loket') => {
    const newNo = allPatients.value.length + 1;
    const timestamp = new Date();
    const barcode = patient ? patient.barcode : generateBarcode([], allPatients);
    
    const newPatient = {
      no: newNo,
      jamPanggil: `${String(timestamp.getHours()).padStart(2, "0")}:${String(
        timestamp.getMinutes()
      ).padStart(2, "0")}`,
      barcode: barcode,
      noAntrian: `KL${String(newNo).padStart(4, "0")} | Klinik - ${barcode}`,
      shift: "Shift 1",
      klinik: klinik.name,
      fastTrack: "TIDAK",
      pembayaran: patient ? patient.pembayaran : "UMUM",
      status: "di-loket",
      processStage: "klinik",
      createdAt: timestamp.toISOString(),
      referencePatient: patient ? patient.noAntrian : null,
    };

    allPatients.value.push(newPatient);
    
    // Increment counter setelah barcode digunakan
    if (!patient) {
      incrementBarcodeCounter();
    }

    return {
      success: true,
      message: `Antrean klinik ${klinik.name} berhasil dibuat dan masuk ke Tabel Loket Klinik`,
      patient: newPatient,
    };
  };

  const createAntreanPenunjang = (penunjang, patient = null, adminType = 'loket') => {
    const newNo = allPatients.value.length + 1;
    const timestamp = new Date();
    const barcode = patient ? patient.barcode : generateBarcode([], allPatients);

    const newPatient = {
      no: newNo,
      jamPanggil: `${String(timestamp.getHours()).padStart(2, "0")}:${String(
        timestamp.getMinutes()
      ).padStart(2, "0")}`,
      barcode: barcode,
      noAntrian: `PN${String(newNo).padStart(4, "0")} | Penunjang - ${barcode}`,
      shift: "Shift 1",
      klinik: penunjang.name,
      fastTrack: "TIDAK",
      pembayaran: patient ? patient.pembayaran : "UMUM",
      status: "di-loket",
      processStage: "penunjang",
      createdAt: timestamp.toISOString(),
      referencePatient: patient ? patient.noAntrian : null,
    };

    allPatients.value.push(newPatient);
    
    // Increment counter setelah barcode digunakan
    if (!patient) {
      incrementBarcodeCounter();
    }

    return {
      success: true,
      message: `Antrean penunjang ${penunjang.name} berhasil dibuat dan masuk ke Tabel Loket Penunjang`,
      patient: newPatient,
    };
  };

  const createAntreanKlinikRuang = (klinikRuang, ruang, patient = null, adminType = 'klinik') => {
    const newNo = allPatients.value.length + 1;
    const timestamp = new Date();
    const barcode = patient ? patient.barcode : generateBarcode([], allPatients);

    // Generate nomor antrian baru dengan format: [huruf pertama poli + urutan abjad ruang + nomor antrian ruang]
    // Contoh: "Anak" ruang 1 = "AA001" (A dari Anak, A dari ruang 1, 001 nomor antrian)
    
    // 1. Ambil huruf pertama dari nama klinik/poli
    const firstLetter = klinikRuang.namaKlinik.charAt(0).toUpperCase();
    
    // 2. Konversi nomor ruang ke abjad (1 = A, 2 = B, 3 = C, dst)
    const ruangNumber = parseInt(ruang.nomorRuang) || 1;
    const ruangLetter = String.fromCharCode(64 + ruangNumber); // 64 = '@', 65 = 'A', 66 = 'B', dst
    
    // 3. Hitung nomor antrian ruang (dimulai dari 1, maksimal 3 digit)
    const roomQueues = allPatients.value.filter(p => 
      p.kodeKlinik === klinikRuang.kodeKlinik &&
      p.nomorRuang === ruang.nomorRuang &&
      p.processStage === 'klinik-ruang'
    );
    const queueNumber = roomQueues.length + 1;
    const queueNumberStr = String(queueNumber).padStart(3, "0");
    
    // 4. Format nomor antrian: AA001, AB002, dst
    const newNoAntrian = `${firstLetter}${ruangLetter}${queueNumberStr}`;

    const newPatient = {
      no: newNo,
      jamPanggil: `${String(timestamp.getHours()).padStart(2, "0")}:${String(
        timestamp.getMinutes()
      ).padStart(2, "0")}`,
      barcode: barcode,
      noAntrian: `${newNoAntrian} | ${klinikRuang.namaKlinik} - ${ruang.namaRuang}`,
      noAntrianRuang: `${klinikRuang.namaKlinik} - ${ruang.namaRuang} | ${newNoAntrian}`,
      shift: patient ? (patient.shift || "Shift 1") : "Shift 1",
      klinik: klinikRuang.namaKlinik,
      ruang: ruang.namaRuang,
      kodeKlinik: klinikRuang.kodeKlinik,
      nomorRuang: ruang.nomorRuang,
      nomorScreen: ruang.nomorScreen,
      fastTrack: patient ? (patient.fastTrack || "TIDAK") : "TIDAK",
      pembayaran: patient ? patient.pembayaran : "UMUM",
      status: "waiting",
      processStage: "klinik-ruang", // Set ke klinik-ruang langsung
      createdAt: timestamp.toISOString(),
      referencePatient: patient ? patient.noAntrian : null,
      sourcePatientNo: patient ? patient.no : null,
      // Tracking panggilan
      calledPemeriksaanAwal: false,
      calledTindakan: false,
      lastCalledAt: null,
      lastCalledTipeLayanan: null,
    };

    allPatients.value.push(newPatient);
    
    // Increment counter setelah barcode digunakan
    if (!patient) {
      incrementBarcodeCounter();
    }

    return {
      success: true,
      message: `Antrean ${klinikRuang.namaKlinik} Ruang ${ruang.nomorRuang} berhasil dibuat: ${newNoAntrian}`,
      patient: newPatient,
    };
  };

  // Pindah pasien ke klinik ruang lain dengan nomor antrian tetap
  const pindahKlinikRuang = (patient, targetKlinikRuang, targetRuang) => {
    const patientIndex = allPatients.value.findIndex(p => p.no === patient.no);
    
    if (patientIndex === -1) {
      return { success: false, message: "Pasien tidak ditemukan" };
    }

    const currentPatient = allPatients.value[patientIndex];
    
    // Jika pasien sudah punya antrean klinik ruang, update antreannya
    if (currentPatient.processStage === 'klinik-ruang' && currentPatient.tipeLayanan) {
      const baseNoAntrian = currentPatient.noAntrian?.split(" |")[0] || currentPatient.barcode || '';
      
      // Update dengan klinik dan ruang baru, tapi nomor antrian tetap sama
      allPatients.value[patientIndex] = {
        ...currentPatient,
        klinik: targetKlinikRuang.namaKlinik,
        ruang: targetRuang.namaRuang,
        kodeKlinik: targetKlinikRuang.kodeKlinik,
        nomorRuang: targetRuang.nomorRuang,
        nomorScreen: targetRuang.nomorScreen,
        // Nomor antrian tetap sama
        noAntrian: `${baseNoAntrian} | ${targetKlinikRuang.namaKlinik} - ${targetRuang.namaRuang} - ${currentPatient.tipeLayanan}`,
        noAntrianRuang: `${targetKlinikRuang.namaKlinik} - ${targetRuang.namaRuang} | ${baseNoAntrian}`
      };
      
      // Clear current processing dari ruang lama jika ada
      const oldKey = `klinik-ruang-${currentPatient.kodeKlinik}-${currentPatient.nomorRuang}`;
      if (currentProcessingPatient.value[oldKey]?.no === currentPatient.no) {
        currentProcessingPatient.value[oldKey] = null;
      }
    } else {
      // Pasien belum digenerate tiket, hanya update ruang
      allPatients.value[patientIndex] = {
        ...currentPatient,
        klinik: targetKlinikRuang.namaKlinik,
        ruang: targetRuang.namaRuang,
        kodeKlinik: targetKlinikRuang.kodeKlinik,
        nomorRuang: targetRuang.nomorRuang,
        nomorScreen: targetRuang.nomorScreen
      };
    }

    return {
      success: true,
      message: `Pasien berhasil dipindah ke ${targetKlinikRuang.namaKlinik} Ruang ${targetRuang.nomorRuang}`,
      patient: allPatients.value[patientIndex]
    };
  };

  // Konsultasi: pindah pasien ke klinik ruang lain dengan nomor antrian baru (prefix K- atau KF-)
  const konsultasiKlinikRuang = (patient, targetKlinikRuang, targetRuang, tipeLayanan = 'Pemeriksaan Awal') => {
    const patientIndex = allPatients.value.findIndex(p => p.no === patient.no);
    
    if (patientIndex === -1) {
      return { success: false, message: "Pasien tidak ditemukan" };
    }

    const sourcePatient = allPatients.value[patientIndex];
    
    // Cek apakah sudah ada antrean konsultasi di ruang tujuan
    const existingKonsultasi = allPatients.value.find(p => 
      p.referencePatient === sourcePatient.noAntrian &&
      p.kodeKlinik === targetKlinikRuang.kodeKlinik &&
      p.nomorRuang === targetRuang.nomorRuang &&
      p.processStage === 'klinik-ruang' &&
      (p.noAntrian?.startsWith('K-') || p.noAntrian?.startsWith('KF-'))
    );

    if (existingKonsultasi) {
      return { 
        success: false, 
        message: `Pasien sudah memiliki antrean konsultasi di ${targetKlinikRuang.namaKlinik} Ruang ${targetRuang.nomorRuang}` 
      };
    }

    // Generate queue number untuk konsultasi
    const roomQueues = allPatients.value.filter(p => 
      p.kodeKlinik === targetKlinikRuang.kodeKlinik &&
      p.nomorRuang === targetRuang.nomorRuang &&
      p.tipeLayanan === tipeLayanan &&
      p.processStage === 'klinik-ruang' &&
      (p.noAntrian?.startsWith('K-') || p.noAntrian?.startsWith('KF-'))
    );
    
    const queueNumber = roomQueues.length + 1;
    const prefix = tipeLayanan === 'Pemeriksaan Awal' ? 'PA' : 'TD';
    
    // Tentukan prefix konsultasi: KF- untuk Fast Track, K- untuk normal
    const isFastTrack = sourcePatient.fastTrack === "YA";
    const konsultasiPrefix = isFastTrack ? 'KF-' : 'K-';
    const queueNumberStr = String(queueNumber).padStart(3, "0");
    const newNoAntrian = `${konsultasiPrefix}${prefix}${queueNumberStr}`;
    
    const newNo = allPatients.value.length + 1;
    const timestamp = new Date();

    const newPatient = {
      no: newNo,
      jamPanggil: `${String(timestamp.getHours()).padStart(2, "0")}:${String(
        timestamp.getMinutes()
      ).padStart(2, "0")}`,
      barcode: sourcePatient.barcode,
      noAntrian: `${newNoAntrian} | ${targetKlinikRuang.namaKlinik} - ${targetRuang.namaRuang} - ${tipeLayanan}`,
      noAntrianRuang: `${targetKlinikRuang.namaKlinik} - ${targetRuang.namaRuang} | ${newNoAntrian}`,
      shift: sourcePatient.shift || "Shift 1",
      klinik: targetKlinikRuang.namaKlinik,
      ruang: targetRuang.namaRuang,
      kodeKlinik: targetKlinikRuang.kodeKlinik,
      nomorRuang: targetRuang.nomorRuang,
      nomorScreen: targetRuang.nomorScreen,
      tipeLayanan: tipeLayanan,
      fastTrack: sourcePatient.fastTrack || "TIDAK",
      pembayaran: sourcePatient.pembayaran || "UMUM",
      status: "waiting",
      processStage: "klinik-ruang",
      createdAt: sourcePatient.createdAt || timestamp.toISOString(), // Gunakan createdAt dari pasien awal
      referencePatient: sourcePatient.noAntrian,
      sourcePatientNo: sourcePatient.no,
      isKonsultasi: true, // Flag untuk konsultasi
    };

    allPatients.value.push(newPatient);

    return {
      success: true,
      message: `Antrean konsultasi berhasil dibuat: ${newNoAntrian} untuk ${targetKlinikRuang.namaKlinik} Ruang ${targetRuang.nomorRuang}`,
      patient: newPatient,
    };
  };

  // Scan barcode dan generate antrean klinik ruang baru
  const scanAndCreateAntreanKlinikRuang = (barcodeInput, klinikRuang, ruang, tipeLayanan = 'Pemeriksaan Awal') => {
    // Clean input - remove whitespace and handle prefix letters
    const cleanInput = String(barcodeInput).trim().toUpperCase();
    // Remove leading letters if any (e.g., "J200730100005" -> "200730100005")
    const numericInput = cleanInput.replace(/^[A-Z]+/, '');
    
    // Find patient by barcode or noAntrian
    const sourcePatient = allPatients.value.find(p => {
      // Exact barcode match
      if (p.barcode === cleanInput || p.barcode === numericInput) return true;
      
      // Check if noAntrian includes the input
      const noAntrianUpper = (p.noAntrian || '').toUpperCase();
      if (noAntrianUpper.includes(cleanInput) || noAntrianUpper.includes(numericInput)) return true;
      
      // Try extracting number from noAntrian
      const noAntrianNumber = noAntrianUpper.match(/([A-Z]+)(\d+)/);
      if (noAntrianNumber) {
        const extractedNumber = noAntrianNumber[2];
        if (extractedNumber.includes(numericInput) || numericInput.includes(extractedNumber)) return true;
      }
      
      return false;
    });

    if (!sourcePatient) {
      return { success: false, message: "Pasien tidak ditemukan. Pastikan barcode/nomor antrian benar." };
    }

    // Check if patient already has antrean klinik ruang for this room
    const existingAntrean = allPatients.value.find(p => 
      p.referencePatient === sourcePatient.noAntrian &&
      p.kodeKlinik === klinikRuang.kodeKlinik &&
      p.nomorRuang === ruang.nomorRuang &&
      p.processStage === 'klinik-ruang'
    );

    if (existingAntrean) {
      return { 
        success: false, 
        message: `Pasien sudah memiliki antrean di ${klinikRuang.namaKlinik} Ruang ${ruang.nomorRuang}` 
      };
    }

    // Generate queue number for this specific room and tipeLayanan
    const roomQueues = allPatients.value.filter(p => 
      p.kodeKlinik === klinikRuang.kodeKlinik &&
      p.nomorRuang === ruang.nomorRuang &&
      p.tipeLayanan === tipeLayanan &&
      p.processStage === 'klinik-ruang' &&
      !p.noAntrian?.startsWith('K-') && // Exclude konsultasi
      !p.noAntrian?.startsWith('KF-') // Exclude konsultasi Fast Track
    );
    
    const queueNumber = roomQueues.length + 1;
    const prefix = tipeLayanan === 'Pemeriksaan Awal' ? 'PA' : 'TD';
    
    // Tentukan prefix untuk Fast Track: F- untuk Fast Track
    const isFastTrack = sourcePatient.fastTrack === "YA";
    const fastTrackPrefix = isFastTrack ? 'F-' : '';
    const queueNumberStr = String(queueNumber).padStart(3, "0");
    const newNoAntrian = `${fastTrackPrefix}${prefix}${queueNumberStr}`;
    
    const newNo = allPatients.value.length + 1;
    const timestamp = new Date();

    const newPatient = {
      no: newNo,
      jamPanggil: `${String(timestamp.getHours()).padStart(2, "0")}:${String(
        timestamp.getMinutes()
      ).padStart(2, "0")}`,
      barcode: sourcePatient.barcode,
      noAntrian: `${newNoAntrian} | ${klinikRuang.namaKlinik} - ${ruang.namaRuang} - ${tipeLayanan}`,
      noAntrianRuang: `${klinikRuang.namaKlinik} - ${ruang.namaRuang} | ${newNoAntrian}`,
      shift: sourcePatient.shift || "Shift 1",
      klinik: klinikRuang.namaKlinik,
      ruang: ruang.namaRuang,
      kodeKlinik: klinikRuang.kodeKlinik,
      nomorRuang: ruang.nomorRuang,
      nomorScreen: ruang.nomorScreen,
      tipeLayanan: tipeLayanan,
      fastTrack: sourcePatient.fastTrack || "TIDAK",
      pembayaran: sourcePatient.pembayaran || "UMUM",
      status: "waiting",
      processStage: "klinik-ruang",
      createdAt: sourcePatient.createdAt || timestamp.toISOString(), // Gunakan createdAt dari pasien awal
      referencePatient: sourcePatient.noAntrian,
      sourcePatientNo: sourcePatient.no,
    };

    allPatients.value.push(newPatient);

    return {
      success: true,
      message: `Antrean ${tipeLayanan} berhasil dibuat: ${newPatient.noAntrian.split(" |")[0]} untuk ${klinikRuang.namaKlinik} Ruang ${ruang.nomorRuang}`,
      patient: newPatient,
    };
  };

  // Get patients by klinik and ruang
  const getPatientsByKlinikRuang = (kodeKlinik, nomorRuang, tipeLayanan = null) => {
    return computed(() => {
      let patients = allPatients.value.filter(p => 
        p.kodeKlinik === kodeKlinik &&
        p.nomorRuang === nomorRuang &&
        p.processStage === 'klinik-ruang'
      );

      if (tipeLayanan) {
        patients = patients.filter(p => p.tipeLayanan === tipeLayanan);
      }

      return {
        all: patients,
        waiting: patients.filter(p => p.status === 'waiting'),
        diLoket: patients.filter(p => p.status === 'di-loket'),
        terlambat: patients.filter(p => p.status === 'terlambat'),
        pending: patients.filter(p => p.status === 'pending'),
      };
    });
  };

  // Call next patient for a specific room and tipeLayanan
  const callNextKlinikRuang = (kodeKlinik, nomorRuang, tipeLayanan, allowMultiple = false) => {
    const patients = allPatients.value.filter(p => 
      p.kodeKlinik === kodeKlinik &&
      p.nomorRuang === nomorRuang &&
      p.tipeLayanan === tipeLayanan &&
      p.processStage === 'klinik-ruang' &&
      (p.status === 'waiting' || (allowMultiple && p.status === 'di-loket'))
    ).sort((a, b) => {
      // Sort by status priority first
      const statusPriority = {
        'waiting': 1,
        'di-loket': 2
      };
      const priorityDiff = (statusPriority[a.status] || 99) - (statusPriority[b.status] || 99);
      if (priorityDiff !== 0) return priorityDiff;
      
      // Then sort by queue number (extract from noAntrian)
      const numA = parseInt(a.noAntrian.match(/\d+/)?.[0] || '999');
      const numB = parseInt(b.noAntrian.match(/\d+/)?.[0] || '999');
      return numA - numB;
    });

    if (patients.length === 0) {
      return { success: false, message: `Tidak ada antrian ${tipeLayanan} yang menunggu di ruang ini` };
    }

    const nextPatient = patients[0];
    const patientIndex = allPatients.value.findIndex(p => p.no === nextPatient.no);
    
    if (patientIndex !== -1) {
      // If allowMultiple, we can call even if already di-loket (just update timestamp)
      // Otherwise, only update if status is waiting
      if (allowMultiple || nextPatient.status === 'waiting') {
        allPatients.value[patientIndex] = {
          ...allPatients.value[patientIndex],
          status: "di-loket",
          lastCalledAt: new Date().toISOString() // Track last call time
        };
      }
    }

    return {
      success: true,
      message: `Memanggil pasien ${nextPatient.noAntrian.split(" |")[0]} untuk ${tipeLayanan}`,
      patient: allPatients.value[patientIndex],
    };
  };

  // Process patient in klinik ruang (set as current processing)
  const processPatientKlinikRuang = (patient, action, kodeKlinik, nomorRuang) => {
    const patientIndex = allPatients.value.findIndex(p => p.no === patient.no);
    
    if (patientIndex === -1) {
      return { success: false, message: "Pasien tidak ditemukan" };
    }

    const patientCode = patient.noAntrian.split(" |")[0];
    const key = `klinik-ruang-${kodeKlinik}-${nomorRuang}`;
    let message = "";

    switch (action) {
      case "proses":
        // Set as current processing for this room (1 pasien, tidak dipisah per tipe layanan)
        currentProcessingPatient.value = {
          ...currentProcessingPatient.value,
          [key]: allPatients.value[patientIndex]
        };
        message = `Memproses pasien ${patientCode}`;
        break;

      case "selesai":
        allPatients.value[patientIndex] = {
          ...allPatients.value[patientIndex],
          status: "processed"
        };
        // Clear current processing
        currentProcessingPatient.value[key] = null;
        message = `Pasien ${patientCode} selesai diproses`;
        break;

      case "terlambat":
        allPatients.value[patientIndex] = {
          ...allPatients.value[patientIndex],
          status: "terlambat"
        };
        currentProcessingPatient.value[key] = null;
        message = `Pasien ${patientCode} ditandai terlambat`;
        break;

      case "pending":
        allPatients.value[patientIndex] = {
          ...allPatients.value[patientIndex],
          status: "pending"
        };
        currentProcessingPatient.value[key] = null;
        message = `Pasien ${patientCode} di-pending`;
        break;
    }

    return { success: true, message };
  };

  const changeKlinik = (patient, newKlinik, adminType = 'loket') => {
    const patientIndex = allPatients.value.findIndex((p) => p.no === patient.no);
    
    if (patientIndex !== -1) {
      // Update dengan cara yang Vue reactive
      allPatients.value[patientIndex] = {
        ...allPatients.value[patientIndex],
        klinik: newKlinik.name
      };
      
      // Update current processing if it's the same patient
      if (currentProcessingPatient.value[adminType]?.no === patient.no) {
        currentProcessingPatient.value[adminType] = {
          ...currentProcessingPatient.value[adminType],
          klinik: newKlinik.name
        };
      }

      return {
        success: true,
        message: `Klinik berhasil diubah ke ${newKlinik.name}`,
      };
    }

    return { success: false, message: "Pasien tidak ditemukan" };
  };

  const getCurrentProcessing = (adminType) => {
    return computed(() => currentProcessingPatient.value[adminType]);
  };

  const setCurrentProcessing = (patient, adminType) => {
    currentProcessingPatient.value[adminType] = patient;
  };

  // Helper function untuk generate nomor antrean baru
  // Format: R/E + Loket (A-N) + 3 digit
  // Format: R/E (jenis pelayanan Reguler/Eksekutif) + A-N (nomor loket) + 3 digit angka
  // Contoh: RA001, EA001, RB001, RB002
  // - R = Reguler (untuk pasien Reguler/BPJS)
  // - E = Eksekutif (untuk pasien Eksekutif/Grand Pavilion)
  // IMPORTANT: Counter SHARED untuk semua payment group (JKN/UMUM) dan semua jenis (fast track/non-fast track)
  // Prefix "F-" hanya untuk menandai status fast track, bukan untuk memisahkan counter
  // Setiap loket menampung maksimal 999 nomor (001-999)
  const generateQueueNumber = (clinic, paymentType, isEksekutif = false) => {
    // Tentukan prefix jenis pelayanan: R untuk Reguler, E untuk Eksekutif (Grand Pavilion)
    const serviceType = isEksekutif ? 'E' : 'R';
    
    // Counter SHARED untuk semua payment group dan semua jenis pasien
    // Tidak ada pemisahan counter berdasarkan payment group atau fast track
    const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
    const counterKey = `queue_counter_loket_shared_${today}`;
    
    // Get current counter dari localStorage
    let counter = 0;
    if (typeof window !== 'undefined') {
      const stored = localStorage.getItem(counterKey);
      counter = stored ? parseInt(stored, 10) : 0;
    }
    
    // Increment counter
    counter = counter + 1;
    
    // Tentukan loket berdasarkan counter
    // Loket A untuk 1-999, B untuk 1000-1998, C untuk 2000-2997, dst sampai N (14 loket)
    // Setiap loket menampung maksimal 999 nomor (001-999)
    // Loket index: 0=A, 1=B, 2=C, ..., 13=N
    const loketIndex = Math.floor((counter - 1) / 999); // 0 untuk A, 1 untuk B, dst
    
    // Jika loket melebihi N (14 loket, index 13), wrap kembali ke A
    // Maksimal 14 loket (A-N), jadi maksimal counter per hari = 14 * 999 = 13986
    // Jika melebihi, reset counter ke 1
    if (loketIndex > 13) {
      counter = 1;
      if (typeof window !== 'undefined') {
        localStorage.setItem(counterKey, '1');
      }
      // Format: R/E + Loket A + 001
      return `${serviceType}A001`;
    }
    
    // Loket letter (A-N)
    const loketLetter = String.fromCharCode(65 + loketIndex); // 65 = 'A', 66 = 'B', dst
    
    // Nomor dalam loket (1-999, di-display sebagai 001-999)
    // counter 1-999 → loket A, nomor 001-999
    // counter 1000-1998 → loket B, nomor 001-999
    const numberInLoket = ((counter - 1) % 999) + 1;
    const numberPart = String(numberInLoket).padStart(3, '0');
    
    // Save counter back to localStorage
    if (typeof window !== 'undefined') {
      localStorage.setItem(counterKey, counter.toString());
    }
    
    // Format: R/E + Loket + 3 digit
    // Contoh: RA001, RA002, ..., RA999, RB001, RB002, ...
    return `${serviceType}${loketLetter}${numberPart}`;
  };

  // Register patient from Anjungan (onsite registration)
  const registerPatientFromAnjungan = (clinic, paymentType, visitType = 'SEKARANG', visitDate = null, shift = 'Shift 1', namaDokter = null, isFastTrack = false, fastTrackData = null) => {
    const newNo = allPatients.value.length > 0 
      ? Math.max(...allPatients.value.map(p => p.no)) + 1 
      : 1;
    
    const timestamp = new Date();
    const visitDateTime = visitDate ? new Date(visitDate) : timestamp;
    const jamPanggil = visitDate 
      ? `${String(visitDateTime.getHours()).padStart(2, "0")}:${String(visitDateTime.getMinutes()).padStart(2, "0")}`
      : `${String(timestamp.getHours()).padStart(2, "0")}:${String(timestamp.getMinutes()).padStart(2, "0")}`;
    
    // Generate barcode dengan format: YYMMDD + 5 digit sequential
    const barcode = generateBarcode([], allPatients);
    
    // Tentukan apakah pasien Eksekutif/Grand Pavilion (jika ada namaDokter, berarti Eksekutif)
    const isEksekutif = namaDokter !== null && namaDokter !== undefined && namaDokter !== '';
    
    // Generate nomor antrean dengan format baru: R/E + Loket (A-N) + 3 digit
    // Format: RA001 (Reguler), EA001 (Eksekutif/Grand Pavilion), RB001, RB002, dll
    // Untuk Fast Track, tambahkan prefix "F-" di depan: F-RA001, F-EA001, dll
    const queueNumber = generateQueueNumber(clinic, paymentType, isEksekutif);
    const finalQueueNumber = isFastTrack ? `F-${queueNumber}` : queueNumber;
    const noAntrian = `${finalQueueNumber} | Onsite - ${barcode}`;
    
    // Status awal untuk pasien dari anjungan adalah "menunggu" (belum dipanggil)
    // Hanya setelah dipanggil oleh admin loket, status berubah menjadi "waiting" (bisa check-in)
    const status = 'menunggu';
    
    const newPatient = {
      no: newNo,
      jamPanggil: jamPanggil,
      barcode: barcode,
      noAntrian: noAntrian,
      shift: shift,
      klinik: clinic.name || clinic,
      fastTrack: isFastTrack ? "YA" : "TIDAK",
      pembayaran: paymentType,
      status: status,
      processStage: "loket",
      createdAt: timestamp.toISOString(),
      registrationType: 'onsite',
      visitType: visitType,
      visitDate: visitDate || timestamp.toISOString().substring(0, 10),
      namaDokter: namaDokter || null, // Nama dokter hanya untuk pasien Eksekutif
      // Fast Track data
      penanggungJawab: (isFastTrack && fastTrackData) ? fastTrackData.penanggungJawab : null,
      alasanFastTrack: (isFastTrack && fastTrackData) ? fastTrackData.alasanFastTrack : null,
    };

    allPatients.value.push(newPatient);
    
    // IMPORTANT: Increment counter SETELAH barcode benar-benar digunakan untuk membuat pasien
    // Ini mencegah counter naik meskipun barcode tidak digunakan
    // registerPatientFromAnjungan selalu membuat pasien baru, jadi selalu increment counter
    incrementBarcodeCounter();

    return {
      success: true,
      message: `Pendaftaran ${clinic.name || clinic} untuk kunjungan ${visitType === 'SEKARANG' ? 'HARI INI' : visitDate} dengan pembayaran ${paymentType} berhasil diproses.`,
      patient: newPatient,
    };
  };

  // Check-in patient (update status from waiting to di-loket)
  // IMPORTANT: Hanya menggunakan 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
  const checkInPatient = (patientIdOrBarcode) => {
    console.log('🔍 checkInPatient called with:', patientIdOrBarcode);
    console.log('📊 Total patients in store:', allPatients.value.length);
    
    // Clean input - remove whitespace and normalize
    const cleanInput = String(patientIdOrBarcode).trim();
    
    // PRIORITAS: Hanya cari dengan EXACT barcode match (case-insensitive, whitespace-insensitive)
    // Format barcode: YYMMDD + 5 digit (contoh: 26011500001)
    // Jangan gunakan fallback ke noAntrian atau no karena bisa menyebabkan false positive
    const patientIndex = allPatients.value.findIndex(p => {
      // Normalize barcode untuk comparison
      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 (patientIndex === -1) {
      console.log('❌ Patient not found. Searched for barcode:', cleanInput);
      console.log('📋 Available barcodes (first 10):', allPatients.value.slice(0, 10).map(p => ({
        no: p.no,
        barcode: p.barcode,
        noAntrian: p.noAntrian?.split(' |')[0]
      })));
      return { success: false, message: `Pasien dengan barcode ${cleanInput} tidak ditemukan. Pastikan barcode benar (format: YYMMDD + 5 digit, contoh: 26011500001).` };
    }

    // IMPORTANT: Get fresh patient data from array to avoid stale data
    // Use the patientIndex we found earlier, but get fresh data from array
    const patient = allPatients.value[patientIndex];
    console.log('✅ Patient found (fresh):', {
      no: patient.no,
      barcode: patient.barcode,
      noAntrian: patient.noAntrian,
      status: patient.status,
      processStage: patient.processStage
    });
    
    // Only allow check-in if status is waiting (sudah dipanggil) or pending
    // Pasien dengan status "menunggu" belum bisa check-in (belum dipanggil)
    if (patient.status === 'menunggu') {
      console.log('⚠️ Patient status is menunggu (belum dipanggil):', patient.status);
      return { 
        success: false, 
        message: `Pasien belum dipanggil oleh admin loket. Mohon menunggu hingga nomor antrean Anda dipanggil.` 
      };
    }
    
    // Check if already checked in
    if (patient.status === 'di-loket') {
      console.log('⚠️ Patient already checked in:', patient.status);
      return { 
        success: false, 
        message: `Pasien sudah melakukan check-in sebelumnya. Status saat ini: ${patient.status}` 
      };
    }
    
    if (patient.status !== 'waiting' && patient.status !== 'pending') {
      console.log('⚠️ Patient status is not waiting/pending:', patient.status);
      return { 
        success: false, 
        message: `Pasien tidak dapat check-in. Status saat ini: ${patient.status}` 
      };
    }

    // Update status to di-loket using the patientIndex
    allPatients.value[patientIndex] = {
      ...allPatients.value[patientIndex],
      status: "di-loket",
    };
    
    console.log('✅ Check-in successful, patient status updated to di-loket');

    return {
      success: true,
      message: `Check-in berhasil. Pasien ${patient.noAntrian.split(" |")[0]} siap diproses di loket.`,
      patient: allPatients.value[patientIndex],
    };
  };

  // State persistence is handled automatically by pinia-plugin-persistedstate
  // No need for manual watch or save logic

  return {
    // State
    allPatients,
    quotaUsed,
    currentProcessingPatient,
    kliniks,
    penunjangs,

    // Computed
    totalPasien,

    // Actions
    callNext,
    callMultiplePatients,
    processPatient,
    createAntreanKlinik,
    createAntreanPenunjang,
    createAntreanKlinikRuang,
    scanAndCreateAntreanKlinikRuang,
    getPatientsByKlinikRuang,
    callNextKlinikRuang,
    processPatientKlinikRuang,
    changeKlinik,
    pindahKlinikRuang,
    konsultasiKlinikRuang,
    processNextQueue,
    getPatientsByStage,
    getTotalPasienByStage,
    getCurrentProcessing,
    setCurrentProcessing,
    registerPatientFromAnjungan,
    checkInPatient,
    generateQueueNumber,
  };
}, {
  persist: {
    key: 'queue-store-state',
    storage: typeof window !== 'undefined' ? localStorage : undefined,
    paths: ['allPatients', 'quotaUsed', 'currentProcessingPatient'],
    serializer: {
      deserialize: JSON.parse,
      serialize: JSON.stringify,
    },
    restore: (value) => {
      // Ensure allPatients is always an array
      if (value && value.allPatients && !Array.isArray(value.allPatients)) {
        value.allPatients = [];
      }
      return value;
    },
  },
});