<script setup lang="ts">
import type { IconType, ExtendedThemeType, TranslatableString, GradientProp, GradientDirProp } from '@bagelink/vue'
import type { SetupContext } from 'vue'
import { Icon, Loading, useDialog, useI18n, resolveI18n, useGradientVariant, MOBILE_BREAKPOINT } from '@bagelink/vue'
import { useSlots, ref, onMounted, onUnmounted, computed } from 'vue'
import { RouterLink } from 'vue-router'
defineOptions({ name: 'BglBtn' })
const props = withDefaults(
	defineProps<{
		disabled?: boolean
		icon?: IconType
		iconEnd?: IconType
		iconSize?: number | string
		iconMobileSize?: number | string
		color?: ExtendedThemeType
		variant?: 'solid' | 'flat' | 'outline' | 'soft' | 'frost'
		/** Boolean variant shorthands: <Btn flat /> — same as variant="flat" */
		flat?: boolean
		outline?: boolean
		/** Soft variant: light tinted bg + full-color text & border, driven by `color`.
		    Shorthand for variant="soft". e.g. <Btn color="blue" soft /> */
		soft?: boolean
		/** Frost variant: translucent + blur, tinted by `color`. Reads beautifully
		    over photos / gradients / dark heroes. Shorthand for variant="frost". */
		frost?: boolean
		/** Gradient fill (white text). Boolean = auto (a darker shade of `color`);
		    or a space-separated tone list — "purple" pairs with `color`
		    (blue→purple), "blue purple pink" defines all stops. */
		gradient?: GradientProp
		/** Gradient direction: a named direction ("to-br") or an angle in degrees
		    (45 or "45"). Defaults to 135deg. */
		gradientDir?: GradientDirProp
		/** Solid fill + a hairline border (keeps the background, unlike `outline`). */
		frame?: boolean
		/** @deprecated Use `outline` */
		border?: boolean
		thin?: boolean
		size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
		/** Boolean size shorthands: <Btn sm value="Click me" /> */
		xs?: boolean
		sm?: boolean
		md?: boolean
		lg?: boolean
		xl?: boolean
		type?: 'button' | 'submit' | 'reset'
		loading?: boolean
		role?: string
		value?: TranslatableString
		to?: string | Record<string, any>
		href?: string
		round?: boolean
		is?: string
		ripple?: boolean
		fullWidth?: boolean
		fullWidthMobile?: boolean
		alignTxt?: 'center' | 'start' | 'end'
		alignTxtMobile?: 'center' | 'start' | 'end'
		onClick?: (e: MouseEvent) => void
		confirm?: boolean | string
	}>(),
	{
		onClick: () => '',
		loading: false,
		round: false,
		disabled: false,
		type: 'button',
		role: 'button',
		is: 'button',
		border: false,
		outline: false,
		ripple: true,
		fullWidth: false,
		fullWidthMobile: false,
		alignTxt: 'center',
		alignTxtMobile: 'center',
	},
)

const emit = defineEmits<{
	confirmed: [event: MouseEvent]
}>()

const { $t } = useI18n()

const { isGradient, gradientStyle } = useGradientVariant({
	gradient: () => props.gradient,
	gradientDir: () => props.gradientDir,
	color: () => props.color,
})

const computedVariant = computed(() => {
	if (props.variant) { return props.variant }
	if (isGradient.value) { return 'gradient' }
	if (props.frost) { return 'frost' }
	if (props.soft) { return 'soft' }
	// An explicit `outline`/`border` wins over `flat` — components like Dropdown
	// default the trigger to `flat`, so `<Dropdown outline>` must still resolve to
	// the outline variant rather than being swallowed by the inherited flat.
	if (props.outline || props.border) { return 'outline' }
	// `frame` is "solid fill + a border", so it also overrides an inherited
	// `flat` (e.g. Dropdown's flat trigger) to restore the solid background.
	if (props.frame) { return 'solid' }
	if (props.flat) { return 'flat' }
	return 'solid'
})

const computedPairClass = computed(() => {
	const theme = props.color
	if (!theme) {
		// Frost defaults to a white (light-on-dark) glass when no color is given.
		if (computedVariant.value === 'frost') {
			return 'pair-white'
		}
		// Gradient with explicit stops (e.g. gradient="blue purple") needs a pair
		// class only to activate `.gradient`; default to primary for the auto case.
		if (computedVariant.value === 'gradient') {
			return 'pair-primary'
		}
		// Only flat/outline/soft buttons get a default for visibility
		if (computedVariant.value !== 'solid') {
			return 'pair-black'
		}
		return 'pair-default'
	}
	return `pair-${theme}`
})

const computedSize = computed(() => {
	if (props.size) { return props.size }
	if (props.xs) { return 'xs' }
	if (props.sm) { return 'sm' }
	if (props.md) { return 'md' }
	if (props.lg) { return 'lg' }
	if (props.xl) { return 'xl' }
	return undefined
})

