<script setup lang="ts">
import type { Tab, IconType } from '@bagelink/vue'
import { Icon } from '@bagelink/vue'
import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { useTabs } from './tabsManager'

const props = defineProps<{
	title?: string
	tabs: Tab[]
	modelValue?: string
	sideTabs?: boolean
	group: string
	flat?: boolean
	vertical?: boolean
	icon?: IconType
	iconEnd?: IconType
	iconSize?: number | string
	iconMobileSize?: number | string
	thin?: boolean
	size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
	fullWidth?: boolean
	fullWidthMobile?: boolean
	alignTxt?: 'center' | 'start' | 'end'
	alignTxtMobile?: 'center' | 'start' | 'end'
	outline?: boolean
	/** Adds a border around the tabs wrapper (keeps the background). */
	frame?: boolean
}>()

const emit = defineEmits(['update:modelValue'])
const { currentTab } = useTabs(props.group)
currentTab.value
	= props.modelValue || typeof props.tabs[0] === 'string'
		? props.tabs[0]
		: props.tabs[0].value

const tabsWrap = ref<HTMLElement | undefined>(undefined)
const tabEls = ref<HTMLElement[]>([])

let resizeObserver: ResizeObserver | undefined

/** Position relative to tabs wrap content box (works after breakpoint / font / scroll changes). */
function measureActiveTabIndicator(wrap: HTMLElement, activeTab: HTMLElement) {
	const wrapRect = wrap.getBoundingClientRect()
	const tabRect = activeTab.getBoundingClientRect()
	const left = tabRect.left - wrapRect.left + wrap.scrollLeft
	const width = tabRect.width
	if (width > 0) {
		wrap.style.setProperty('--indicator-left', `${left}px`)
		wrap.style.setProperty('--indicator-width', `${width}px`)
		wrap.style.setProperty('--indicator-opacity', '1')
	}
}

function updateIndicator() {
	nextTick(() => {
		const wrap = tabsWrap.value
		if (!wrap) { return }

		const apply = () => {
			tabEls.value = Array.from(wrap.querySelectorAll<HTMLElement>('.bgl_tab'))
			const activeTab = tabEls.value.find(tab => tab.classList.contains('active'))
			if (!activeTab) {
				wrap.style.setProperty('--indicator-opacity', '0')
				return
			}
			measureActiveTabIndicator(wrap, activeTab)
		}

		// Double rAF: layout + media-query / font metrics often settle after one frame (e.g. mobile ↔ desktop).
		requestAnimationFrame(() => {
			requestAnimationFrame(apply)
		})
	})
}

function selectTab(tab: Tab) {
	currentTab.value = typeof tab === 'string' ? tab : tab.value
	emit('update:modelValue', currentTab.value)
	nextTick(() => { updateIndicator() })
}

function isActive(tab: Tab) {
	if (typeof tab === 'string') { return currentTab.value === tab }
	return currentTab.value === tab.value
}

function tabLabel(tab: Tab) {
	if (typeof tab === 'string') { return tab }
	return tab.label
}

watch(
	() => props.modelValue,
	(value) => {
		if (value && !isActive(value)) { currentTab.value = value }
		nextTick(() => { updateIndicator() })
	},
	{ immediate: true }
)

onMounted(() => {
	tabEls.value = Array.from(tabsWrap.value?.querySelectorAll('.bgl_tab') || [])

	requestAnimationFrame(() => {
		updateIndicator()
	})

	window.addEventListener('resize', updateIndicator)
	tabsWrap.value?.addEventListener('scroll', updateIndicator, { passive: true })

	if (typeof ResizeObserver !== 'undefined' && tabsWrap.value) {
		resizeObserver = new ResizeObserver(() => {
			updateIndicator()
		})
		resizeObserver.observe(tabsWrap.value)
	}

	if (typeof window !== 'undefined' && window.visualViewport) {
		// Mobile browser chrome / zoom — window "resize" alone can miss this.
		window.visualViewport.addEventListener('resize', updateIndicator)
	}
})

watch(
	() => props.tabs,
	() => {
		nextTick(() => { updateIndicator() })
	},
	{ deep: true }
)

onBeforeUnmount(() => {
	window.removeEventListener('resize', updateIndicator)
	tabsWrap.value?.removeEventListener('scroll', updateIndicator)
	resizeObserver?.disconnect()
	resizeObserver = undefined
	if (typeof window !== 'undefined' && window.visualViewport) {
		window.visualViewport.removeEventListener('resize', updateIndicator)
	}
})
</script>

