<script lang="ts" setup>
import type { NavLink } from '@bagelink/vue'
import { Btn, Icon, Dropdown } from '@bagelink/vue'
import { computed, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
import { resolveI18n } from '../../i18n'

interface LinkWithAction extends NavLink {
	activeRoutes?: string[]
	children?: LinkWithAction[]
	action?: () => void
}

const props = withDefaults(defineProps<{
	link: LinkWithAction
	/** sidebar is visually expanded (stays true during the collapse transition) */
	open: boolean
	/** real open state — flips immediately when the user toggles the sidebar */
	realOpen?: boolean
	isMobile: boolean
	bgColor: string
	textColor: string
	activeColor: string
}>(), {})

const route = useRoute()

const hasChildren = computed(() => !!props.link.children?.length)

// active detection (mirrors AppSidebar logic, recursive for parents)
function linkActive(link: LinkWithAction): boolean {
	const linkPath = link.to
	if (link.activeRoutes?.length) {
		return link.activeRoutes.some(p =>
			p === '/' ? route.path === p : route.path === p || route.path.startsWith(`${p}/`))
	}
	if (!linkPath) return false
	if (linkPath === '/') return route.path === linkPath
	return route.path === linkPath || route.path.startsWith(`${linkPath}/`)
}

const childActive = computed(() => props.link.children?.some(linkActive) ?? false)
const selfActive = computed(() => linkActive(props.link))
const isActive = computed(() => selfActive.value || (hasChildren.value && childActive.value))

// expanded/collapsed group state — auto-open when a child is active
const expanded = ref(childActive.value)
watch(childActive, v => { if (v) expanded.value = true })

// Collapse the open child group smoothly *before* the layout switches to the
// icon-only flyout, so parents don't jump up when the sidebar narrows. We watch
// `realOpen` (which flips immediately on toggle) rather than `open` (which stays
// true throughout the width transition), so the grid-rows collapse animation runs
// in sync with the sidebar narrowing instead of snapping at the end.
watch(() => props.realOpen, (isOpenNow) => {
	if (isOpenNow) expanded.value = childActive.value
	else expanded.value = false
})

function onParentClick() {
	if (hasChildren.value) expanded.value = !expanded.value
	else props.link.action?.()
}
</script>

<template>
	<!-- LEAF link -->
	<Btn
		v-if="!hasChildren"
		:title="!open && !isMobile ? resolveI18n(link.label) : ''"
		fullWidth alignTxt="start" class="flex-shrink-0 px-075"
		:class="{ 'nav-btn-active': selfActive }"
		:style="{
			backgroundColor: selfActive ? activeColor : bgColor,
			color: selfActive ? 'white' : textColor,
		}"
		:to="link.to || '/'" @click="link.action"
	>
		<Icon :name="link.icon" size="1.2" />
		<span class="nav-text">{{ resolveI18n(link.label) }}</span>
	</Btn>

	<!-- PARENT with children, EXPANDED sidebar -->
	<div v-else-if="open || isMobile" class="sidebar-group w100p">
		<Btn
			fullWidth alignTxt="start" flat class="flex-shrink-0 px-075 sidebar-group-toggle txt-start sidebar-parent"
			:class="{ 'sidebar-parent-active bold': isActive }"
			:style="{
				color: isActive ? activeColor : textColor,
			}"
			@click="onParentClick"
		>
			<Icon :name="link.icon" size="1.2" />
			<span class="nav-text flex-grow">{{ resolveI18n(link.label) }}</span>
			<Icon name="expand_more" size="1.1" class="nav-text sidebar-chevron line-height-1" :class="{ 'sidebar-chevron-open': expanded }" />
		</Btn>
		<div class="sidebar-children" :class="{ 'sidebar-children-open': expanded }">
			<div class="sidebar-children-inner ps-1">
				<Btn
					v-for="child in link.children" :key="child.to || child.label"
					fullWidth alignTxt="start"  class="flex-shrink-0 ps-075 pe-075 sidebar-child"
					:class="{ 'bold sidebar-child-active': linkActive(child) }"
					:style="{
						color: linkActive(child) ? activeColor : textColor,
						'--sidebar-active-color': activeColor,
					}"
					flat
					:to="child.to || '/'" @click="child.action"
				>
					<Icon v-if="child.icon" :name="child.icon" size="1.05" class="opacity-7" />
					<span class="nav-text">{{ resolveI18n(child.label) }}</span>
				</Btn>
			</div>
		</div>
	</div>

	<!-- PARENT with children, COLLAPSED sidebar → hover popover flyout -->
	<Dropdown
		v-else
		placement="right-start"
		:triggers="['hover']"
		:delay="{ show: 0, hide: 200 }"
		card
		class="w100p sidebar-flyout-trigger"
	>
		<template #trigger>
			<Btn
				fullWidth alignTxt="start" class="flex-shrink-0 px-075"
				:class="{ 'nav-btn-active': isActive }"
				:style="{
					backgroundColor: isActive ? activeColor : bgColor,
					color: isActive ? 'white' : textColor,
				}"
			>
				<Icon :name="link.icon" size="1.2" />
				<span class="nav-text">{{ resolveI18n(link.label) }}</span>
			</Btn>
		</template>
		<!-- flyout content -->
		<div class="sidebar-flyout p-05 min-w-180px display-flex gap-025 column">
			<p class="sidebar-flyout-label m-0 semi opacity-5 uppercase">{{ resolveI18n(link.label) }}</p>
			<Btn
				v-for="child in link.children" :key="child.to || child.label"
				fullWidth alignTxt="start" thin flat class="flex-shrink-0 px-075 radius-1 sidebar-child"
				:class="{ 'bold sidebar-child-active': linkActive(child) }"
				:style="{
					color: linkActive(child) ? activeColor : 'var(--bgl-text-color)',
					'--sidebar-active-color': activeColor,
				}"
				:to="child.to || '/'" @click="child.action"
			>
				<Icon v-if="child.icon" :name="child.icon" size="1.05" class="opacity-7" />
				<span>{{ resolveI18n(child.label) }}</span>
			</Btn>
		</div>
	</Dropdown>
