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

export interface TextInputProps extends ValidateInputBaseT, BagelInputShellProps {
	id?: string
	title?: string
	helptext?: string
	name?: string
	placeholder?: string
	modelValue?: string
	label?: string
	small?: boolean
	dense?: boolean
	required?: boolean
	pattern?: string
	defaultValue?: string
	shrink?: boolean
	underlined?: boolean
	disabled?: boolean
	type?: string
	nativeInputAttrs?: { [key: string]: any }
	icon?: IconType
	iconStart?: IconType
	multiline?: boolean
	autoheight?: boolean
	code?: boolean
	rows?: number | string
	autocomplete?: string
	autofocus?: boolean
	error?: string
	onFocusout?: (e: FocusEvent) => void
	onFocus?: (e: FocusEvent) => void
}

export interface PasswordInputProps extends TextInputProps {
	strengthMeter?: boolean
}

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

const { $t } = useI18n()

const textInputProps = computed(() => {
	// eslint-disable-next-line @typescript-eslint/no-unused-vars
	const { strengthMeter: _strengthMeter, modelValue: _modelValue, ...rest } = props
	return rest
})

const password = defineModel<string>()
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(--bgl-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 ? [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="textInputProps" :type="inputType" class="mb-0" />
		<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(--bgl-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(--bgl-input-bg);
}

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

.password-strength-label {
transition: color 0.3s ease;
}

</style>