const isMobileScreen = ref(false)

function checkMobile() {
	isMobileScreen.value = window.innerWidth <= MOBILE_BREAKPOINT
}

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

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

async function handleClick(event: MouseEvent) {
	if (props.confirm !== undefined && props.confirm !== false) {
		const { confirm } = useDialog()
		const message = typeof props.confirm === 'string' ? props.confirm : $t('modalConfirm.message')
		const confirmed = await confirm({
			title: $t('modalConfirm.title'),
			message
		})

		if (!confirmed) { return }

		props.onClick(event)
		emit('confirmed', event)
	} else {
		props.onClick(event)
	}
}

const iconSizeComputed = computed(() => {
	if (props.iconSize !== undefined) { return props.iconSize }

	// Default icon sizes based on button size
	const sizeMap = { xs: 0.7, sm: 0.9, md: 1, lg: 1.3, xl: 1.6 }
	const size = computedSize.value
	if (size && sizeMap[size]) { return sizeMap[size] }

	return isMobileScreen.value ? 1 : 1.2
})

const isComponent = computed(() => {
	if (props.disabled) { return props.is }
	if (props.to !== undefined && props.to !== '') { return RouterLink }
	if (props.href !== undefined && props.href !== '') { return 'a' }
	return props.is
})

const bind = computed(() => {
	const obj: { [key: string]: any } = {}
	if (!props.disabled) {
		if (props.to !== undefined && props.to !== '') { obj.to = props.to }
		else if (props.href !== undefined && props.href !== '') { obj.href = props.href }
	}
	if ((props.to === undefined || props.to === '') && (props.href === undefined || props.href === '')) {
		obj.role = props.role
		obj.type = props.type
	}
	return obj
})
const slots: SetupContext['slots'] = useSlots()
</script>

<template>
	<component
		:is="isComponent" v-ripple="ripple" v-bind="bind" :disabled="disabled" class="bgl_btn" :class="[{
			'bgl_btn-icon': icon && !slots.default && !value,
			thin,
			'bgl_btn_xsSize': computedSize === 'xs',
			'bgl_btn_sSize': computedSize === 'sm',
			'bgl_btn_mSize': computedSize === 'md',
			'bgl_btn_lSize': computedSize === 'lg',
			'bgl_btn_xlSize': computedSize === 'xl',
			'bgl_btn_fullWidth': fullWidth,
			'bgl_btn_fullWidthMobile': fullWidthMobile,
			'bgl_btn_alignStart': alignTxt === 'start',
			'bgl_btn_alignEnd': alignTxt === 'end',
			'bgl_btn_alignStartMobile': alignTxtMobile === 'start',
			'bgl_btn_alignEndMobile': alignTxtMobile === 'end',
			round,
			'bgl_flatPill': computedVariant === 'flat',
			'bgl_pill-border': computedVariant === 'outline',
			'soft': computedVariant === 'soft',
			'frost': computedVariant === 'frost',
			'gradient': computedVariant === 'gradient',
			'bgl_pill-frame': frame,
		}, computedPairClass]" :style="gradientStyle" :tabindex="disabled ? -1 : 0" @click.stop="handleClick" @keydown.enter="handleClick" @keydown.space="handleClick"
	>
		<Loading v-if="loading" class="h-100p" size="15" color="currentColor" />
		<div v-else class="bgl_btn-flex">
			<Icon
				v-if="icon" :icon="icon" class="transition-400" :size="iconSizeComputed"
				:mobile-size="iconMobileSize"
			/>
			<slot />
			<template v-if="!slots.default && value">
				{{ resolveI18n(value) }}
			</template>
			<Icon
				v-if="iconEnd" :icon="iconEnd" class="transition-400" :size="iconSizeComputed"
				:mobile-size="iconMobileSize"
			/>
		</div>
	</component>
</template>

<style scoped>

/* @import '../styles/base-colors.css'; */

.bgl_btn {
padding-left: var(--bgl-btn-padding);
padding-right: var(--bgl-btn-padding);
transition: var(--bgl-transition);
text-decoration: none;
/* Colors now handled by pair-* classes */
}

/* Touch targets: keep visuals, but extend the hit area to >=44px on touch devices */
@media (pointer: coarse) {
.bgl_btn {
	position: relative;
}

.bgl_btn::after {
	content: '';
	position: absolute;
	left: 50%;
	top: 50%;
	transform: translate(-50%, -50%);
	width: max(100%, 44px);
	height: max(100%, 44px);
}
}

.bgl_btn.bgl_btn-icon {
padding-left: 0;
padding-right: 0;
height: var(--bgl-btn-height);
width: var(--bgl-btn-height);
border-radius: 100%;
font-size: 1rem;
flex-shrink: 0;
}