<template>
	<div ref="tabsWrap" class="grid auto-flow-columns relative fit-content bgl_tabs_wrap overflow-hidden" :class="{ 'bgl_flat-tabs': flat, 'bgl_vertical-tabs': vertical, 'bgl_tabs-outline': outline, 'bgl_tabs-frame': frame }">
	<slot name="tabs" v-bind="{ selectTab, isActive, tabLabel, tabs: tabEls }">
		<button v-for="(tab, i) in props.tabs" :key="i" type="button" :class="[
			{ active: isActive(tab) },
			{	
				'bgl_tab-thin': thin,
				'bgl_tab-xs': size === 'xs',
				'bgl_tab-s': size === 'sm',
				'bgl_tab-l': size === 'lg',
				'bgl_tab-xl': size === 'xl',
				'w-100p justify-center': fullWidth,
				'w-auto m_w-100p': fullWidthMobile,
				'bgl_tab-align-center': alignTxt === 'center',
				'bgl_tab-align-start': alignTxt === 'start',
				'bgl_tab-align-end': alignTxt === 'end',
				'bgl_tab-align-center-mobile': alignTxtMobile === 'center',
				'bgl_tab-align-start-mobile': alignTxtMobile === 'start',
				'bgl_tab-align-end-mobile': alignTxtMobile === 'end',
						}
					]" class="bgl_tab relative z-1" @click="selectTab(tab)">
			<Icon v-if="icon" :icon="icon" :size="iconSize" :mobile-size="iconMobileSize" />
			<Icon v-else-if="typeof tab !== 'string' && tab.icon" :icon="tab.icon" :size="iconSize" :mobile-size="iconMobileSize" />
			{{ tabLabel(tab) }}
			<Icon v-if="iconEnd" :icon="iconEnd" :size="iconSize" :mobile-size="iconMobileSize" />
		</button>
		</slot>
		</div>
</template>

<style>

:root {
--bgl_tabs-background: var(--bgl-input-bg);
--bgl_tabs-border-radius: var(--bgl-tabs-border-radius, var(--bgl-input-border-radius));
--bgl_tabs-inline-padding: calc(var(--bgl-btn-padding) / 8);
--bgl_tabs-block-padding: calc(var(--bgl-btn-padding) / 8);
--bgl_tabs-shadow: inset 0 0 10px #00000012;
--bgl_tabs-gap: 0.25rem;
--bgl_tabs-font-size: var(--bgl-input-font-size);
--bgl_tab-inline-padding: calc(var(--bgl-btn-padding) / 2);
--bgl_tab-block-padding: calc(var(--bgl-btn-padding) / 8);
--bgl_tab-gap: 0.5rem;
--bgl-tab-hover-bg: rgba(255, 255, 255, .4);
--bgl_tabs-indicator-color: var(--bgl-popup-bg);
--bgl-tabs-flat-indicator-color: var(--bgl-primary);
}

</style>

<style scoped>

.bgl_tabs_wrap {
background: var(--bgl_tabs-background);
border-radius: calc(var(--bgl_tabs-border-radius) * 1.4);
	padding-inline: var(--bgl_tabs-inline-padding);
	padding-block: var(--bgl_tabs-block-padding);
	box-shadow: var(--bgl_tabs-shadow);
	gap: var(--bgl_tabs-gap);
}

/* outline: border + drop the filled background & shadow (transparent shell). */
.bgl_tabs-outline.bgl_tabs_wrap {
	border: 1px solid var(--bgl-border-color);
	background: transparent;
	box-shadow: none;
}

/* frame: border on top of the normal filled background (keeps bg & shadow). */
.bgl_tabs-frame.bgl_tabs_wrap {
	border: 1px solid var(--bgl-border-color);
}

.bgl_tab {
border: none;
background: transparent;
cursor: pointer;
font-size: inherit;
font-family: inherit;
height: calc(var(--bgl-btn-height) - var(--bgl_tabs-block-padding) * 2);
padding-inline: var(--bgl_tab-inline-padding);
padding-block: 0;
	border-radius: var(--bgl_tab-border-radius);
transition: var(--bgl-transition);
color: inherit;
display: flex;
align-items: center;
	gap: var(--bgl_tab-gap);
}

