<script lang="ts">
	import _ from 'lodash';
	import { createEventDispatcher, onMount } from 'svelte';
	const dispatch = createEventDispatcher();

	const START_COUNT = 27;
	const MAX_COUNT = 33;
	const MARGIN_SIZE = 16;

	let horizontalCount = START_COUNT;
	let verticalCount = START_COUNT;
	let blockSize = 64;
	let cornerBlocks = 2;

	let horizontalMargin = MARGIN_SIZE;
	let verticalMargin = MARGIN_SIZE;
	let unloaded = true;

	export let transparent = false;
	export let subdued = false;

	function updateCounts() {
		const gridWidth = window.innerWidth - MARGIN_SIZE;
		const gridHeight = window.innerHeight - MARGIN_SIZE;

		const [longerSide, shorterSide] =
			gridWidth > gridHeight ? [gridWidth, gridHeight] : [gridHeight, gridWidth];

		function discrepancy(count: number) {
			const blockSize = longerSide / count;
			return shorterSide / blockSize - Math.floor(shorterSide / blockSize);
		}

		let finalCount = START_COUNT;
		let count = START_COUNT;
		let bestDiscrepancy = discrepancy(count);
		while (count < MAX_COUNT) {
			count += 2;
			const currentDiscrepancy = discrepancy(count);
			if (currentDiscrepancy < bestDiscrepancy) {
				bestDiscrepancy = currentDiscrepancy;
				finalCount = count;
			}
		}

		const longerCount = finalCount;
		const shorterCount = Math.round(longerCount * (shorterSide / longerSide));

		[horizontalCount, verticalCount] =
			gridWidth > gridHeight ? [longerCount, shorterCount] : [shorterCount, longerCount];
		blockSize = longerSide / finalCount;
		horizontalMargin = (window.innerWidth - blockSize * horizontalCount) / 2;
		verticalMargin = (window.innerHeight - blockSize * verticalCount) / 2;
		cornerBlocks = shorterCount > 8 ? 3 : Math.max(1, Math.floor(shorterCount / 4));
		dispatch('change', {
			horizontalCount,
			verticalCount,
			blockSize,
			horizontalMargin,
			verticalMargin
		});
	}
	const updateCountsOnResize = _.throttle(updateCounts, 200);

	onMount(() => {
		window.addEventListener('resize', updateCountsOnResize);
		updateCounts();
		unloaded = false;
	});
</script>

<div
	class="background"
	class:unloaded
	class:transparent
	class:subdued
	class:even-vertical={verticalCount % 2 === 0}
	style="--horizontal-count: {horizontalCount};
					 --vertical-count: {verticalCount};
					 --block-size: {blockSize}px;
					 --horizontal-margin: {horizontalMargin}px;
					 --vertical-margin: {verticalMargin}px;"
>
	<div class="corners">
		<div class="corner top left"></div>
		<div class="corner top right"></div>
		<div class="corner bottom left"></div>
		<div class="corner bottom right"></div>
	</div>
	<div class="edges">
		{#each ['top', 'bottom'] as edge}
			<div class="edge {edge}">
				{#each [...Array(horizontalCount).keys()] as n}
					<div
						class="block"
						class:corner-block={n < cornerBlocks || n >= horizontalCount - cornerBlocks}
					></div>
				{/each}
			</div>
		{/each}
		{#each ['left', 'right'] as edge}
			<div class="edge {edge}">
				{#each [...Array(verticalCount).keys()] as n}
					<div
						class="block"
						class:corner-block={n < cornerBlocks || n >= verticalCount - cornerBlocks}
					></div>
				{/each}
			</div>
		{/each}
	</div>
	<div class="grid">
		{#each [...Array(verticalCount).keys()] as x}
			<div class="row" data-idx="{x}">
				{#each [...Array(horizontalCount).keys()] as y}
					<div class="block" data-idx="{y}"></div>
				{/each}
			</div>
		{/each}
	</div>
</div>

<style>
	.background {
		position: absolute;
		top: 0;
		left: 0;
		width: 100%;
		height: 100%;

		pointer-events: none;

		--corner-color: white;
	}

	.corner {
		background-color: var(--corner-color);

		position: absolute;
		&.top {
			top: 0;
			height: var(--vertical-margin);
		}
		&.bottom {
			bottom: 0;
			height: var(--vertical-margin);
		}
		&.left {
			left: 0;
			width: var(--horizontal-margin);
		}
		&.right {
			right: 0;
			width: var(--horizontal-margin);
		}
	}

	.edges {
		& .edge {
			position: absolute;
			display: flex;
		}

		& .top {
			top: 0;
		}

		& .bottom {
			bottom: 0;
		}

		& .top,
		& .bottom {
			width: calc(100vw - var(--horizontal-margin) * 2);
			height: calc(var(--margin-size) * 2);
			left: var(--horizontal-margin);

			& .block {
				width: var(--block-size);
				height: var(--vertical-margin);
			}
		}

		& .left {
			left: 0;
		}

		& .right {
			right: 0;
		}

		& .left,
		& .right {
			flex-direction: column;
			height: calc(100vh - var(--vertical-margin) * 2);
			width: calc(var(--margin-size) * 2);
			top: var(--vertical-margin);

			& .block {
				width: var(--horizontal-margin);
				height: var(--block-size);
			}
		}

		& .block {
			display: inline-block;

			background: black;
			&:nth-child(odd) {
				background: white;
			}

			&.corner-block {
				background: white;
			}
		}
	}

	.block,
	.corner {
		transition: background 1s;
	}

	.background.even-vertical .edges .right .block:not(.corner-block) {
		background: white;
		&:nth-child(odd) {
			background: black;
		}
	}

	.background.transparent {
		& .block {
			background: transparent !important;
		}

		& .edge {
			&.top .block {
				border-right: 1px solid gray;
				&:first-child {
					border-left: 1px solid gray;
				}
			}

			&.bottom .block {
				border-right: 1px solid gray;
				&:first-child {
					border-left: 1px solid gray;
				}
			}

			&.left .block {
				border-bottom: 1px solid gray;
				&:first-child {
					border-top: 1px solid gray;
				}
			}

			&.right .block {
				border-bottom: 1px solid gray;
				&:first-child {
					border-top: 1px solid gray;
				}
			}
		}

		& .corner {
			background: transparent !important;
		}
	}

	.background.subdued {
		& .edge,
		& .corner {
			opacity: 0.33;
		}
	}

	.grid {
		display: grid;
		grid-template-columns: repeat(var(--horizontal-count), var(--block-size));
		grid-template-rows: repeat(var(--vertical-count), var(--block-size));
		position: absolute;
		top: var(--vertical-margin);
		left: var(--horizontal-margin);

		& .row {
			display: contents;
		}

		& .block {
			background: black;
			border-right: 1px solid gray;
			border-bottom: 1px solid gray;
		}

		& .row:first-child .block {
			border-top: 1px solid gray;
		}

		& .block:first-child {
			border-left: 1px solid gray;
		}
	}

	.background.unloaded {
		& .grid {
			width: calc(100vw - var(--horizontal-margin) * 2);
			height: calc(100vh - var(--vertical-margin) * 2);
			grid-template-rows: repeat(var(--vertical-count), 1fr);
			grid-template-columns: repeat(var(--horizontal-count), 1fr);
		}

		& .edge {
			justify-content: space-evenly;
		}
	}
</style>