a {
text-decoration: none;
}

.bgl_btn-flex {
display: flex;
align-items: center;
gap: 0.5rem;
justify-content: center;
height: 100%;
}

.bgl_btn .bgl_btn-icon {
font-size: calc(var(--bgl-input-font-size) * 1.3);
}

.bgl_btn:hover,
.bgl_btn-icon:hover {
filter: var(--bgl-hover-filter);
}

.bgl_btn:active:not(:disabled),
.bgl_btn-icon:active:not(:disabled) {
filter: var(--bgl-active-filter);
}

/* Flat hover/active styles now handled by base-colors.css */

.bgl_btn.round {
border-radius: 1000px !important;
}

[dir="rtl"] .bgl_btn-icon {
transform: rotateY(180deg);
}

[dir="rtl"] .ltr .bgl_btn-icon {
transform: rotateY(0deg);
}

/* Border active styles now handled by base-colors.css */

.bgl_btn:disabled,
.bgl_btn[disabled=true] {
opacity: 0.7;
filter: grayscale(0.3);
cursor: not-allowed;
}

.bgl_btn-icon .bgl_btn-flex {
height: 100%;
}

/* xs size */
.bgl_btn_xsSize {
padding-inline: calc(var(--bgl-btn-padding) / 6);
border-radius: calc(var(--bgl-btn-border-radius) / 2);
font-size: calc(var(--bgl-input-font-size) * 0.6);
}

.bgl_btn-icon.bgl_btn_xsSize {
height: calc(var(--bgl-btn-height) / 2);
width: calc(var(--bgl-btn-height) / 2);
line-height: normal;
}

.bgl_btn_xsSize {
height: calc(var(--bgl-btn-height) / 2);
line-height: calc(var(--bgl-btn-height) / 2);
}

.bgl_btn_xsSize .bgl_btn-flex {
gap: 0.2rem;
}

/* s size */
.bgl_btn.thin,
.bgl_btn_sSize {
padding-inline: calc(var(--bgl-btn-padding) / 3);
border-radius: calc(var(--bgl-btn-border-radius) / 1.5);
}

.bgl_btn-icon.thin,
.bgl_btn-icon.bgl_btn_sSize {
height: calc(var(--bgl-btn-height) / 1.5);
width: calc(var(--bgl-btn-height) / 1.5);
line-height: normal;
}

.bgl_btn.thin,
.bgl_btn_sSize {
height: calc(var(--bgl-btn-height) * 0.7);
line-height: calc(var(--bgl-btn-height) * 0.7);
}

/* m size */
.bgl_btn_mSize {
padding-inline: var(--bgl-btn-padding);
font-size: var(--bgl-input-font-size);
height: var(--bgl-btn-height);
line-height: var(--bgl-btn-height);
}

.bgl_btn-icon.bgl_btn_mSize {
height: var(--bgl-btn-height);
width: var(--bgl-btn-height);
}

/* l size */
.bgl_btn_lSize {
padding-inline: calc(var(--bgl-btn-padding) * 1.3);
font-size: calc(var(--bgl-input-font-size) * 1.1);
height: calc(var(--bgl-btn-height) * 1.2);
line-height: calc(var(--bgl-btn-height) * 1.2);
}

.bgl_btn-icon.bgl_btn_lSize {
height: calc(var(--bgl-btn-height) * 1.2);
width: calc(var(--bgl-btn-height) * 1.2);
}

/* xl size */
.bgl_btn_xlSize {
padding-inline: calc(var(--bgl-btn-padding) * 1.6);
font-size: calc(var(--bgl-input-font-size) * 1.3);
height: calc(var(--bgl-btn-height) * 1.5);
line-height: calc(var(--bgl-btn-height) * 1.5);
}

.bgl_btn-icon.bgl_btn_xlSize {
height: calc(var(--bgl-btn-height) * 1.5);
width: calc(var(--bgl-btn-height) * 1.5);
}

.bgl_btn_fullWidth {
width: 100%;
}

.bgl_btn_fullWidthMobile {
width: auto;
}

/* Content alignment styles */
.bgl_btn_alignStart .bgl_btn-flex {
justify-content: flex-start;
}

.bgl_btn_alignEnd .bgl_btn-flex {
justify-content: flex-end;
}

.bgl_btn_alignStartMobile .bgl_btn-flex {
justify-content: center;
}

.bgl_btn_alignEndMobile .bgl_btn-flex {
justify-content: center;
}

@media screen and (max-width: 910px) {
.bgl_btn_fullWidthMobile {
	width: 100%;
}

.bgl_btn_alignStartMobile .bgl_btn-flex {
	justify-content: flex-start;
}

.bgl_btn_alignEndMobile .bgl_btn-flex {
	justify-content: flex-end;
}
}

</style>
