<script setup lang="ts">
defineOptions({ name: 'BglBadge' })
import type { IconType, ThemeType, GradientProp, GradientDirProp } from '@bagelink/vue'
import type { SetupContext } from 'vue'
import { Btn, Icon, useGradientVariant } from '@bagelink/vue'
import { computed, useSlots } from 'vue'
import '../styles/base-colors.css'

interface BtnProp {
	icon?: IconType
	onClick: () => void
	value?: string
}

const props = defineProps<{
	disabled?: boolean
	icon?: IconType
	iconEnd?: IconType
	color?: ThemeType
	variant?: 'solid' | 'flat' | 'outline' | 'glass' | 'soft' | 'frost'
	/** Boolean variant shorthands: <Badge 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. <Badge 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
	/** Translucent frosted badge — readable on photos / gradients / dark heroes.
	    Shorthand for variant="glass". */
	glass?: boolean
	/** Leading status dot in the theme color (e.g. ● Live, ● Active). */
	dot?: boolean
	/** @deprecated Use `outline` */
	border?: boolean
	loading?: boolean
	value?: string
	round?: boolean
	btn?: BtnProp
	btnEnd?: BtnProp
	size?: 'sm' | 'md' | 'lg'
	/** Boolean size shorthands: <Badge sm value="New" /> */
	sm?: boolean
	lg?: boolean
	/** Mobile-only size override (≤ 910px). Lets a `lg` desktop badge shrink on
	    phones so it doesn't overflow / touch neighbours. e.g.
	    <Badge lg mobile-size="sm" />. Mirrors `Icon`'s `mobileSize` prop. */
	mobileSize?: 'sm' | 'md' | 'lg'
	uppercase?: boolean
}>()

const slots: SetupContext['slots'] = useSlots()

const computedTheme = computed(
	() => {
		if (props.disabled) { return 'gray-light' }
		return props.color as ThemeType
	},
)

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

const computedPairClass = computed(() => {
	const theme = computedTheme.value
	if (!theme) {
		// Frost defaults to a white (light-on-dark) glass when no color is given.
		if (computedVariant.value === 'frost') { return 'pair-white' }
		return 'pair-primary'
	}
	return `pair-${theme}`
})

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

/** Mobile-only size override (≤ 910px). Falls back to undefined when not set,
    so the desktop size keeps applying at all widths. */
const computedMobileSize = computed(() => props.mobileSize)

const computedVariant = computed(() => {
	if (props.variant) { return props.variant }
	if (isGradient.value) { return 'gradient' }
	if (props.frost) { return 'frost' }
	if (props.glass) { return 'glass' }
	if (props.soft) { return 'soft' }
	if (props.flat) { return 'flat' }
	if (props.outline || props.border) { return 'outline' }
	return 'solid'
})

const computedClasses = computed(() => {
	const classes: Record<string, boolean> = {
		'bgl_pill': !props.icon || !!slots.default || !!props.value,
		'round': props.round,
		'bgl_flatPill': computedVariant.value === 'flat',
		'bgl_pill-border': computedVariant.value === 'outline',
		'bgl_pill-frame': props.frame,
		'bgl_glassPill': computedVariant.value === 'glass',
		'soft': computedVariant.value === 'soft',
		'frost': computedVariant.value === 'frost',
		'gradient': computedVariant.value === 'gradient',
		'pillLarge': computedSize.value === 'lg',
		'pillSmall': computedSize.value === 'sm',
		'm_pillLarge': computedMobileSize.value === 'lg',
		'm_pillMd': computedMobileSize.value === 'md',
		'm_pillSmall': computedMobileSize.value === 'sm',
	}

	// Add the pair class
	classes[computedPairClass.value] = true

	return classes
})
</script>

