<script lang="ts" setup>
import { ref, provide, onMounted, onUnmounted, computed, watch } from 'vue'
import { useEscapeKey } from '../../composables/useEscapeKey'
import { MOBILE_BREAKPOINT } from '../../utils/constants'
import { AppLayoutKey, SIDEBAR_COLLAPSED_WIDTH, SIDEBAR_COLLAPSED_WIDTH_CARD } from './appLayoutContext'

interface Props {
	sidebarWidth?: string
	sidebarCardStyle?: boolean
	defaultOpen?: boolean
	/** v-model:open — controlled sidebar state */
	open?: boolean
	/** Persist sidebar state to localStorage (desktop only). Default true. */
	persist?: boolean
	storageKey?: string
}

const props = withDefaults(defineProps<Props>(), {
	sidebarWidth: '260px',
	sidebarCardStyle: false,
	defaultOpen: true,
	open: undefined,
	persist: true,
	storageKey: 'bgl-sidebar-open',
})

const emit = defineEmits<{ 'update:open': [value: boolean] }>()

function readStored(): boolean | undefined {
	if (!props.persist || typeof localStorage === 'undefined') { return undefined }
	const raw = localStorage.getItem(props.storageKey)
	return raw === null ? undefined : raw === 'true'
}

const isOpen = ref(props.open ?? readStored() ?? props.defaultOpen)
const isMobile = ref(false)

const sidebarCollapsedWidth = props.sidebarCardStyle ? SIDEBAR_COLLAPSED_WIDTH_CARD : SIDEBAR_COLLAPSED_WIDTH

// Sync controlled prop → internal state
watch(() => props.open, (v) => {
	if (v !== undefined) { isOpen.value = v }
})

watch(isOpen, (v) => {
	emit('update:open', v)
	// Persist only explicit desktop state — never the forced mobile collapse
	if (props.persist && !isMobile.value && typeof localStorage !== 'undefined') {
		localStorage.setItem(props.storageKey, String(v))
	}
})

function checkMobile() {
	isMobile.value = window.innerWidth <= MOBILE_BREAKPOINT
	if (isMobile.value) {
		isOpen.value = false
	}
}

function toggleMenu() {
	isOpen.value = !isOpen.value
}

// Esc closes the sidebar overlay on mobile
useEscapeKey(() => { isOpen.value = false }, () => isMobile.value && isOpen.value)

// Close menu on mobile when clicking outside
function closeOnMobile() {
	if (isMobile.value) {
		isOpen.value = false
	}
}

// Computed styles for main content margin
const mainContentStyles = computed(() => {
	if (isMobile.value) {
		return { marginInlineStart: '0' }
	}
	return {
		marginInlineStart: isOpen.value ? props.sidebarWidth : sidebarCollapsedWidth
	}
})

provide(AppLayoutKey, {
	isOpen,
	isMobile,
	toggleMenu,
	closeOnMobile,
	sidebarWidth: props.sidebarWidth,
	sidebarCollapsedWidth,
	sidebarCardStyle: props.sidebarCardStyle,
})

onMounted(() => {
	checkMobile()
	window.addEventListener('resize', checkMobile)
})

onUnmounted(() => {
	window.removeEventListener('resize', checkMobile)
})
</script>

<template>
	<div class="app-layout vh-100 relative">
		<!-- Mobile Overlay -->
		<div
			v-if="isMobile && isOpen"
			class="overlay"
			@click="closeOnMobile"
		/>

		<!-- Sidebar Slot -->
		<slot name="sidebar" v-bind="{ isOpen, isMobile, toggleMenu, closeOnMobile }" />

		<!-- Main Content Area -->
		<main
			class="main-content flex column ease-300"
			:style="mainContentStyles"
		>
			<!-- Header Slot -->
			<slot name="header" v-bind="{ isOpen, isMobile, toggleMenu, closeOnMobile }" />

			<!-- Page Content -->
			<div class="page-content overflow w-100p h-100p">
				<slot v-bind="{ isOpen, isMobile, toggleMenu, closeOnMobile }" />
			</div>
		</main>
	</div>
</template>

<style scoped>

.app-layout {
display: flex;
height: 100vh;
overflow: hidden;
}
.app-layout:has(.cardWrapSide) {
padding-inline-start: 0.5rem;
padding-inline-end: 1rem;
}

.app-layout:has(.sidebar-collapsed .cardWrapSide) {
padding-inline-start: 1.5rem;
}

/* Overlay for mobile */
.overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 40;
}

/* Main Content */
.main-content {
flex: 1;
overflow: hidden;
transition: margin-inline-start 400ms ease;
	min-height: 100vh
}

.page-content {
	overflow: auto;
}
@media screen and (max-width: 910px) {
.app-layout:has(.cardWrapSide),
.app-layout:has(.sidebar-collapsed .cardWrapSide) {
	padding-inline-start: 0rem;
	padding-inline-end: 0rem;
}
}

</style>
