<template>
	<div class="pagination-container">
		<div
			v-if="currentPage === pageTotal && total > env.maxMatches"
			class="more"
		>Can't find what you're looking for? Narrow down the results using a filter.</div>

		<nav class="pagination">
			<ul class="pages nolist">
				<li>
					<Link
						:href="getPath(1)"
						:class="{ disabled: !hasPrevPage }"
						class="page first nolink"
						@click="(event) => go(1, event)"
					><Icon icon="first2" /></Link>
				</li>

				<li>
					<Link
						:href="hasPrevPage ? getPath(currentPage - 1) : null"
						:class="{ disabled: !hasPrevPage }"
						class="page prev nolink"
						@click="(event) => hasPrevPage && go(currentPage - 1, event)"
					><Icon icon="arrow-left" /></Link>
				</li>
			</ul>

			<div class="index">
				<ul class="pages before wrap nolist">
					<li
						v-for="prevPage in prevPages"
						:key="`page-${prevPage}`"
					>
						<Link
							:href="getPath(prevPage)"
							:class="{ active: prevPage === currentPage }"
							class="page nolink"
							@click="(event) => go(prevPage, event)"
						>{{ prevPage }}</Link>
					</li>
				</ul>

				<ul class="pages nolist">
					<li>
						<div class="page active">{{ currentPage }}</div>
					</li>
				</ul>

				<ul class="pages after wrap nolist">
					<li
						v-for="nextPage in nextPages"
						:key="`page-${nextPage}`"
					>
						<Link
							:href="getPath(nextPage)"
							:class="{ active: nextPage === currentPage }"
							class="page nolink"
							@click="(event) => go(nextPage, event)"
						>{{ nextPage }}</Link>
					</li>
				</ul>
			</div>

			<ul class="pages nolist">
				<li>
					<Link
						:href="hasNextPage ? getPath(currentPage + 1) : null"
						:class="{ disabled: !hasNextPage }"
						class="page next nolink"
						@click="(event) => hasNextPage && go(currentPage + 1, event)"
					><Icon icon="arrow-right" /></Link>
				</li>

				<li>
					<Link
						:href="getPath(pageTotal)"
						:class="{ disabled: !hasNextPage }"
						class="page last nolink"
						@click="(event) => go(pageTotal, event)"
					><Icon icon="last2" /></Link>
				</li>
			</ul>
		</nav>
	</div>
</template>

<script setup>
import { computed, inject } from 'vue';
import { parse } from 'path-to-regexp';

const props = defineProps({
	page: {
		type: Number,
		default: null,
	},
	total: {
		type: Number,
		default: null,
	},
	redirect: {
		type: Boolean,
		default: true,
	},
	query: {
		type: String,
		default: null,
	},
	includeQuery: {
		type: Boolean,
		default: true,
	},
	useMaxMatches: {
		type: Boolean,
		default: true,
	},
});

const emit = defineEmits(['navigation']);

const pageContext = inject('pageContext');

const {
	routeParams,
	urlParsed,
	pageProps,
	env,
} = pageContext;

const currentPage = computed(() => props.page || Number(routeParams?.page));

const limit = computed(() => props.limit || Number(pageProps.limit) || 30);
const total = computed(() => props.total || Number(pageProps.total));
const pageTotal = computed(() => Math.ceil((props.useMaxMatches ? Math.min(total.value, env.maxMatches) : total.value) / limit.value));

const hasNextPage = computed(() => currentPage.value + 1 <= pageTotal.value);
const hasPrevPage = computed(() => currentPage.value - 1 >= 1);

const prevPages = computed(() => Array.from({ length: 4 }, (value, index) => {
	const page = currentPage.value - index - 1;

	if (page < 1) {
		return null;
	}

	return page;
}).filter(Boolean));

const nextPages = computed(() => Array.from({ length: 4 }, (value, index) => {
	const page = currentPage.value + index + 1;

	if (page > pageTotal.value) {
		return null;
	}

	return page;
}).filter(Boolean));

function go(page, event) {
	if (!props.redirect) {
		event.preventDefault();
		history.pushState({}, '', event.target.href); // eslint-disable-line no-restricted-globals
	}

	emit('navigation', {
		href: event.target.href,
		page,
	});
}

function getPath(page) {
	const query = typeof window === 'undefined'
		? urlParsed.searchOriginal
		: window.location.search;

	if (!routeParams.path && props.includeQuery && query) {
		return `${pageContext.urlParsed.pathname}${page}${query}`;
	}

	if (!routeParams.path) {
		return `${pageContext.urlParsed.pathname}${page}`;
	}

	const path = parse(routeParams.path)
		.map((segment) => {
			if (segment.name === 'page') {
				return `/${page}`;
			}

			return `${segment.prefix || ''}${routeParams[segment.name] || segment}`;
		})
		.join('');

	if (props.includeQuery && query) {
		return `${path}${query}`;
	}

	return path;
}
</script>

<style scoped>
.pagination-container {
	display: flex;
	flex-direction: column;
	justify-content: center;
}

.pagination {
	height: 5rem;
	display: flex;
	justify-content: center;
	flex-shrink: 0;
	box-sizing: border-box;
	padding: 1rem;
	margin-bottom: 1rem;
	font-size: 0;
	overflow: hidden;
}

.pages {
	display: flex;
	gap: 0 .25rem;
}

.wrap {
	flex-wrap: wrap;
}

.before {
	flex-direction: row-reverse;
	margin-right: .25rem;
}

.after {
	margin-left: .25rem;
}

.index {
	display: flex;
	justify-content: center;
}

.page {
	width: 3rem;
	height: 3rem;
	display: inline-flex;
	justify-content: center;
	align-items: center;
	border-radius: .5rem;
	margin-bottom: 1rem;
	background: var(--background);
	box-shadow: 0 0 3px var(--shadow-weak-30);
	color: var(--shadow);
	font-weight: bold;
	font-size: 1rem;

	.icon {
		width: .9rem;
		height: .9rem;
		fill: var(--shadow);
	}

	&.active {
		background: var(--primary);
		color: var(--text-light);
	}

	&.disabled .icon {
		fill: var(--shadow-weak-20);
	}
}

.prev {
	margin-right: .5rem;
}

.next {
	margin-left: .5rem;
}

.more {
	padding: 2rem;
	text-align: center;
	color: var(--shadow-strong-10);
	font-size: 1.1rem;
}

@media (--small-30) {
	.pagination {
		height: 4.5rem;
	}

	.page {
		width: 2.25rem;
		height: 2.5rem;
	}
}
</style>