<script setup lang="ts">
import type { IconType } from '@bagelink/vue'
import { Btn, TextInput, useI18n } from '@bagelink/vue'
import { zxcvbn } from '@zxcvbn-ts/core'
import { computed } from 'vue'

const props = withDefaults(
	defineProps<TextInputProps>(),
	{
		autocomplete: 'current-password',
		label: '',
		strengthMeter: false
	}
)

const { $t } = useI18n()

export interface TextInputProps {
	id?: string
	title?: string
	helptext?: string
	placeholder?: string
	label?: string
	small?: boolean
	dense?: boolean
	required?: boolean
	pattern?: string
	shrink?: boolean
	underlined?: boolean
	disabled?: boolean
	name?: string
	nativeInputAttrs?: { [key: string]: any }
	icon?: IconType
	iconStart?: IconType
	multiline?: boolean
	autoheight?: boolean
	code?: boolean
	lines?: number
	autofocus?: boolean
	debounceDelay?: number
	autocomplete?: AutoFillField
	onFocusout?: (e: FocusEvent) => void
	strengthMeter?: boolean
	error?: string
}
const password = defineModel<string>('modelValue')
const showPwd = defineModel<boolean>('showPwd', { default: false })

const toggleShowPwdIcon = computed(() => showPwd.value ? 'visibility_off' : 'visibility')
const inputType = computed(() => (showPwd.value ? 'text' : 'password'))

const passwordStrength = computed(() => {
	const pwd = password.value
	if (!props.strengthMeter || pwd == null || pwd.length === 0) {
		return null
	}
	return zxcvbn(pwd)
})

const strengthScore = computed(() => {
	if (password.value == null || password.value.length === 0) {
		return null
	}
	return passwordStrength.value?.score ?? 0
})

const strengthColor = computed(() => {
	const score = strengthScore.value
	if (score == null) return 'var(--input-bg)' // gray - no password
	if (score <= 1) return 'var(--bgl-red)' // red
	if (score === 2) return 'var(--bgl-orange)' // orange
	if (score === 3) return 'var(--bgl-yellow)' // amber
	return 'var(--bgl-green)' // green
})

const strengthLabel = computed(() => {
	const score = strengthScore.value
	if (score == null) return ''
	if (score === 0) return $t('password.veryWeak')
	if (score === 1) return $t('password.weak')
	if (score === 2) return $t('password.fair')
	if (score === 3) return $t('password.good')
	return $t('password.strong')
})

const strengthPercentage = computed(() => {
	const score = strengthScore.value
	if (score == null) return 0
	return ((score + 1) / 5) * 100
})

const feedbackMessage = computed(() => {
	const strength = passwordStrength.value
	if (!strength)
		return ''
	const { feedback: { warning, suggestions } } = strength
	const warnings = (warning != null && warning !== '') ? [warning] : []
	return [...warnings, ...suggestions].join(' ')
})
</script>

<template>
	<div class="relative passwordInput" :class="{ 'relative mb-2': props.strengthMeter, 'has-error': !!props.error, 'underlined': props.underlined }">
		<TextInput v-model="password" v-bind="props" :type="inputType" class="mb-0" :name="props.name" :error="props.error" :underlined="props.underlined" />
		<div class="m-password position-bottom-end flex column justify-content-center">
			<Btn flat thin class="mx-05" :icon="toggleShowPwdIcon" @click="showPwd = !showPwd" />
		</div>
		<div v-if="props.strengthMeter" class="password-strength-container absolute start end -bottom-1-5">
			<div v-tooltip="feedbackMessage || `Password strength: ${strengthLabel}`" class="password-strength-bar pointer overflow-hidden round">
				<div
					class="password-strength-fill h-100p round" :style="{
						width: `${strengthPercentage}%`,
						backgroundColor: strengthColor,
					}"
				/>
			</div>
			<span class="password-strength-label txt10 light white-space " :style="{ color: strengthColor }">
				{{ strengthLabel }}
			</span>
		</div>
	</div>
</template>

<style>
.m-password {
	height: var(--input-height) !important;
}

[dir='rtl'] .passwordInput input {
	direction: ltr;
	text-align: right;
}

.password-strength-container {
	height: 1.25rem;
}

.password-strength-bar {
	flex: 1;
	height: 6px;
	background-color: var(--input-bg);
}

.password-strength-fill {
	transition: width 0.3s ease, background-color 0.3s ease;
}

.password-strength-label {
	transition: color 0.3s ease;
}
</style>
