document.addEventListener('alpine:init', () => {
	Alpine.data("dashboard", () => ({
		// dashboard
		today: "",
		filter: { date1: "", date2: "" },
		list: [],
		isLoading: false,
		counters: { Pend: 0, Coll: 0, Recv: 0, Inc: 0, Fin: 0, Total: 0 },

		// Toast queue to prevent DOM accumulation
		_toastQueue: [],
		_maxToasts: 3,

		selectedPrinter: localStorage.getItem('selectedPrinter') || 'zebracs2',
		
		initSelectedPrinter() {
			this.$watch('selectedPrinter', value => {
				localStorage.setItem('selectedPrinter', value);
			});
		},
		// PDF Generation Dialog
		isGenerateDialogOpen: false,
		generateAccessnumber: null,
		generateLang: 0,
		statusColor: {
			Pend: 'bg-white text-black font-bold',
			PartColl: 'bg-[#ff99aa] text-black font-bold',
			Coll: 'bg-[#d63031] text-white font-bold',
			PartRecv: 'bg-[#a0c0d9] text-black font-bold',
			Recv: 'bg-[#0984e3] text-white font-bold',
			Inc: 'bg-[#ffff00] text-black font-bold',
			Fin: 'bg-[#008000] text-white font-bold',
		},
		statusRowBg: {
			Pend: 'bg-white text-black',
			PartColl: 'bg-[#ff99aa] text-black',
			Coll: 'bg-[#d63031] text-white',
			PartRecv: 'bg-[#a0c0d9] text-black',
			Recv: 'bg-[#0984e3] text-white',
			Inc: 'bg-[#ffff00] text-black',
			Fin: 'bg-[#008000] text-white',
		},
		filterTable: "",
		filterKey: 'Total',
		statusMap: {
			Total: [],
			Pend: ['Pend'],
			Coll: ['Coll', 'PartColl'],
			Recv: ['Recv', 'PartRecv'],
			Inc: ['Inc'],
			Fin: ['Fin'],
		},

		// Status order for sorting (Pend -> Coll -> Recv -> Inc -> Fin)
		statusOrder: { Pend: 1, PartColl: 2, Coll: 3, PartRecv: 4, Recv: 5, Inc: 6, Fin: 7 },

		// Sorting & Pagination
		sortCol: 'REQDATE',
		sortAsc: false,
		currentPage: 1,
		pageSize: 30,

		// Cached computed properties to prevent memory leak
		filtered: [],
		sorted: [],
		paginated: [],
		totalPages: 1,
		validatedCount: 0,

		sort(col) {
			if (this.sortCol === col) {
				this.sortAsc = !this.sortAsc;
			} else {
				this.sortCol = col;
				this.sortAsc = true;
			}
			this.computeSorted();
			this.computePaginated();
		},

		nextPage() {
			if (this.currentPage < this.totalPages) {
				this.currentPage++;
				this.computePaginated();
			}
		},

		prevPage() {
			if (this.currentPage > 1) {
				this.currentPage--;
				this.computePaginated();
			}
		},

		setFilterKey(key) {
			this.filterKey = key;
			this.computeFiltered();
			this.computeSorted();
			this.computeTotalPages();
			this.computePaginated();
		},

		setFilterTable(value) {
			this.filterTable = value;
			this.currentPage = 1;
			this.computeFiltered();
			this.computeSorted();
			this.computeTotalPages();
			this.computePaginated();
		},

		// Compute methods - called only when dependencies change
		computeFiltered() {
			let filteredList = this.list;
			if (this.filterKey === 'Validated') {
				filteredList = filteredList.filter(item => this.isValidated(item));
			} else {
				const validStatuses = this.statusMap[this.filterKey];
				if (validStatuses.length > 0) {
					filteredList = filteredList.filter(item => validStatuses.includes(item.STATS));
				}
			}
			if (this.filterTable) {
				const searchTerm = this.filterTable.toLowerCase();
				filteredList = filteredList.filter(item =>
					Object.values(item).some(value =>
						String(value).toLowerCase().includes(searchTerm)
					)
				);
			}
			this.filtered = filteredList;
		},

		computeSorted() {
			this.sorted = this.filtered.slice().sort((a, b) => {
				// First sort by status (Pend -> Coll -> Recv -> Inc -> Fin)
				let statusA = this.statusOrder[a.STATS] ?? 0;
				let statusB = this.statusOrder[b.STATS] ?? 0;
				if (statusA !== statusB) {
					return statusA - statusB;
				}
				
				// Then sort by selected column
				let modifier = this.sortAsc ? 1 : -1;
				if (a[this.sortCol] < b[this.sortCol]) return -1 * modifier;
				if (a[this.sortCol] > b[this.sortCol]) return 1 * modifier;
				return 0;
			});
		},

		computePaginated() {
			const start = (this.currentPage - 1) * this.pageSize;
			const end = start + this.pageSize;
			this.paginated = this.sorted.slice(start, end);
		},

		computeTotalPages() {
			this.totalPages = Math.ceil(this.filtered.length / this.pageSize) || 1;
		},

		init() {
			this.today = new Date().toISOString().slice(0, 10);
			this.filter.date1 = this.today;
			this.filter.date2 = this.today;		
			
			this.initSelectedPrinter();
			
			// Initial load only - no auto-refresh
			this.fetchList();
		},

		fetchList() {
			this.isLoading = true;
			this.list = [];
			let param = new URLSearchParams(this.filter).toString();
			for (let k in this.counters) { this.counters[k] = 0; }
			fetch(`${BASEURL}/api/requests?${param}`, {
				method: 'GET',
				headers: { 'Content-Type': 'application/json' },
			}).then(res => res.json()).then(data => {
				this.list = data.data ?? [];
				this.filterKey = 'Total';
				this.list.forEach(item => {
					if (this.counters[item.STATS] !== undefined) { this.counters[item.STATS]++; this.counters.Total++; }
					else {
						if (item.STATS == 'PartColl') { this.counters.Coll++; }
						else if (item.STATS == 'PartRecv') { this.counters.Recv++; }
						this.counters.Total++;
					}
				});
				// Compute derived data after list is loaded
				this.computeFiltered();
				this.computeValidatedCount();
				this.computeSorted();
				this.computeTotalPages();
				this.computePaginated();
			}).finally(() => {
				this.isLoading = false;
			});
		},

		reset() {
			this.filter.date1 = this.today;
			this.filter.date2 = this.today;
			this.fetchList();
		},

		isValidated(item) {
			return item.ISVAL == 1 && item.ISPENDING != 1;
		},

		computeValidatedCount() {
			this.validatedCount = this.list.filter(r => this.isValidated(r)).length;
		},

		/*
		sample dialog
		*/
		item: '',
		isDialogSampleOpen: false,
		isSampleLoading: false,

		openSampleDialog(accessnumber) {
			this.isDialogSampleOpen = true;
			this.fetchItem(accessnumber)
		},

		closeSampleDialog() {
			this.isDialogSampleOpen = false;
			this.item = null;
			this.item = [];
		},

		fetchItem(accessnumber) {
			this.isSampleLoading = true;
			this.item = [];
			fetch(`${BASEURL}/api/samples/${accessnumber}`, { method: 'GET', headers: { 'Content-Type': 'application/json' } })
				.then(res => res.json()).then(data => {
					this.item = data.data ?? {};
					if (!Array.isArray(this.item.samples)) this.item.samples = [];
				}).finally(() => {
					this.isSampleLoading = false;
				});
		},

		collect(sampcode, accessnumber) {
			fetch(`${BASEURL}/api/samples/collect/${accessnumber}/${sampcode}`, {
				method: 'POST', headers: { 'Content-Type': 'application/json' }
			})
				.then(res => res.json()).then(data => {
					this.fetchItem(accessnumber);
				});
		},

		unreceive(sampcode, accessnumber) {
			if (!confirm(`Unreceive sample ${sampcode} from request ${accessnumber}?`)) { return; }
			fetch(`${BASEURL}/api/samples/unreceive/${accessnumber}/${sampcode}`, {
				method: 'POST', headers: { 'Content-Type': 'application/json' }
			})
				.then(res => res.json()).then(data => {
					this.fetchItem(accessnumber);
				});
		},

		/*
		unvalidate dialog
		*/
		isDialogUnvalOpen: false,
		unvalReason: '',
		unvalAccessnumber: null,
		openUnvalDialog(accessnumber) {
			this.unvalReason = '';
			this.isDialogUnvalOpen = true;
			this.unvalAccessnumber = accessnumber;
		},
		unvalidate(accessnumber, userid) {
			if (!confirm(`Unvalidate request ${accessnumber}?`)) { return; }
			fetch(`${BASEURL}/api/requests/validate/${accessnumber}`, {
				method: "DELETE",
				headers: { "Content-Type": "application/json" },
				body: JSON.stringify({ userid: `${userid}`, comment: this.unvalReason.trim() })
			}).then(response => {
				this.closeUnvalDialog();
				this.fetchList();
				console.log(`Unvalidate clicked for ${accessnumber}, by user ${userid}`);
			});
		},
		closeUnvalDialog() {
			this.isDialogUnvalOpen = false;
		},

		/*
		audit dialog
		*/
		isDialogAuditOpen: false,
		auditData: null,
		auditAccessnumber: null,
		auditTab: 'all',
		// Cached audit events to prevent memory leak
		_cachedAuditEvents: [],
		openAuditDialog(accessnumber) {
			this.auditAccessnumber = accessnumber;
			this.auditData = null;
			this._cachedAuditEvents = [];
			this.auditTab = 'all';
			this.isDialogAuditOpen = true;
			this.fetchAudit(accessnumber);
		},
		closeAuditDialog() {
			this.isDialogAuditOpen = false;
			this.auditData = null;
			this._cachedAuditEvents = [];
			this.auditAccessnumber = null;
		},
		fetchAudit(accessnumber) {
			fetch(`${BASEURL}/api/requests/${accessnumber}/audit`, {
				method: 'GET',
				headers: { 'Content-Type': 'application/json' }
			}).then(res => res.json()).then(data => {
				this.auditData = data.data;
				this.computeAuditEvents();
			});
		},
		computeAuditEvents() {
			if (!this.auditData) {
				this._cachedAuditEvents = [];
				return;
			}
			let events = [];
			let id = 0;
			
			this.auditData.validation.forEach(v => {
				let desc = `Validated by ${v.user}`;
				if (v.type === 'UNVAL') {
					desc = `Unvalidated by ${v.user}`;
				}
				events.push({
					id: id++,
					category: 'validation',
					type: v.type,
					description: desc,
					datetime: v.datetime,
					user: v.user,
					reason: v.reason || null
				});
			});
			
			this.auditData.sample_collection.forEach(s => {
				events.push({
					id: id++,
					category: 'sample',
					type: s.action === 'COLLECTED' ? 'COLLECT' : 'UNRECEIVE',
					description: `Tube ${s.tubenumber}: ${s.action} by ${s.user}`,
					datetime: s.datetime,
					user: s.user,
					reason: null
				});
			});

			this.auditData.tube_received?.forEach(t => {
				events.push({
					id: id++,
					category: 'receive',
					type: 'RECEIVED',
					description: `${t.sampletype} received by ${t.user}`,
					datetime: t.datetime,
					user: t.user,
					reason: null
				});
			});

			this.auditData.pdf_generation?.forEach(p => {
				let desc = '';
				if (p.type === 'PRINT') {
					desc = `Printed report (${p.status})`;
				} else if (p.type === 'GEN_PDF') {
					desc = `PDF Generated (${p.status})`;
				} else if (p.type === 'REGEN_PDF') {
					desc = `PDF Regenerated (${p.status})`;
				}
				events.push({
					id: id++,
					category: 'pdf',
					type: p.type,
					description: desc,
					datetime: p.datetime,
					user: p.user,
					reason: null
				});
			});

			this._cachedAuditEvents = events.sort((a, b) => {
				if (!a.datetime) return 1;
				if (!b.datetime) return -1;
				return new Date(a.datetime) - new Date(b.datetime);
			});
		},
		get getAllAuditEvents() {
			return this._cachedAuditEvents;
		},
		get getFilteredAuditEvents() {
			if (this.auditTab === 'all') return this._cachedAuditEvents;
			return this._cachedAuditEvents.filter(e => e.category === this.auditTab);
		},


		/*
		PDF Generation Dialog methods
		*/
		openGenerateDialog(accessnumber) {
			this.generateAccessnumber = accessnumber;
			this.generateLang = 0;
			this.isGenerateDialogOpen = true;
		},

		closeGenerateDialog() {
			this.isGenerateDialogOpen = false;
			this.generateAccessnumber = null;
		},

		async generatePdfFromDialog() {
			const eng = this.generateLang === 1 ? '?eng=1' : '?eng=0';
			
			try {
				const res = await fetch(`${BASEURL}report/${this.generateAccessnumber}/pdf${eng}`);
				const data = await res.json();
				
				if (data.success) {
					this.showToast(`${data.lang} PDF queued for download`, 'success');
				} else {
					this.showToast('PDF generation failed', 'error');
				}
			} catch (e) {
				this.showToast('PDF generation failed - try again', 'error');
			}
		},

		printAllLabels(accessnumber) {
			const printer = this.selectedPrinter || 'lab';
			fetch(`${BASEURL}/label/all/${accessnumber}/${printer}`, { method: 'GET' })
				.then(res => {
					if (res.ok) {
						this.showToast('All labels printed', 'success');
					} else {
						this.showToast('Print failed', 'error');
					}
				})
				.catch(() => this.showToast('Print failed', 'error'));
		},
		
		printCollectionLabel(accessnumber) {
			const printer = this.selectedPrinter || 'lab';
			fetch(`${BASEURL}/label/coll/${accessnumber}/${printer}`, { method: 'GET' })
				.then(res => {
					if (res.ok) {
						this.showToast('Collection label printed', 'success');
					} else {
						this.showToast('Print failed', 'error');
					}
				})
				.catch(() => this.showToast('Print failed', 'error'));
		},
		
		printSampleLabel(accessnumber, sampcode) {
			const printer = this.selectedPrinter || 'lab';
			fetch(`${BASEURL}/label/dispatch/${accessnumber}/${sampcode}/${printer}`, { method: 'GET' })
				.then(res => {
					if (res.ok) {
						this.showToast('Sample label printed', 'success');
					} else {
						this.showToast('Print failed', 'error');
					}
				})
				.catch(() => this.showToast('Print failed', 'error'));
		},

		/*
		preview dialog methods
		*/
		isDialogPreviewOpen: false,
		previewAccessnumber: null,
		previewItem: null,
		isPreviewIframeLoaded: false,
		isPreviewValidating: false,
		openPreviewDialog(item) {
			this.previewItem = item;
			this.previewAccessnumber = item.SP_ACCESSNUMBER;
			this.isPreviewIframeLoaded = false;
			this.isPreviewValidating = false;
			this.isDialogPreviewOpen = true;
		},
		closePreviewDialog() {
			this.isDialogPreviewOpen = false;
			this.previewItem = null;
			this.previewAccessnumber = null;
			this.isPreviewIframeLoaded = false;
			// Clear iframe src to release memory
			const iframe = this.$refs.previewIframe;
			if (iframe) iframe.src = 'about:blank';
		},
		getPreviewUrl() {
			if(this.previewAccessnumber != null) {
			  return `${BASEURL}report/${this.previewAccessnumber}`;
      }
		},
		onPreviewIframeLoad() {
			this.isPreviewIframeLoaded = true;
		},
		async validateFromPreview(accessnumber, userid) {
			if (!this.isPreviewIframeLoaded || this.isPreviewValidating) return;
			
			this.isPreviewValidating = true;
			try {
				const res = await fetch(`${BASEURL}/api/requests/validate/${accessnumber}`, {
					method: 'POST',
					headers: { 'Content-Type': 'application/json' }
				});
				const data = await res.json();
				this.isPreviewValidating = false;
				
				if (data.val) {
					this.showToast(`Validated (val${data.val}): ${accessnumber}`, 'success');
					
					// Generate PDF if second validation (val2) succeeded
					if (data.val === 2) {
						try {
							const pdfRes = await fetch(`${BASEURL}report/${accessnumber}/pdf`);
							const pdfData = await pdfRes.json();
							
							if (pdfData.success) {
								this.showToast(`${pdfData.lang} PDF queued for download`, 'success');
							} else {
								this.showToast('PDF generation failed', 'error');
							}
						} catch (e) {
							this.showToast('PDF generation failed', 'error');
						}
					}
					
					this.fetchList();
					this.closePreviewDialog();
				} else if (data.message && data.message.includes('already validate')) {
					this.showToast('You have already validated this request', 'error');
				} else {
					this.showToast(data.message || 'Validation failed', 'error');
				}
			} catch (e) {
				this.isPreviewValidating = false;
				this.showToast('Validation failed', 'error');
			}
		},

		// English Result Dialog
		isDialogEngResultOpen: false,
		engResultAccessnumber: null,
		engResultItem: null,
		isCreatingEngResult: false,
		isEngResultIframeLoaded: false,

		openEngResultDialog(item) {
			this.engResultItem = item;
			this.engResultAccessnumber = item.SP_ACCESSNUMBER;
			this.isEngResultIframeLoaded = false;
			this.isCreatingEngResult = false;
			this.isDialogEngResultOpen = true;
		},

		closeEngResultDialog() {
			this.isDialogEngResultOpen = false;
			this.engResultAccessnumber = null;
			this.engResultItem = null;
			this.isEngResultIframeLoaded = false;
			this.isCreatingEngResult = false;
			// Clear iframe src to release memory
			const iframe = this.$refs.engResultIframe;
			if (iframe) iframe.src = 'about:blank';
		},

		getEngResultUrl() {
			if (this.engResultAccessnumber) {
				return `${BASEURL}report/${this.engResultAccessnumber}?eng=1`;
			}
			return '';
		},

		onEngResultIframeLoad() {
			this.isEngResultIframeLoaded = true;
		},

		async confirmCreateEngResult() {
			if (!this.engResultAccessnumber || this.isCreatingEngResult) return;

			this.isCreatingEngResult = true;
			try {
				const res = await fetch(`${BASEURL}/api/requests/${this.engResultAccessnumber}/eng`, {
					method: 'POST',
					headers: { 'Content-Type': 'application/json' }
				});
				const data = await res.json();
				this.isCreatingEngResult = false;

				if (data.status === 'success') {
					this.showToast('English result created successfully', 'success');
					this.closeEngResultDialog();
					this.fetchList();
				} else {
					this.showToast(data.message || 'Failed to create English result', 'error');
				}
			} catch (e) {
				this.isCreatingEngResult = false;
				this.showToast('Failed to create English result', 'error');
			}
		},

		showToast(message, type = 'success') {
			// Limit concurrent toasts to prevent DOM accumulation
			if (this._toastQueue.length >= this._maxToasts) {
				const oldToast = this._toastQueue.shift();
				if (oldToast && oldToast.parentNode) oldToast.remove();
			}
			
			const toast = document.createElement('div');
			toast.className = `alert alert-${type} fixed top-4 right-4 z-50`;
			toast.innerHTML = `<i class="fa ${type === 'error' ? 'fa-times-circle' : 'fa-check-circle'}"></i> ${message}`;
			document.body.appendChild(toast);
			this._toastQueue.push(toast);
			
			setTimeout(() => {
				toast.remove();
				const index = this._toastQueue.indexOf(toast);
				if (index > -1) this._toastQueue.splice(index, 1);
			}, 2000);
		},

		destroy() {
			// Clear large data arrays to free memory
			this.list = [];
			this.filtered = [];
			this.sorted = [];
			this.paginated = [];
			this.auditData = null;
			this._cachedAuditEvents = [];
			this.item = null;
			this.previewItem = null;
			this.engResultItem = null;
			// Clear any open dialogs and their iframe references
			if (this.$refs.previewIframe) this.$refs.previewIframe.src = 'about:blank';
			if (this.$refs.engResultIframe) this.$refs.engResultIframe.src = 'about:blank';
			// Clear any remaining toasts
			this._toastQueue.forEach(t => { if (t.parentNode) t.remove(); });
			this._toastQueue = [];
		},
	}));
});