<template>
	<div
		class="bgl_pill"
		:style="[{ height: 'var(--bgl-pill-height)' }, gradientStyle]"
		:disabled="disabled"
		:class="computedClasses"
	>
		<div class="flex h-100 justify-content-center relative ">
			<div v-if="loading" class="loading absolute inset-0 mx-auto" />
			<div class="px-025 flex gap-025 justify-content-center align-items-center" :class="{ 'opacity-0': loading }">
				<Btn v-if="btn" class="bgl_pill-btn -ms-025" icon-size="0.8" round v-bind="btn" />
				<span v-if="dot" class="bgl_pill-dot" />
				<Icon v-if="icon" class="line-height-0" :icon="icon" style="font-size: var(--bgl-pill-font-size)" />
				<slot :class="{ uppercase }" />
				<template v-if="!slots.default">
					<p class="pillText inline" :class="{ uppercase }">
						{{ value }}
					</p>
				</template>
				<Icon v-if="iconEnd" class="line-height-0" :icon="iconEnd" style="font-size: var(--bgl-pill-font-size)" />
				<Btn v-if="btnEnd" class="bgl_pill-btn -me-025" icon-size="0.8" round v-bind="btnEnd" />
			</div>
		</div>
	</div>
</template>

<style scoped>

.pillLarge{
--bgl-pill-font-size: var(--bgl-font-size);
--bgl-pill-height:auto;
}
.pillSmall{
--bgl-pill-font-size: 9px;
--bgl-pill-height:15px;
}

/* Mobile-only size overrides (≤ 910px). These win over the desktop size class
   because the size is driven entirely by --bgl-pill-font-size / --bgl-pill-height,
   and a later @media rule with equal specificity overrides the base class. */
@media screen and (max-width: 910px) {
	.m_pillLarge {
		--bgl-pill-font-size: var(--bgl-font-size);
		--bgl-pill-height: auto;
	}
	.m_pillMd {
		--bgl-pill-font-size: 12px;
		--bgl-pill-height: 20px;
	}
	.m_pillSmall {
		--bgl-pill-font-size: 9px;
		--bgl-pill-height: 15px;
	}
}
.pillText{
font-size: var(--bgl-pill-font-size);
white-space: nowrap;
}
.bgl_pill-dot{
width: 6px;
height: 6px;
border-radius: 50%;
flex-shrink: 0;
/* Use the badge's text color so the dot is always legible on both solid
   (white text) and -light/-tint (tone text) variants. */
background: currentColor;
}
.bgl_pill-btn{
color: var(--bgl-pill-btn-color);
background: var(--bgl-pill-btn-bg);
width: calc(var(--bgl-pill-height) / 1.25)!important;
height: calc(var(--bgl-pill-height) / 1.25)!important;
}
.loading {
  border: 1px solid var(--bgl-light-text);
  border-bottom: 2px solid var(--bgl-light-text);
  animation: spin 1s linear infinite;
  border-radius: 100px;
  width: 1rem;
  height: 1rem;
  margin: auto;
}
.bgl_flatPill .loading {
border-bottom: 2px solid var(--bgl-text-color);
}

@keyframes spin {
  0% {
transform: rotate(0deg);
  }
  100% {
transform: rotate(360deg);
  }
}

.bgl_pill {
  padding-inline: calc(var(--bgl-pill-font-size) / 6);
  padding-block: calc(var(--bgl-pill-font-size) / 24);
transition: var(--bgl-transition);
  display: inline-block;
  margin-inline-end: 0.25rem;
  border-radius: var(--bgl-pill-border-radius);
  min-height: var(--bgl-pill-height);
vertical-align: middle;
}

.bgl_pill[disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
}
.bgl_pill.round {
border-radius: 1000px;
}

/* Glass: frosted translucent badge for photos / gradients / dark heroes.
   Defaults to light-on-dark; flip via --bgl-glass-bg / --bgl-glass-color. */
.bgl_glassPill {
background-color: var(--bgl-glass-bg, rgba(255, 255, 255, 0.18)) !important;
color: var(--bgl-glass-color, #fff) !important;
border: 1px solid var(--bgl-glass-border, rgba(255, 255, 255, 0.28));
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}

</style>