</template>

<style scoped>
.sidebar-chevron {
	margin-inline-start: auto;
	transition: transform 0.2s ease;
	opacity: 0.6;
}
.sidebar-chevron-open {
	transform: rotate(180deg)!important;
}
.sidebar-children {
	display: grid;
	grid-template-rows: 0fr;
	transition: grid-template-rows 0.3s cubic-bezier(0.4, 0, 0.2, 1);
	overflow: hidden;
}
.sidebar-children-open {
	grid-template-rows: 1fr;
}
.sidebar-children-inner {
	min-height: 0;
	display: flex;
	flex-direction: column;
	gap: 0.125rem;
}
.sidebar-children-open .sidebar-children-inner {
	padding-block: 0.25rem;
}
/* Parent toggle — flat <Btn> with no color prop picks up a default `pair-black`
   background; neutralize it so the active parent shows only colored text/icon. */
.sidebar-parent.bgl_btn {
	background-color: transparent !important;
	transition: background-color 0.15s ease, color 0.15s ease;
}
.sidebar-parent.bgl_btn:hover {
	background-color: color-mix(in srgb, currentColor 8%, transparent) !important;
	filter: none;
}

.sidebar-flyout-label {
	padding: 0.25rem 0.5rem 0.375rem;
	font-size: 0.6875rem;
}
</style>

<!-- Global (un-scoped) so the same child styling also applies inside the flyout,
     which is teleported to <body> and therefore outside this component's scope. -->
<style>
.sidebar-child {
	font-size: 0.85rem;
	position: relative;
	transition: background-color 0.15s ease, color 0.15s ease, font-weight 0.15s ease;
}
/* Neutralize the default `pair-black` background a flat <Btn> picks up when no
   color prop is set, so we can control the child background ourselves. */
.sidebar-child.bgl_btn {
	background-color: transparent !important;
}
/* Active child — filled with a subtle tint of the active color. */
.sidebar-child.bgl_btn.sidebar-child-active,
.sidebar-child.bgl_btn.sidebar-child-active:hover {
	background-color: color-mix(in srgb, var(--sidebar-active-color) 14%, transparent) !important;
}

/* Hover indication for children (mirrors the parent feel) */
.sidebar-child.bgl_btn:hover {
	background-color: color-mix(in srgb, currentColor 12%, transparent) !important;
	filter: none;
}
</style>
