(function (global) {
	'use strict';

	var LUNCH_START = 720;
	var LUNCH_END = 780;

	var STATUS_COLORS = {
		pending: '#94a3b8',
		in_progress: '#3b82f6',
		done: '#10b981',
		delayed: '#ef4444'
	};

	var WEEK_CHART_RGB = [
		[15, 118, 110],
		[59, 130, 246],
		[245, 158, 11],
		[139, 92, 246],
		[236, 72, 153],
		[34, 197, 94],
		[239, 68, 68],
		[20, 184, 166],
		[99, 102, 241],
		[249, 115, 22],
		[148, 163, 184],
		[14, 165, 233]
	];

	function weekChartColor(index, alpha) {
		var rgb = WEEK_CHART_RGB[Math.abs(index) % WEEK_CHART_RGB.length];
		var opacity = Number.isFinite(Number(alpha)) ? Number(alpha) : 0.85;
		return 'rgba(' + rgb[0] + ', ' + rgb[1] + ', ' + rgb[2] + ', ' + opacity + ')';
	}

	function weekColorResolver(compareData, weeksCount) {
		var useDistinct = !!compareData.period_mode || weeksCount > 2;
		return function (index) {
			if (!useDistinct) {
				return index === 0 ? 'rgba(148, 163, 184, 0.85)' : 'rgba(15, 118, 110, 0.85)';
			}
			return weekChartColor(index);
		};
	}

	var chartInstances = {};
	var pedidosChartInstances = {};

	function formatDelta(value, suffix) {
		var num = Number(value);
		if (!Number.isFinite(num) || Math.abs(num) < 0.05) {
			return '';
		}
		var sign = num > 0 ? '+' : '';
		if (suffix === '%') {
			return sign + num.toLocaleString('es-CO', { maximumFractionDigits: 1 }) + '% vs ant.';
		}
		return sign + Math.round(num) + ' vs ant.';
	}

	function formatHours(minutes) {
		var value = Math.max(0, Math.round(Number(minutes) || 0));
		if (value < 60) {
			return value + ' min';
		}

		var h = Math.floor(value / 60);
		var m = value % 60;
		return h + ' h ' + m + ' min';
	}

	function formatPercent(value) {
		var num = Number(value);
		if (!Number.isFinite(num)) {
			return '0%';
		}
		return num.toLocaleString('es-CO', { maximumFractionDigits: 1 }) + '%';
	}

	function dayCapacityMinutes(hours, includeLunch, lunchStart, lunchEnd) {
		var start = Number(hours && hours.start);
		var end = Number(hours && hours.end);
		if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) {
			return 0;
		}

		var capacity = end - start;
		lunchStart = Number.isFinite(Number(lunchStart)) ? Number(lunchStart) : LUNCH_START;
		lunchEnd = Number.isFinite(Number(lunchEnd)) ? Number(lunchEnd) : LUNCH_END;
		if (includeLunch && start < lunchEnd && end > lunchStart) {
			capacity -= Math.max(0, Math.min(lunchEnd, end) - Math.max(lunchStart, start));
		}

		return Math.max(0, capacity);
	}

	function emptyByStatus() {
		return {
			pending: { count: 0, minutes: 0 },
			in_progress: { count: 0, minutes: 0 },
			done: { count: 0, minutes: 0 },
			delayed: { count: 0, minutes: 0 }
		};
	}

	function computeWeekMetrics(options) {
		options = options || {};

		var dayHours = options.dayHours || {};
		var days = options.days || [];
		var includeLunch = !!options.includeLunch;
		var lunchStart = options.lunchStart;
		var lunchEnd = options.lunchEnd;
		var isDayNonWorking = options.isDayNonWorking;
		var getDisplayItemsForDay = options.getDisplayItemsForDay;
		var tasks = options.tasks || [];

		var availableMinutes = 0;
		var occupiedMinutes = 0;
		var workingDays = 0;
		var byStatus = emptyByStatus();
		var delayMinutes = 0;
		var doneMinutes = 0;

		days.forEach(function (day) {
			var dayIndex = parseInt(day.index, 10);
			if (typeof isDayNonWorking === 'function' && isDayNonWorking(dayIndex)) {
				return;
			}

			var slot = dayHours[String(dayIndex)] || dayHours[dayIndex] || {};
			var capacity = dayCapacityMinutes(slot, includeLunch, lunchStart, lunchEnd);
			if (capacity <= 0) {
				return;
			}

			availableMinutes += capacity;
			workingDays += 1;
		});

		tasks.forEach(function (task) {
			var status = task.status || 'pending';
			if (!byStatus[status]) {
				status = 'pending';
			}

			var minutes = Math.max(0, Number(task.duration_minutes) || 0);
			byStatus[status].count += 1;
			byStatus[status].minutes += minutes;

			if (status === 'done') {
				doneMinutes += minutes;
			}
			if (status === 'delayed' || task.reschedule_delay) {
				delayMinutes += minutes;
			}
		});

		if (typeof getDisplayItemsForDay === 'function') {
			occupiedMinutes = 0;
			days.forEach(function (day) {
				var dayIndex = parseInt(day.index, 10);
				if (typeof isDayNonWorking === 'function' && isDayNonWorking(dayIndex)) {
					return;
				}
				getDisplayItemsForDay(dayIndex).forEach(function (item) {
					occupiedMinutes += Number(item.segment && item.segment.minutes) || 0;
				});
			});
		} else {
			occupiedMinutes = tasks.reduce(function (sum, task) {
				return sum + Math.max(0, Number(task.duration_minutes) || 0);
			}, 0);
		}

		var freeMinutes = Math.max(0, availableMinutes - occupiedMinutes);
		var utilizationPct = availableMinutes > 0 ? Math.round((occupiedMinutes / availableMinutes) * 1000) / 10 : 0;
		var efficiencyPct = occupiedMinutes > 0 ? Math.round((doneMinutes / occupiedMinutes) * 1000) / 10 : 0;

		return {
			workingDays: workingDays,
			availableMinutes: availableMinutes,
			occupiedMinutes: occupiedMinutes,
			freeMinutes: freeMinutes,
			delayMinutes: delayMinutes,
			doneMinutes: doneMinutes,
			utilizationPct: utilizationPct,
			efficiencyPct: efficiencyPct,
			taskCount: tasks.length,
			byStatus: byStatus
		};
	}

	function renderWeekPanel(container, metrics, statuses) {
		if (!container) {
			return;
		}

		metrics = metrics || {};
		statuses = statuses || {};

		if (!metrics.workingDays && !metrics.taskCount) {
			container.hidden = true;
			container.innerHTML = '';
			return;
		}

		container.hidden = false;

		var cards = [
			{
				label: 'Horas disponibles',
				value: formatHours(metrics.availableMinutes),
				hint: metrics.workingDays + ' días laborables'
			},
			{
				label: 'Horas ocupadas',
				value: formatHours(metrics.occupiedMinutes),
				hint: formatPercent(metrics.utilizationPct) + ' de la capacidad'
			},
			{
				label: 'Horas libres',
				value: formatHours(metrics.freeMinutes),
				hint: 'Capacidad sin programar'
			},
			{
				label: 'Eficiencia',
				value: formatPercent(metrics.efficiencyPct),
				hint: 'Terminado / programado'
			},
			{
				label: 'Tiempo retraso',
				value: formatHours(metrics.delayMinutes),
				hint: 'Actividades retrasadas'
			}
		];

		var statusHtml = Object.keys(byStatusSafe(metrics.byStatus)).map(function (key) {
			var row = metrics.byStatus[key];
			if (!row || !row.count) {
				return '';
			}
			var label = statuses[key] || key;
			return '<li class="logistica-planeacion__metrics-status logistica-planeacion__metrics-status--' + key + '">' +
				'<span class="logistica-planeacion__metrics-status-label">' + escapeHtml(label) + '</span>' +
				'<span class="logistica-planeacion__metrics-status-value">' + row.count + ' · ' + formatHours(row.minutes) + '</span>' +
			'</li>';
		}).join('');

		var utilization = Math.min(100, Math.max(0, Number(metrics.utilizationPct) || 0));

		container.innerHTML =
			'<div class="logistica-planeacion__metrics-week-head">' +
				'<h3 class="logistica-planeacion__metrics-title">Resumen semanal</h3>' +
				'<span class="logistica-planeacion__metrics-subtitle">' + metrics.taskCount + ' actividades</span>' +
			'</div>' +
			'<div class="logistica-planeacion__metrics-cards">' +
				cards.map(function (card) {
					return '<article class="logistica-planeacion__metrics-card">' +
						'<span class="logistica-planeacion__metrics-card-label">' + escapeHtml(card.label) + '</span>' +
						'<strong class="logistica-planeacion__metrics-card-value">' + escapeHtml(card.value) + '</strong>' +
						'<span class="logistica-planeacion__metrics-card-hint">' + escapeHtml(card.hint) + '</span>' +
					'</article>';
				}).join('') +
			'</div>' +
			(statusHtml ? '<ul class="logistica-planeacion__metrics-status-list">' + statusHtml + '</ul>' : '') +
			'<div class="logistica-planeacion__metrics-util-bar" aria-hidden="true">' +
				'<span style="width:' + utilization + '%"></span>' +
			'</div>';
	}

	function byStatusSafe(byStatus) {
		return byStatus || emptyByStatus();
	}

	function escapeHtml(text) {
		return String(text || '')
			.replace(/&/g, '&amp;')
			.replace(/</g, '&lt;')
			.replace(/>/g, '&gt;')
			.replace(/"/g, '&quot;');
	}

	function destroyPedidosCharts() {
		Object.keys(pedidosChartInstances).forEach(function (key) {
			if (pedidosChartInstances[key]) {
				pedidosChartInstances[key].destroy();
				pedidosChartInstances[key] = null;
			}
		});
	}

	function renderPedidosWeekPanel(container, pedidosData) {
		if (!container) {
			return;
		}

		pedidosData = pedidosData || {};
		var current = pedidosData.current || pedidosData.metrics || {};
		var comprometidos = Number(current.comprometidos) || 0;
		var aTiempo = Number(current.entregas_a_tiempo) || 0;
		var entregados = Number(current.entregados) || 0;
		var weekLabel = pedidosData.week_label || current.week_label || '';

		container.hidden = false;

		var cards = [
			{
				label: 'Cumplimiento',
				value: formatPercent(current.cumplimiento_pct),
				hint: comprometidos > 0
					? (aTiempo + ' de ' + comprometidos + ' comprometidos a tiempo')
					: 'Sin pedidos comprometidos esta semana'
			},
			{
				label: 'Entregas a tiempo',
				value: String(aTiempo),
				hint: entregados + ' entregados en la semana'
			},
			{
				label: 'Prórrogas',
				value: String(current.prorrogas || 0),
				hint: 'Con fecha de prórroga en la semana'
			},
			{
				label: 'Retrasos',
				value: String(current.retrasos || 0),
				hint: 'Fuera de fecha comprometida'
			},
			{
				label: 'Pedidos comprometidos',
				value: String(comprometidos),
				hint: 'Con fecha de entrega en la semana'
			}
		];

		container.innerHTML =
			'<div class="logistica-planeacion__metrics-week-head">' +
				'<h3 class="logistica-planeacion__metrics-title">' + escapeHtml('Resumen semanal') + '</h3>' +
				'<span class="logistica-planeacion__metrics-subtitle">' + escapeHtml(weekLabel ? ('Semana ' + weekLabel) : 'Semana actual') + '</span>' +
			'</div>' +
			'<div class="logistica-planeacion__metrics-cards">' +
				cards.map(function (card) {
					return '<article class="logistica-planeacion__metrics-card">' +
						'<span class="logistica-planeacion__metrics-card-label">' + escapeHtml(card.label) + '</span>' +
						'<strong class="logistica-planeacion__metrics-card-value">' + escapeHtml(card.value) + '</strong>' +
						'<span class="logistica-planeacion__metrics-card-hint">' + escapeHtml(card.hint) + '</span>' +
					'</article>';
				}).join('') +
			'</div>';
	}

	function getPedidosCanvas(root, name) {
		return root ? root.querySelector('[data-planeacion-pedidos-chart="' + name + '"]') : null;
	}

	function renderPedidosPeriodCharts(root, periodData, ChartLib) {
		ChartLib = resolveChartLib(ChartLib);
		var chartsWrap = root ? root.querySelector('[data-planeacion-pedidos-period-charts]') : null;
		var hint = root ? root.querySelector('[data-planeacion-pedidos-period-hint]') : null;

		if (!root || !periodData || !chartsWrap) {
			return;
		}

		var weeks = periodData.weeks || [];
		if (!weeks.length) {
			destroyPedidosCharts();
			chartsWrap.hidden = true;
			if (hint) {
				hint.textContent = 'No hay pedidos comprometidos en el período seleccionado.';
				hint.hidden = false;
			}
			return;
		}

		if (!ChartLib) {
			chartsWrap.hidden = true;
			if (hint) {
				hint.textContent = 'No se pudo cargar el componente de gráficos. Recargue la página.';
				hint.hidden = false;
			}
			return;
		}

		if (hint) {
			hint.hidden = true;
		}
		chartsWrap.hidden = false;
		destroyPedidosCharts();

		var labels = weeks.map(function (week) {
			return week.week_label || week.semana_inicio;
		});

		var cumplimientoCanvas = getPedidosCanvas(root, 'cumplimiento');
		if (cumplimientoCanvas) {
			pedidosChartInstances.cumplimiento = new ChartLib(cumplimientoCanvas, {
				type: 'line',
				data: {
					labels: labels,
					datasets: [{
						label: 'Cumplimiento %',
						data: weeks.map(function (w) { return Number(w.cumplimiento_pct) || 0; }),
						borderColor: 'rgba(15, 118, 110, 1)',
						backgroundColor: 'rgba(15, 118, 110, 0.12)',
						fill: true,
						tension: 0.25
					}]
				},
				options: chartLinePercentOptions()
			});
		}

		var entregasCanvas = getPedidosCanvas(root, 'entregas');
		if (entregasCanvas) {
			pedidosChartInstances.entregas = new ChartLib(entregasCanvas, {
				type: 'bar',
				data: {
					labels: labels,
					datasets: [
						{
							label: 'Comprometidos',
							data: weeks.map(function (w) { return Number(w.comprometidos) || 0; }),
							backgroundColor: 'rgba(148, 163, 184, 0.75)',
							borderRadius: 4
						},
						{
							label: 'A tiempo',
							data: weeks.map(function (w) { return Number(w.entregas_a_tiempo) || 0; }),
							backgroundColor: 'rgba(16, 185, 129, 0.85)',
							borderRadius: 4
						}
					]
				},
				options: chartBarOptions()
			});
		}

		var riesgosCanvas = getPedidosCanvas(root, 'riesgos');
		if (riesgosCanvas) {
			pedidosChartInstances.riesgos = new ChartLib(riesgosCanvas, {
				type: 'bar',
				data: {
					labels: labels,
					datasets: [
						{
							label: 'Prórrogas',
							data: weeks.map(function (w) { return Number(w.prorrogas) || 0; }),
							backgroundColor: 'rgba(245, 158, 11, 0.85)',
							borderRadius: 4
						},
						{
							label: 'Retrasos',
							data: weeks.map(function (w) { return Number(w.retrasos) || 0; }),
							backgroundColor: 'rgba(239, 68, 68, 0.78)',
							borderRadius: 4
						}
					]
				},
				options: chartBarOptions()
			});
		}
	}

	function destroyCharts() {
		Object.keys(chartInstances).forEach(function (key) {
			if (chartInstances[key]) {
				chartInstances[key].destroy();
				chartInstances[key] = null;
			}
		});
	}

	function getCanvas(root, name) {
		return root ? root.querySelector('[data-planeacion-chart="' + name + '"]') : null;
	}

	function resolveChartLib(ChartLib) {
		if (ChartLib && typeof ChartLib === 'function') {
			return ChartLib;
		}
		if (global.Chart && typeof global.Chart === 'function') {
			return global.Chart;
		}
		return null;
	}

	function renderWeekComparisonCharts(root, compareData, statuses, ChartLib) {
		ChartLib = resolveChartLib(ChartLib);
		if (!root || !compareData) {
			return;
		}

		var weeks = compareData.weeks || [];
		var chartsWrap = root.querySelector('[data-planeacion-metrics-charts]');
		var hint = root.querySelector('[data-planeacion-metrics-compare-hint]')
			|| root.querySelector('[data-planeacion-metrics-month-hint]');
		var label = root.querySelector('[data-planeacion-metrics-compare-label]')
			|| root.querySelector('[data-planeacion-metrics-month-label]');
		var periodLabel = root.querySelector('[data-planeacion-metrics-period-label]');
		var compareDetails = root.querySelector('.logistica-planeacion__metrics-compare')
			|| root.querySelector('.logistica-planeacion__metrics-month');

		if (periodLabel) {
			var periodText = compareData.comparison_label || '';
			periodLabel.textContent = periodText ? ' · ' + periodText : '';
		} else if (label) {
			var comparisonLabel = compareData.comparison_label || '';
			label.textContent = comparisonLabel ? ' · ' + comparisonLabel : '';
		}

		var hasData = compareData.period_mode ? weeks.length > 0 : !!compareData.has_saved_weeks;
		if (!weeks.length || !hasData) {
			if (chartsWrap) {
				chartsWrap.hidden = true;
			}
			if (hint) {
				hint.textContent = compareData.period_mode
					? 'No hay programación guardada en el período seleccionado.'
					: 'Aún no hay semanas guardadas para comparar. Programa actividades en la semana actual o anterior y espera el guardado automático.';
				hint.hidden = false;
			}
			destroyCharts();
			return;
		}

		if (compareDetails && !compareDetails.open) {
			if (hint) {
				hint.textContent = 'Abra esta sección para cargar la comparación de semanas.';
				hint.hidden = false;
			}
			if (chartsWrap) {
				chartsWrap.hidden = true;
			}
			return;
		}

		if (!ChartLib) {
			if (chartsWrap) {
				chartsWrap.hidden = true;
			}
			if (hint) {
				hint.textContent = 'No se pudo cargar el componente de gráficos. Recargue la página.';
				hint.hidden = false;
			}
			return;
		}

		if (hint) {
			if (compareData.period_mode && weeks.length && !compareData.has_saved_weeks) {
				hint.textContent = 'No hay programación guardada en el período seleccionado.';
				hint.hidden = false;
			} else {
				hint.hidden = true;
			}
		}
		if (chartsWrap) {
			chartsWrap.hidden = false;
		}

		destroyCharts();

		var labels = weeks.map(function (week) {
			return week.week_label || week.semana_inicio;
		});
		var colorForWeek = weekColorResolver(compareData, weeks.length);

		var hoursCanvas = getCanvas(root, 'hours');
		if (hoursCanvas) {
			chartInstances.hours = new ChartLib(hoursCanvas, {
				type: 'bar',
				data: {
					labels: labels,
					datasets: [
						{
							label: 'Disponibles (h)',
							data: weeks.map(function (w) { return Math.round(((w.available_minutes || 0) / 60) * 10) / 10; }),
							backgroundColor: weeks.map(function (_, index) { return weekChartColor(index, 0.35); }),
							borderRadius: 4
						},
						{
							label: 'Ocupadas (h)',
							data: weeks.map(function (w) { return Math.round(((w.occupied_minutes || 0) / 60) * 10) / 10; }),
							backgroundColor: weeks.map(function (_, index) { return colorForWeek(index); }),
							borderRadius: 4
						}
					]
				},
				options: chartBarOptions()
			});
		}

		var perfCanvas = getCanvas(root, 'performance');
		if (perfCanvas) {
			chartInstances.performance = new ChartLib(perfCanvas, {
				type: 'bar',
				data: {
					labels: ['Ocupación %', 'Eficiencia %'],
					datasets: weeks.map(function (week, index) {
						return {
							label: week.week_label || ('Semana ' + (index + 1)),
							data: [
								Number(week.utilization_pct) || 0,
								Number(week.efficiency_pct) || 0
							],
							backgroundColor: colorForWeek(index),
							borderRadius: 4
						};
					})
				},
				options: chartLinePercentOptions()
			});
		}

		var statusCanvas = getCanvas(root, 'status');
		if (statusCanvas) {
			var statusKeys = ['pending', 'in_progress', 'done', 'delayed'];
			chartInstances.status = new ChartLib(statusCanvas, {
				type: 'bar',
				data: {
					labels: statusKeys.map(function (key) { return statuses[key] || key; }),
					datasets: weeks.map(function (week, index) {
						var byStatus = week.by_status || {};
						return {
							label: week.week_label || ('Semana ' + (index + 1)),
							data: statusKeys.map(function (key) {
								return (byStatus[key] && byStatus[key].minutes) || 0;
							}),
							backgroundColor: colorForWeek(index),
							borderRadius: 4
						};
					})
				},
				options: chartBarHoursOptions()
			});
		}

		var delayCanvas = getCanvas(root, 'delay');
		if (delayCanvas) {
			chartInstances.delay = new ChartLib(delayCanvas, {
				type: 'bar',
				data: {
					labels: labels,
					datasets: [{
						label: 'Retraso (h)',
						data: weeks.map(function (w) { return Math.round(((w.delay_minutes || 0) / 60) * 10) / 10; }),
						backgroundColor: weeks.map(function (_, index) { return colorForWeek(index); }),
						borderRadius: 4
					}]
				},
				options: chartBarOptions()
			});
		}

		global.requestAnimationFrame(function () {
			Object.keys(chartInstances).forEach(function (key) {
				if (chartInstances[key] && typeof chartInstances[key].resize === 'function') {
					chartInstances[key].resize();
				}
			});
		});
	}

	function renderMonthCharts(root, monthData, statuses, ChartLib) {
		renderWeekComparisonCharts(root, monthData, statuses, ChartLib);
	}

	function chartBarHoursOptions() {
		return {
			responsive: true,
			maintainAspectRatio: false,
			scales: {
				y: {
					beginAtZero: true,
					ticks: {
						callback: function (value) {
							var minutes = Number(value) || 0;
							if (minutes < 60) {
								return minutes + ' min';
							}
							return Math.round((minutes / 60) * 10) / 10 + ' h';
						}
					}
				}
			},
			plugins: {
				legend: { position: 'bottom' },
				tooltip: {
					callbacks: {
						label: function (context) {
							var minutes = Number(context.raw) || 0;
							return (context.dataset.label || '') + ': ' + formatHours(minutes);
						}
					}
				}
			}
		};
	}

	function chartBarOptions() {
		return {
			responsive: true,
			maintainAspectRatio: false,
			scales: {
				y: {
					beginAtZero: true,
					ticks: { precision: 0 }
				}
			},
			plugins: {
				legend: { position: 'bottom' }
			}
		};
	}

	function chartLinePercentOptions() {
		return {
			responsive: true,
			maintainAspectRatio: false,
			scales: {
				y: {
					beginAtZero: true,
					max: 100,
					ticks: {
						callback: function (value) {
							return value + '%';
						}
					}
				}
			},
			plugins: {
				legend: { position: 'bottom' }
			}
		};
	}

	global.LogisticaPlaneacionMetrics = {
		computeWeekMetrics: computeWeekMetrics,
		renderWeekPanel: renderWeekPanel,
		renderPedidosWeekPanel: renderPedidosWeekPanel,
		renderWeekComparisonCharts: renderWeekComparisonCharts,
		renderPedidosPeriodCharts: renderPedidosPeriodCharts,
		renderMonthCharts: renderMonthCharts,
		destroyCharts: destroyCharts,
		destroyPedidosCharts: destroyPedidosCharts,
		formatHours: formatHours,
		formatPercent: formatPercent
	};
}(window));
