<script setup lang="ts">
import { Btn } from '@bagelink/vue'
import { watch, nextTick } from 'vue'

interface Range {
	start: number
	end: number
}

interface PaginationProps {
	totalItems: number
	perPage?: number
	totalPages?: number
	variant?: 'default' | 'simple'
	rtl?: boolean
	maxVisiblePages?: number
}

const props = withDefaults(defineProps<PaginationProps>(), {
	totalItems: 0,
	perPage: 25,
	totalPages: undefined,
	variant: 'default',
	rtl: false,
	maxVisiblePages: 3
})

const page = defineModel<number>('page', { default: 1 })
const range = defineModel<Range>('range')

const paginationContainer = $ref<HTMLElement>()
let indicatorPosition = $ref(0)
let indicatorWidth = $ref(0)

// Calculate totalPages from totalItems and perPage if not provided directly
const computedTotalPages = $computed(() => {
	if (props.totalPages !== undefined) return props.totalPages
	const { perPage } = props
	return Math.max(1, Math.ceil(props.totalItems / perPage))
})

watch(
	[() => page.value, () => props.perPage, () => props.totalItems],
	() => {
		if (range.value) {
			const { perPage } = props
			// Calculate zero-based indices
			const start = (page.value - 1) * perPage
			const end = Math.min(start + perPage - 1, props.totalItems - 1)
			range.value = { start, end }
		}
		// Update indicator position when page changes
		nextTick(() => { updateIndicatorPosition() })
	},
	{ immediate: true }
)

// Also watch for RTL changes
watch(() => props.rtl, updateIndicatorPosition)

// Calculate which page numbers to show
const visiblePages = $computed(() => {
	const { maxVisiblePages } = props

	// If we have few enough pages, show all of them
	if (computedTotalPages <= maxVisiblePages * 2) {
		return Array.from({ length: computedTotalPages }, (_, i) => i + 1)
	}

	// Always include current page and adjacent pages for navigation
	const mustInclude = new Set<number>()

	// Current page is always included
	mustInclude.add(page.value)

	// Ensure adjacent pages are included for navigation
	if (page.value > 1) mustInclude.add(page.value - 1)
	if (page.value < computedTotalPages) mustInclude.add(page.value + 1)

	// Always include first and last pages
	mustInclude.add(1)
	mustInclude.add(computedTotalPages)

	// Start with explicitly required pages
	const pageArray = Array.from(mustInclude).sort((a, b) => a - b)

	// Now fill remaining slots if there's room within maxVisiblePages
	if (pageArray.length < maxVisiblePages + 2) {
		// Try to add pages between existing ones
		for (let i = 0; i < pageArray.length - 1; i++) {
			const current = pageArray[i]
			const next = pageArray[i + 1]

			if (next - current > 1) {
				// There's a gap - fill in additional pages
				const pagesToAdd = Math.min(next - current - 1, maxVisiblePages + 2 - pageArray.length)

				const newPages = Array.from(
					{ length: pagesToAdd },
					(_, idx) => current + idx + 1
				)

				pageArray.splice(i + 1, 0, ...newPages)
				i += newPages.length // Skip past inserted items
			}
		}
	}

	return pageArray
})

function updateIndicatorPosition() {
	if (!paginationContainer) return

	const selectedButton = paginationContainer.querySelector('.selected')
	if (!selectedButton) return

	const containerRect = paginationContainer.getBoundingClientRect()
	const buttonRect = selectedButton.getBoundingClientRect()

	// Get position and dimensions
	indicatorWidth = buttonRect.width

	if (props.rtl) {
		// RTL positioning - align to right edge
		const rightOffset = containerRect.right - buttonRect.right
		indicatorPosition = rightOffset
	} else {
		// LTR positioning - align to left edge
		const leftOffset = buttonRect.left - containerRect.left
		indicatorPosition = leftOffset
	}
}

function handleClick(p: number) {
	if (p < 1 || p > computedTotalPages) return
	page.value = p
}

function next() {
	handleClick(page.value + 1)
}

function prev() {
	handleClick(page.value - 1)
}

// Convert zero-based index to one-based for display
function displayIndex(index: number | undefined): string {
	return index === undefined ? '-' : (index + 1).toString()
}

interface PageItem {
	type: 'page' | 'ellipsis'
	key: string | number
	number?: number
}

// Enhanced rendering - creates UI with ellipses in the right positions
const renderPageButtons = $computed(() => {
	const items: PageItem[] = []

	for (let i = 0; i < visiblePages.length; i++) {
		const pageNum = visiblePages[i]

		// Insert ellipsis before this page if needed
		if (i > 0) {
			const prevPage = visiblePages[i - 1]
			if (pageNum - prevPage > 1) {
				items.push({
					type: 'ellipsis',
					key: `ellipsis-${i}`
				})
			}
		}

		// Add the page button
		items.push({
			type: 'page',
			number: pageNum,
			key: pageNum
		})
	}

	return items
})
</script>

<template>
	<div v-if="computedTotalPages > 1" ref="paginationContainer" class="relative flex gap-1 justify-content">
		<!-- Default pagination with page numbers -->
		<template v-if="variant !== 'simple'">
			<div
				class="indicator radius-1"
				:style="{
					[rtl ? 'right' : 'left']: `${indicatorPosition}px`,
					width: `${indicatorWidth}px`,
				}"
			/>
			<!-- Render the page buttons and ellipses in order -->
			<template v-for="item in renderPageButtons" :key="item.key">
				<!-- Page button -->
				<Btn
					v-if="item.type === 'page'" flat thin
					:class="{ selected: item.number === page }"
					:value="item.number ? item.number.toString() : ''"
					@click="item.number ? handleClick(item.number) : null"
				/>

				<!-- Ellipsis -->
				<div v-else-if="item.type === 'ellipsis'" class="pagination-ellipsis">
					...
				</div>
			</template>
		</template>

		<!-- Simple pagination with prev/next buttons -->
		<template v-else>
			<Btn flat thin :disabled="page <= 1" icon="chevron_left" @click="prev" />
			<span class="pagination-info">
				{{ displayIndex(range?.start) }}-{{ displayIndex(range?.end) }} / {{ props.totalItems }}
			</span>
			<Btn flat thin :disabled="page >= computedTotalPages" icon="chevron_right" @click="next" />
		</template>
	</div>
</template>

<style scoped>
.indicator {
	position: absolute;
	height: 30px;
	background-color: var(--bgl-primary);
	transition: all 0.3s ease;
	z-index: -1;
}

.selected {
	color: white !important;
}

.pagination-info {
	min-width: 60px;
	text-align: center;
	font-size: 14px;
}

.pagination-ellipsis {
	display: flex;
	align-items: center;
	padding: 0 4px;
}
</style>
