(function () {
	'use strict';

	if (typeof window.p5 !== 'function') return;

	var gradients = [
		{ start: [16, 141, 199], end: [239, 142, 56] },
		{ start: [247, 255, 0], end: [219, 54, 164] },
		{ start: [33, 95, 0], end: [228, 228, 217] },
		{ start: [222, 98, 98], end: [255, 184, 140] },
		{ start: [251, 211, 233], end: [187, 55, 125] },
		{ start: [67, 206, 162], end: [24, 90, 157] }
	];

	function pickGradient() {
		return gradients[Math.floor(Math.random() * gradients.length)];
	}

	function prefersReducedMotion() {
		try {
			return window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
		} catch (e) {
			return false;
		}
	}

	var activeContainer = null;
	var isPlaying = false;
	var analyser = null;
	var freqData = null;
	var rotateAngle = 0;
	var startRGB = [0, 0, 0];
	var endRGB = [0, 0, 0];

	function setGradientRandom() {
		var g = pickGradient();
		startRGB = g.start.slice();
		endRGB = g.end.slice();
	}
	setGradientRandom();

	function updateAnalyserFromGlobal() {
		analyser = window.__mtAudioAnalyser || null;
		if (!analyser) {
			freqData = null;
			return;
		}
		try {
			var bins = analyser.frequencyBinCount;
			if (!freqData || freqData.length !== bins) freqData = new Uint8Array(bins);
		} catch (e) {
			analyser = null;
			freqData = null;
		}
	}

	updateAnalyserFromGlobal();

	function getSpectrumValues() {
		if (!analyser || !freqData) return null;
		try { analyser.getByteFrequencyData(freqData); } catch (e) { return null; }
		var bins = freqData.length;
		var spectrumValues = [];
		var end = Math.min(bins - 3, Math.floor(Math.PI * 100) * 3);
		for (var i = 0; i < end; i += 3) {
			spectrumValues.push((freqData[i] + freqData[i + 1] + freqData[i + 2]) / 3);
		}
		return spectrumValues;
	}

	var ro = null;
	function watchResize(container, cb) {
		try {
			if (!('ResizeObserver' in window)) return;
			if (!ro) ro = new ResizeObserver(function () { cb(); });
			ro.observe(container);
		} catch (e) {}
	}

	function unwatchResize(container) {
		try {
			if (ro && container) ro.unobserve(container);
		} catch (e) {}
	}

	var p5Instance = null;
	var p5Canvas = null;

	function ensureP5() {
		if (p5Instance) return;
		p5Instance = new window.p5(function (p) {
			var startColor;
			var endColor;

			function resizeToContainer() {
				if (!activeContainer) return;
				var w = Math.max(1, activeContainer.clientWidth || 180);
				var h = Math.max(1, activeContainer.clientHeight || 270);
				try { p.resizeCanvas(w, h); } catch (e) {}
			}

			p.setup = function () {
				p5Canvas = p.createCanvas(1, 1);
				// Place it offscreen until we have a target.
				p5Canvas.parent(document.body);
				p5Canvas.elt.style.position = 'fixed';
				p5Canvas.elt.style.left = '-9999px';
				p5Canvas.elt.style.top = '-9999px';
				p.colorMode(p.RGB);
				startColor = p.color(0, 0, 0);
				endColor = p.color(0, 0, 0);
				p.frameRate(prefersReducedMotion() ? 1 : 30);
				p.noLoop();
			};

			p.draw = function () {
				// Transparent canvas; the CSS gradient sits behind.
				p.clear();

				var w = p.width;
				var h = p.height;
				p.translate(w / 2, h / 2);

				p.rotate(rotateAngle);
				rotateAngle += isPlaying ? 0.001 : 0.0004;

				var ring = Math.min(w, h) * 0.26;
				p.noFill();

				var spectrumValues = isPlaying ? getSpectrumValues() : null;
				if (!spectrumValues || !spectrumValues.length) {
					p.stroke(110);
					p.ellipse(0, 0, ring, ring);
					p.stroke(60);
					p.ellipse(0, 0, ring * 1.06, ring * 1.06);
					return;
				}

				startColor = p.color(startRGB[0], startRGB[1], startRGB[2]);
				endColor = p.color(endRGB[0], endRGB[1], endRGB[2]);

				var count = 0;
				var angle = 0.0;
				var incrementPosRight = 0.0;
				var incrementPosLeft = 0.0;
				var increment = 0.0128;
				var lerpy;

				p.stroke(255);
				p.ellipse(0, 0, ring, ring);

				for (var i = 0; i < p.TWO_PI; i += 0.04) {
					var x = p.sin(i) * (Math.min(w, h) * 0.14);
					var y = p.cos(i) * (Math.min(w, h) * 0.14);

					if (i < p.PI) {
						lerpy = p.lerpColor(startColor, endColor, incrementPosRight);
						incrementPosRight += increment;
					} else {
						lerpy = p.lerpColor(endColor, startColor, incrementPosLeft);
						incrementPosLeft += increment;
					}

					p.stroke(lerpy);
					p.push();
					p.translate(x, y);
					p.rotate(-angle);

					var v = spectrumValues[count] || 0;
					var barH = p.map(v, 0, 200, 2, Math.min(w, h) * 0.22);
					p.rect(0, 0, 1, barH);
					p.pop();

					count++;
					angle += 0.04;
					if (count >= spectrumValues.length) break;
				}
			};

			// Expose resize helper
			p.__mtResizeToContainer = resizeToContainer;
		});
	}

	function attachTo(container) {
		if (!container) return;
		ensureP5();
		if (!p5Canvas || !p5Canvas.elt) return;

		// Move canvas into the selected .mt-p5viz container.
		try {
			p5Canvas.parent(container);
		} catch (e) {
			try { container.appendChild(p5Canvas.elt); } catch (e2) {}
		}

		// Remove offscreen positioning (CSS will size it)
		try {
			p5Canvas.elt.style.position = '';
			p5Canvas.elt.style.left = '';
			p5Canvas.elt.style.top = '';
		} catch (e) {}

		if (p5Instance && p5Instance.__mtResizeToContainer) {
			p5Instance.__mtResizeToContainer();
		}
	}

	function setTarget(container, playing) {
		if (activeContainer === container && isPlaying === !!playing) {
			return;
		}

		if (activeContainer && activeContainer !== container) {
			unwatchResize(activeContainer);
		}

		activeContainer = container || null;
		isPlaying = !!playing;
		updateAnalyserFromGlobal();

		if (!activeContainer) {
			if (p5Instance) p5Instance.noLoop();
			return;
		}

		attachTo(activeContainer);
		watchResize(activeContainer, function () {
			if (p5Instance && p5Instance.__mtResizeToContainer) p5Instance.__mtResizeToContainer();
		});

		// Start rendering when we have a target.
		if (p5Instance) {
			p5Instance.frameRate(prefersReducedMotion() ? 1 : (isPlaying ? 30 : 6));
			p5Instance.loop();
		}
	}

	window.addEventListener('mt-audio-analyser', function () {
		setGradientRandom();
		updateAnalyserFromGlobal();
	});

	window.addEventListener('mt-audio-viz-target', function (e) {
		var d = e && e.detail ? e.detail : null;
		if (!d || !d.container) return;
		setTarget(d.container, d.playing);
	});
})();