.bgl_tab:hover {
background: var(--bgl-tab-hover-bg);
border-radius: var(--bgl_tab-border-radius, 7px);
}

.bgl_tabs_wrap::before {
content: '';
position: absolute;
top: var(--bgl_tabs-block-padding);
bottom: var(--bgl_tabs-block-padding);
left: var(--indicator-left, 0);
width: var(--indicator-width, 0);
background: var(--bgl_tabs-indicator-color);
border-radius: var(--bgl_tabs-border-radius);
transition: var(--bgl-transition);
z-index: 0;
/* Hide indicator initially until position is calculated */
opacity: var(--indicator-opacity, 0);
}

.bgl_flat-tabs.bgl_tabs_wrap {
background: transparent;
box-shadow: none;
}
.bgl_flat-tabs.bgl_tabs_wrap::before {
background: transparent;
border-bottom: 1px solid var(--bgl-tabs-flat-indicator-color);
border-radius: 0;
top: calc(var(--bgl-btn-padding) * 1.25);
bottom: unset;

}
.bgl_flat-tabs .active.bgl_tab {
color: var(--bgl-primary)
}

.bgl_flat-tabs .bgl_tab:hover {
background: var(--bgl-tab-hover-bg);
}
.bgl_tab-thin {
padding-inline: calc(var(--bgl_tab-inline-padding) / 2);
height: calc(var(--bgl-btn-height) * 0.7 - var(--bgl_tabs-block-padding) * 2);
}

.bgl_tab-xs {
padding-inline: calc(var(--bgl_tab-inline-padding) / 3);
font-size: calc(var(--bgl-input-font-size) * 0.6);
height: calc(var(--bgl-btn-height) * 0.5 - var(--bgl_tabs-block-padding) * 2);
}

.bgl_tab-s {
padding-inline: calc(var(--bgl_tab-inline-padding) / 1.5);
height: calc(var(--bgl-btn-height) * 0.7 - var(--bgl_tabs-block-padding) * 2);
}

.bgl_tab-l {
padding-inline: calc(var(--bgl_tab-inline-padding) * 1.3);
font-size: calc(var(--bgl-input-font-size) * 1.1);
height: calc(var(--bgl-btn-height) * 1.2 - var(--bgl_tabs-block-padding) * 2);
}

.bgl_tab-xl {
padding-inline: calc(var(--bgl_tab-inline-padding) * 1.6);
font-size: calc(var(--bgl-input-font-size) * 1.3);
height: calc(var(--bgl-btn-height) * 1.5 - var(--bgl_tabs-block-padding) * 2);
}

.bgl_tab-align-start {
justify-content: flex-start !important;
}

.bgl_tab-align-end {
justify-content: flex-end !important;
}

.bgl_tab-align-center {
justify-content: center !important;
}

.bgl_tab-align-start-mobile,
.bgl_tab-align-end-mobile {
justify-content: center !important;
}

.bgl_vertical-tabs {
grid-auto-flow: row;
align-items: start;
justify-items: start;
gap: 1rem
}
.bgl_vertical-tabs .bgl_tab {
padding-inline: 0;
border-radius: 0;
border-bottom: 1px solid transparent;
}
.bgl_vertical-tabs .bgl_tab:hover {
background: transparent;
border-bottom: 1px solid var(--bgl-tabs-flat-indicator-color);

}
.bgl_vertical-tabs .bgl_tab.active {
border-bottom: 1px solid var(--bgl-tabs-flat-indicator-color);
}
.bgl_vertical-tabs.bgl_tabs_wrap::before {
border: none;
}

@media screen and (max-width: 910px) {
.bgl_tab-align-start-mobile {
		justify-content: flex-start !important;
	}

	.bgl_tab-align-end-mobile {
		justify-content: flex-end !important;
	}

	.bgl_tab-align-center-mobile {
		justify-content: center !important;
	}

	.bgl_vertical-tabs {
grid-auto-flow: column;
overflow: auto;
max-width: 100vw;
padding-inline-end: 1rem;
width: 100%;
gap: 1rem;
position: relative;
}

.bgl_vertical-tabs::-webkit-scrollbar {
display: none;
}
.bgl_vertical-tabs .bgl_tab {
white-space: nowrap;
}

.bgl_tab {
gap: 0.25rem;
padding: 0.25rem 0.5rem;
}
}

</style>
