(function (window) {
	'use strict';

	/** Carta / Letter (pulgadas → mm). */
	var SHEET_WIDTH_MM = 215.9;
	var SHEET_HEIGHT_MM = 279.4;
	/** Media carta = mitad de carta (horizontal del rótulo). */
	var MEDIA_CARTA_HEIGHT_MM = 139.7;
	var LABELS_PER_PAGE = 2;

	function escapeHtml(value) {
		return String(value == null ? '' : value)
			.replace(/&/g, '&amp;')
			.replace(/</g, '&lt;')
			.replace(/>/g, '&gt;')
			.replace(/"/g, '&quot;');
	}

	function displayValue(value) {
		var text = String(value == null ? '' : value).trim();
		return text === '' ? '&nbsp;' : escapeHtml(text);
	}

	function getConfig() {
		var cfg = window.LogisticaAdmin && window.LogisticaAdmin.rotuloRollosPrintConfig;
		return cfg || {
			widthMm: 216,
			heightMm: 140,
			cssUrl: '',
			colorPalette: [
				'#7CB342', '#29B6F6', '#FF7043', '#AB47BC', '#FFA726', '#26A69A',
				'#EC407A', '#5C6BC0', '#8D6E63', '#78909C', '#66BB6A', '#42A5F5'
			]
		};
	}

	function colorForTamano(tamano, config) {
		var palette = (config && config.colorPalette) || getConfig().colorPalette || [];
		var key = String(tamano || '').trim().toLowerCase();
		if (!key || !palette.length) {
			return '#64748b';
		}
		var crc = crc32(key);
		return palette[Math.abs(crc) % palette.length];
	}

	function crc32(str) {
		var table = crc32.table;
		var crc = 0 ^ (-1);
		var i;

		if (!table) {
			table = crc32.table = [];
			for (i = 0; i < 256; i++) {
				var c = i;
				var j;
				for (j = 0; j < 8; j++) {
					c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1);
				}
				table[i] = c;
			}
		}

		for (i = 0; i < str.length; i++) {
			crc = (crc >>> 8) ^ table[(crc ^ str.charCodeAt(i)) & 0xFF];
		}

		return (crc ^ (-1)) | 0;
	}

	function splitAnchoLabel(anchoLabel, tamano) {
		var label = String(anchoLabel || '').trim();
		var size = String(tamano || '').trim();
		if (!label || !size) {
			return { prefix: label, size: size };
		}
		if (label.slice(-size.length).toUpperCase() === size.toUpperCase()) {
			return {
				prefix: label.slice(0, label.length - size.length).trim(),
				size: size
			};
		}
		return { prefix: label, size: '' };
	}

	/**
	 * Tamaño de impresión por rótulo: media carta horizontal (mitad de carta).
	 * El ancho/largo de config se usa como tope de diseño y se ajusta al hueco.
	 */
	function getPrintLabelSize(config) {
		var slotW = SHEET_WIDTH_MM;
		var slotH = MEDIA_CARTA_HEIGHT_MM;
		var wantW = Math.max(1, Number(config && config.widthMm) || 216);
		var wantH = Math.max(1, Number(config && config.heightMm) || 140);
		var scale = Math.min(slotW / wantW, slotH / wantH);

		// Llenar media carta para corte limpio (2 rótulos = 1 carta).
		return {
			widthMm: Math.round(slotW * 100) / 100,
			heightMm: Math.round(slotH * 100) / 100,
			designScale: scale
		};
	}

	function buildRollLabelHtml(job, config, options) {
		options = options || {};
		var accent = job.accent_color || colorForTamano(job.tamano, config);
		var parts = splitAnchoLabel(job.ancho_label || job.ancho || '', job.tamano || '');
		var prefixHtml = displayValue(parts.prefix);
		var sizeHtml = parts.size
			? ('<span class="logistica-roll-label__ancho-size" style="background-color:' + escapeHtml(accent) + ';">' + escapeHtml(parts.size) + '</span>')
			: '';
		var printSize = getPrintLabelSize(config);
		var widthMm = options.preview
			? (config && config.widthMm ? config.widthMm : 216)
			: printSize.widthMm;
		var heightMm = options.preview
			? (config && config.heightMm ? config.heightMm : 140)
			: printSize.heightMm;
		var labelClass = 'logistica-roll-label'
			+ (options.preview ? ' is-preview' : '')
			+ (options.printSlot ? ' is-print-slot' : '');
		var varsStyle = '--roll-label-w-mm:' + widthMm + ';--roll-label-h-mm:' + heightMm + ';';
		var sizeStyle = options.preview
			? (' style="' + varsStyle + 'width:100%;height:100%;"')
			: (' style="' + varsStyle + 'width:' + widthMm + 'mm;height:' + heightMm + 'mm;"');

		return (
			'<article class="' + labelClass + '"' + sizeStyle + ' data-accent="' + escapeHtml(accent) + '">' +
				'<section class="logistica-roll-label__block logistica-roll-label__block--ancho">' +
					'<header class="logistica-roll-label__head" style="background-color:' + escapeHtml(accent) + ';">ANCHO</header>' +
					'<div class="logistica-roll-label__value logistica-roll-label__value--ancho">' +
						'<span class="logistica-roll-label__ancho-prefix">' + prefixHtml + '</span>' + sizeHtml +
					'</div>' +
				'</section>' +
				'<div class="logistica-roll-label__split">' +
					'<section class="logistica-roll-label__block logistica-roll-label__block--half">' +
						'<header class="logistica-roll-label__head" style="background-color:' + escapeHtml(accent) + ';">LOTE</header>' +
						'<div class="logistica-roll-label__value">' + displayValue(job.lote) + '</div>' +
					'</section>' +
					'<section class="logistica-roll-label__block logistica-roll-label__block--half">' +
						'<header class="logistica-roll-label__head" style="background-color:' + escapeHtml(accent) + ';">PESO</header>' +
						'<div class="logistica-roll-label__value">' + displayValue(job.peso) + '</div>' +
					'</section>' +
				'</div>' +
				'<section class="logistica-roll-label__block logistica-roll-label__block--gramaje">' +
					'<header class="logistica-roll-label__head" style="background-color:' + escapeHtml(accent) + ';">GRAMAJE</header>' +
					'<div class="logistica-roll-label__value">' + displayValue(job.gramaje) + '</div>' +
				'</section>' +
			'</article>'
		);
	}

	function getEmbeddedPrintCss() {
		var labelW = SHEET_WIDTH_MM;
		var labelH = MEDIA_CARTA_HEIGHT_MM;

		return ''
			+ '@page{size:' + SHEET_WIDTH_MM + 'mm ' + SHEET_HEIGHT_MM + 'mm;margin:0;}'
			+ 'html,body{margin:0!important;padding:0!important;background:#fff!important;}'
			+ 'body.logistica-roll-label-print-doc{background:#fff!important;}'
			+ '.logistica-roll-label-print-page{'
			+ 'box-sizing:border-box;'
			+ 'display:flex;'
			+ 'flex-direction:column;'
			+ 'height:' + SHEET_HEIGHT_MM + 'mm;'
			+ 'margin:0;'
			+ 'padding:0;'
			+ 'page-break-after:always;'
			+ 'break-after:page;'
			+ 'width:' + SHEET_WIDTH_MM + 'mm;'
			+ '}'
			+ '.logistica-roll-label-print-page:last-child{'
			+ 'page-break-after:auto;'
			+ 'break-after:auto;'
			+ '}'
			+ '.logistica-roll-label{'
			+ 'background:#fff!important;'
			+ 'border:0.4cqw solid #111;'
			+ 'box-sizing:border-box;'
			+ 'color:#111;'
			+ 'container-type:size;'
			+ 'display:flex;'
			+ 'flex:0 0 ' + labelH + 'mm;'
			+ 'flex-direction:column;'
			+ 'font-family:Arial,Helvetica,sans-serif;'
			+ 'height:' + labelH + 'mm;'
			+ 'margin:0;'
			+ 'max-height:' + labelH + 'mm;'
			+ 'max-width:' + labelW + 'mm;'
			+ 'overflow:hidden;'
			+ 'page-break-after:auto;'
			+ 'page-break-inside:avoid;'
			+ 'break-inside:avoid;'
			+ 'width:' + labelW + 'mm;'
			+ '-webkit-print-color-adjust:exact;'
			+ 'print-color-adjust:exact;'
			+ '}'
			+ '.logistica-roll-label__block{border-bottom:0.35cqw solid #111;display:flex;flex-direction:column;min-height:0;}'
			+ '.logistica-roll-label__block:last-child{border-bottom:0;}'
			+ '.logistica-roll-label__block--ancho{flex:1.15 1 auto;}'
			+ '.logistica-roll-label__split{display:flex;flex:1 1 auto;min-height:0;}'
			+ '.logistica-roll-label__block--half{border-right:0.35cqw solid #111;flex:1 1 50%;min-width:0;}'
			+ '.logistica-roll-label__block--half:last-child{border-right:0;}'
			+ '.logistica-roll-label__block--gramaje{flex:0.85 0 auto;}'
			+ '.logistica-roll-label__head{'
			+ 'color:#111;'
			+ 'flex-shrink:0;'
			+ 'font-size:4.8cqw;'
			+ 'font-weight:800;'
			+ 'letter-spacing:0.05em;'
			+ 'line-height:1.05;'
			+ 'padding:2.8cqh 2cqw;'
			+ 'text-align:center;'
			+ 'text-transform:uppercase;'
			+ '-webkit-print-color-adjust:exact;'
			+ 'print-color-adjust:exact;'
			+ '}'
			+ '.logistica-roll-label__value{'
			+ 'align-items:center;'
			+ 'background:#fff;'
			+ 'box-sizing:border-box;'
			+ 'display:flex;'
			+ 'flex:1 1 auto;'
			+ 'font-size:10.5cqw;'
			+ 'font-weight:800;'
			+ 'justify-content:center;'
			+ 'line-height:1;'
			+ 'min-height:0;'
			+ 'overflow:hidden;'
			+ 'padding:1.8cqh 1.5cqw;'
			+ 'text-align:center;'
			+ 'width:100%;'
			+ 'word-break:break-word;'
			+ '}'
			+ '.logistica-roll-label__block--half .logistica-roll-label__value{font-size:8.8cqw;}'
			+ '.logistica-roll-label__block--gramaje .logistica-roll-label__value{font-size:11.2cqw;}'
			+ '.logistica-roll-label__value--ancho{font-size:8.2cqw;flex-wrap:wrap;gap:1.2cqw;}'
			+ '.logistica-roll-label__ancho-prefix{white-space:nowrap;}'
			+ '.logistica-roll-label__ancho-size{'
			+ 'border:0.15cqw solid rgba(17,17,17,0.35);'
			+ 'border-radius:0.8cqw;'
			+ 'color:#111;'
			+ 'display:inline-block;'
			+ 'font-size:1em;'
			+ 'font-weight:800;'
			+ 'padding:1.2cqh 2.2cqw;'
			+ 'white-space:nowrap;'
			+ '-webkit-print-color-adjust:exact;'
			+ 'print-color-adjust:exact;'
			+ '}'
			+ '@media print{'
			+ 'html,body{width:' + SHEET_WIDTH_MM + 'mm;height:auto;}'
			+ '.logistica-roll-label-print-page{-webkit-print-color-adjust:exact;print-color-adjust:exact;}'
			+ '*{-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important;}'
			+ '}';
	}

	function chunkJobs(jobs, size) {
		var chunks = [];
		var list = jobs || [];
		var i;

		for (i = 0; i < list.length; i += size) {
			chunks.push(list.slice(i, i + size));
		}

		return chunks;
	}

	function buildPrintDocument(jobs, config) {
		var pagesHtml = chunkJobs(jobs, LABELS_PER_PAGE).map(function (pageJobs) {
			var labels = pageJobs.map(function (job) {
				return buildRollLabelHtml(job, config, { printSlot: true });
			}).join('');

			return '<div class="logistica-roll-label-print-page">' + labels + '</div>';
		}).join('');

		return (
			'<!DOCTYPE html><html lang="es"><head><meta charset="utf-8">' +
			'<title>\u200b</title>' +
			'<style>' + getEmbeddedPrintCss() + '</style>' +
			'</head><body class="logistica-roll-label-print-doc">' +
			pagesHtml +
			'</body></html>'
		);
	}

	function removePrintFrame() {
		var frame = document.getElementById('logistica-roll-label-print-frame');
		if (frame && frame.parentNode) {
			frame.parentNode.removeChild(frame);
		}
	}

	function printLabels(jobs) {
		var config = getConfig();
		var html = buildPrintDocument(jobs, config);

		removePrintFrame();

		var iframe = document.createElement('iframe');
		iframe.id = 'logistica-roll-label-print-frame';
		iframe.setAttribute('aria-hidden', 'true');
		iframe.setAttribute('tabindex', '-1');
		iframe.style.cssText = 'border:0;clip:rect(0,0,0,0);height:0;overflow:hidden;position:fixed;right:0;bottom:0;width:0;';
		document.body.appendChild(iframe);

		return new Promise(function (resolve, reject) {
			var finished = false;

			function finish(error) {
				if (finished) {
					return;
				}
				finished = true;
				iframe.onload = null;
				setTimeout(removePrintFrame, 1500);
				if (error) {
					reject(error);
					return;
				}
				resolve({ count: jobs.length });
			}

			iframe.onload = function () {
				var printWindow = iframe.contentWindow;
				if (!printWindow) {
					finish(new Error('No se pudo preparar la impresión.'));
					return;
				}

				setTimeout(function () {
					try {
						printWindow.focus();
						printWindow.print();
						finish(null);
					} catch (printError) {
						finish(printError);
					}
				}, 600);
			};

			iframe.onerror = function () {
				finish(new Error('No se pudo cargar el documento de impresión.'));
			};

			iframe.srcdoc = html;
		});
	}

	function formFieldValue(form, name) {
		if (!form) {
			return '';
		}
		var field = form.querySelector('[data-rotulo-field="' + name + '"]');
		return field ? String(field.value || '').trim() : '';
	}

	function incrementLote(lote, offset) {
		var text = String(lote == null ? '' : lote).trim();
		var match;
		var prefix;
		var numStr;
		var suffix;
		var num;
		var padded;

		if (!text || offset === 0) {
			return text;
		}

		match = text.match(/^(\D*)(\d+)(\D*)$/);
		if (!match) {
			return text;
		}

		prefix = match[1];
		numStr = match[2];
		suffix = match[3];
		num = parseInt(numStr, 10) + offset;
		if (!Number.isFinite(num) || num < 0) {
			return text;
		}

		padded = String(num);
		if (numStr.length > padded.length) {
			padded = (new Array(numStr.length - padded.length + 1)).join('0') + padded;
		}

		return prefix + padded + suffix;
	}

	function canIncrementLote(lote) {
		return /^(\D*)(\d+)(\D*)$/.test(String(lote == null ? '' : lote).trim());
	}

	function getPesoForIndex(form, index) {
		var indexed;
		var single;

		if (!form) {
			return '';
		}

		indexed = form.querySelector('[data-rotulo-peso-index="' + index + '"]');
		if (indexed) {
			return String(indexed.value || '').trim();
		}

		single = form.querySelector('[data-rotulo-field="peso"]');
		return single ? String(single.value || '').trim() : '';
	}

	function buildJobsFromForm(form, ctx) {
		var numConsecutivo = Math.max(1, parseInt(formFieldValue(form, 'num_consecutivo'), 10) || 1);
		var numCopias = Math.max(1, parseInt(formFieldValue(form, 'num_copias'), 10) || 1);
		var baseLote = formFieldValue(form, 'lote');
		var jobs = [];
		var i;
		var c;
		var job;

		for (i = 0; i < numConsecutivo; i++) {
			job = {
				ancho_label: formFieldValue(form, 'ancho_label') || (ctx && ctx.ancho_label) || '',
				tamano: formFieldValue(form, 'tamano') || (ctx && ctx.tamano) || '',
				accent_color: formFieldValue(form, 'accent_color') || (ctx && ctx.accent_color) || '',
				lote: incrementLote(baseLote, i),
				peso: getPesoForIndex(form, i),
				gramaje: formFieldValue(form, 'gramaje')
			};
			for (c = 0; c < numCopias; c++) {
				jobs.push({
					ancho_label: job.ancho_label,
					tamano: job.tamano,
					accent_color: job.accent_color,
					lote: job.lote,
					peso: job.peso,
					gramaje: job.gramaje
				});
			}
		}

		return jobs;
	}

	function describeConsecutivoRange(form) {
		var num = Math.max(1, parseInt(formFieldValue(form, 'num_consecutivo'), 10) || 1);
		var lote = formFieldValue(form, 'lote');
		if (!lote) {
			return '';
		}
		if (num <= 1) {
			return 'Lote: ' + lote;
		}
		return 'Lotes: ' + lote + ' → ' + incrementLote(lote, num - 1) + ' (' + num + ')';
	}

	function validateJobs(jobs, form) {
		var list = jobs || [];
		var numConsecutivo = Math.max(1, parseInt(formFieldValue(form, 'num_consecutivo'), 10) || 1);

		if (!list.length) {
			return 'No hay rótulos para imprimir.';
		}
		if (!formFieldValue(form, 'tamano') && !formFieldValue(form, 'ancho_label')) {
			return 'Selecciona un ancho válido.';
		}
		if (!formFieldValue(form, 'lote')) {
			return 'Indica el lote.';
		}
		if (numConsecutivo > 1 && !canIncrementLote(formFieldValue(form, 'lote'))) {
			return 'El lote inicial debe incluir un número para generar lotes consecutivos.';
		}
		if (!formFieldValue(form, 'gramaje')) {
			return 'Indica el gramaje.';
		}
		return '';
	}

	function buildPreviewJobFromForm(form, ctx) {
		return {
			ancho_label: formFieldValue(form, 'ancho_label') || (ctx && ctx.ancho_label) || '',
			tamano: formFieldValue(form, 'tamano') || (ctx && ctx.tamano) || '',
			accent_color: formFieldValue(form, 'accent_color') || (ctx && ctx.accent_color) || '',
			lote: formFieldValue(form, 'lote'),
			peso: getPesoForIndex(form, 0),
			gramaje: formFieldValue(form, 'gramaje')
		};
	}

	function renderPreview(root, job) {
		if (!root) {
			return Promise.resolve();
		}

		var config = getConfig();
		var widthMm = config.widthMm || 216;
		var heightMm = config.heightMm || 140;

		root.innerHTML =
			'<div class="logistica-roll-label-preview-scaler" style="--roll-preview-w:' + widthMm + ';--roll-preview-h:' + heightMm + ';">' +
				buildRollLabelHtml(job || {}, config, { preview: true }) +
			'</div>';

		return Promise.resolve();
	}

	window.LogisticaRotuloRollosPrint = {
		buildRollLabelHtml: buildRollLabelHtml,
		buildJobsFromForm: buildJobsFromForm,
		validateJobs: validateJobs,
		describeConsecutivoRange: describeConsecutivoRange,
		incrementLote: incrementLote,
		buildPreviewJobFromForm: buildPreviewJobFromForm,
		renderPreview: renderPreview,
		printLabels: printLabels,
		colorForTamano: colorForTamano,
		getPrintLabelSize: getPrintLabelSize
	};
}(window));
