<script setup lang="ts">
import type { Option } from '@bagelink/vue'
import { Btn, SelectInput, useI18n } from '@bagelink/vue'
import { computed, ref, watch, nextTick } from 'vue'
import { getOptionValue } from '../utils/options'

interface Range {
	start: number
	end: number
}

interface PaginationProps {
	totalItems: number
	totalPages?: number
	variant?: 'default' | 'simple'
	rtl?: boolean
	maxVisiblePages?: number
	/** When set, renders a "per page" selector with these choices. */
	perPageOptions?: number[]
}

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

const { $t } = useI18n()

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

// Update how many items show per page, then jump back to the first page.
function onPerPageChange(opt: Option | Option[] | undefined) {
	const v = Number(getOptionValue(Array.isArray(opt) ? opt[0] : opt))
	if (!Number.isNaN(v) && v > 0) {
		perPage.value = v
		page.value = 1
	}
}

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

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

watch(
	[() => page.value, () => perPage.value, () => props.totalItems],
	() => {
		if (range.value) {
			// Calculate zero-based indices
			const start = (page.value - 1) * perPage.value
			const end = Math.min(start + perPage.value - 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.value <= maxVisiblePages * 2) {
		return Array.from({ length: computedTotalPages.value }, (_, 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.value) { mustInclude.add(page.value + 1) }

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

	// 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.value) { return }

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

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

	// Get position and dimensions
	indicatorWidth.value = buttonRect.width

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

function handleClick(p: number) {
	if (p < 1 || p > computedTotalPages.value) { 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.value.length; i++) {
		const pageNum = visiblePages.value[i]

		// Insert ellipsis before this page if needed
		if (i > 0) {
			const prevPage = visiblePages.value[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 || perPageOptions" class="flex gap-1 align-items-center justify-content-between">
		<!-- Per-page selector -->
		<label v-if="perPageOptions" class="flex gap-05 align-items-center txt14 nowrap">
			<span class="color-gray">{{ $t('pagination.perPage') }}</span>
			<SelectInput
				thin border :options="perPageOptions" :model-value="perPage"
				@update:model-value="onPerPageChange"
			/>
		</label>

		<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>
	</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>
