<template>
<span class="mk-sparkle">
	<span ref="content">
		<slot></slot>
	</span>
	<canvas ref="canvas"></canvas>
</span>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import * as os from '@client/os';

const sprite = new Image();
sprite.src = "/static-assets/client/sparkle-spritesheet.png";


export default defineComponent({
	props: {
		count: {
			type: Number,
			required: true,
		},
		speed: {
			type: Number,
			required: true,
		},
	},
	data() {
		return {
			sprites: [0,6,13,20],
			particles: [],
			anim: null,
			ctx: null,
		};
	},
	methods: {
		createSparkles(w, h, count) {
			var holder = [];

			for (var i = 0; i < count; i++) {

				const color = '#' + ('000000' + Math.floor(Math.random() * 16777215).toString(16)).slice(-6);

				holder[i] = {
					position: {
						x: Math.floor(Math.random() * w),
						y: Math.floor(Math.random() * h)
					},
					style: this.sprites[ Math.floor(Math.random() * 4) ],
					delta: {
						x: Math.floor(Math.random() * 1000) - 500,
						y: Math.floor(Math.random() * 1000) - 500
					},
					color: color,
					opacity: Math.random(),
				};

			}

			return holder;
		},
		draw(time) {
			this.ctx.clearRect(0, 0, this.$refs.canvas.width, this.$refs.canvas.height);
			this.ctx.beginPath();

			const particleSize = Math.floor(this.fontSize / 2);
			this.particles.forEach((particle) => {
				var modulus = Math.floor(Math.random()*7);

				if (Math.floor(time) % modulus === 0) {
					particle.style = this.sprites[ Math.floor(Math.random()*4) ];
				}

				this.ctx.save();
				this.ctx.globalAlpha = particle.opacity;
				this.ctx.drawImage(sprite, particle.style, 0, 7, 7, particle.position.x, particle.position.y, particleSize, particleSize);

				this.ctx.globalCompositeOperation = "source-atop";
				this.ctx.globalAlpha = 0.5;
				this.ctx.fillStyle = particle.color;
				this.ctx.fillRect(particle.position.x, particle.position.y, particleSize, particleSize);

				this.ctx.restore();
			});
			this.ctx.stroke();
		},
		tick() {
			this.anim = window.requestAnimationFrame((time) => {
				if (!this.$refs.canvas) {
					return;
				}
				this.particles.forEach((particle) => {
					if (!particle) {
						return;
					}
					var randX = Math.random() > Math.random() * 2;
					var randY = Math.random() > Math.random() * 3;

					if (randX) {
						particle.position.x += (particle.delta.x * this.speed) / 1500;
					}

					if (!randY) {
						particle.position.y -= (particle.delta.y * this.speed) / 800;
					}

					if( particle.position.x > this.$refs.canvas.width ) {
						particle.position.x = -7;
					} else if (particle.position.x < -7) {
						particle.position.x = this.$refs.canvas.width;
					}

					if (particle.position.y > this.$refs.canvas.height) {
						particle.position.y = -7;
						particle.position.x = Math.floor(Math.random() * this.$refs.canvas.width);
					} else if (particle.position.y < -7) {
						particle.position.y = this.$refs.canvas.height;
						particle.position.x = Math.floor(Math.random() * this.$refs.canvas.width);
					}

					particle.opacity -= 0.005;

					if (particle.opacity <= 0) {
						particle.opacity = 1;
					}
				});

				this.draw(time);

				this.tick();
			});
		},
		resize() {
			if (this.$refs.content) {
				const contentRect = this.$refs.content.getBoundingClientRect();
				this.fontSize = parseFloat(getComputedStyle(this.$refs.content).fontSize);
				const padding = this.fontSize * 0.2;

				this.$refs.canvas.width = parseInt(contentRect.width + padding);
				this.$refs.canvas.height = parseInt(contentRect.height + padding);

				this.particles = this.createSparkles(this.$refs.canvas.width, this.$refs.canvas.height, this.count);
			}
		},
	},
	mounted() {
		this.ctx = this.$refs.canvas.getContext('2d');

		new ResizeObserver(this.resize).observe(this.$refs.content);

		this.resize();
		this.tick();
	},
	updated() {
		this.resize();
	},
	destroyed() {
		window.cancelAnimationFrame(this.anim);
	},
});
</script>

<style lang="scss" scoped>
.mk-sparkle {
	position: relative;
	display: inline-block;

	> span {
		display: inline-block;
	}

	> canvas {
		position: absolute;
		top: -0.1em;
		left: -0.1em;
		pointer-events: none;
	}
}
</style>