<template>
  <view :class="rootClass" :style="customStyle" @click="handleClick">
    <view v-if="label || $slots.label" :class="labelClass" :style="labelStyle">
      <text v-if="isRequired && markerSide === 'before'" class="wd-input__required wd-input__required--left">*</text>
      <view v-if="prefixIcon || $slots.prefix" class="wd-input__prefix">
        <wd-icon v-if="prefixIcon && !$slots.prefix" custom-class="wd-input__icon" :name="prefixIcon" @click="onClickPrefixIcon" />
        <slot v-else name="prefix"></slot>
      </view>
      <view class="wd-input__label-inner">
        <text v-if="label && !$slots.label">{{ label }}</text>
        <slot v-else-if="$slots.label" name="label"></slot>
      </view>
      <text v-if="isRequired && markerSide === 'after'" class="wd-input__required">*</text>
    </view>
    <view class="wd-input__body">
      <view class="wd-input__value">
        <view v-if="(prefixIcon || $slots.prefix) && !label" class="wd-input__prefix">
          <wd-icon v-if="prefixIcon && !$slots.prefix" custom-class="wd-input__icon" :name="prefixIcon" @click="onClickPrefixIcon" />
          <slot v-else name="prefix"></slot>
        </view>
        <input
          :class="[
            'wd-input__inner',
            prefixIcon ? 'wd-input__inner--prefix' : '',
            showWordCount ? 'wd-input__inner--count' : '',
            alignRight ? 'is-align-right' : '',
            customInputClass
          ]"
          :type="type"
          :password="showPassword && !isPwdVisible"
          v-model="inputValue"
          :placeholder="placeholderValue"
          :disabled="disabled || readonly"
          :maxlength="maxlength"
          :focus="focused"
          :confirm-type="confirmType"
          :confirm-hold="confirmHold"
          :cursor="cursor"
          :cursor-spacing="cursorSpacing"
          :placeholder-style="placeholderStyle"
          :selection-start="selectionStart"
          :selection-end="selectionEnd"
          :adjust-position="adjustPosition"
          :hold-keyboard="holdKeyboard"
          :always-embed="alwaysEmbed"
          :placeholder-class="inputPlaceholderClass"
          :ignoreCompositionEvent="ignoreCompositionEvent"
          :inputmode="inputmode"
          @input="handleInput"
          @focus="handleFocus"
          @blur="handleBlur"
          @confirm="handleConfirm"
          @keyboardheightchange="handleKeyboardheightchange"
        />
        <view v-if="props.readonly" class="wd-input__readonly-mask" />
        <view v-if="showClear || showPassword || suffixIcon || showWordCount || $slots.suffix" class="wd-input__suffix">
          <wd-icon v-if="showClear" custom-class="wd-input__clear" name="error-fill" @click="handleClear" />
          <wd-icon v-if="showPassword" custom-class="wd-input__icon" :name="isPwdVisible ? 'view' : 'eye-close'" @click="togglePwdVisible" />
          <view v-if="showWordCount" class="wd-input__count">
            <text
              :class="[
              inputValue && String(inputValue).length > 0 ? 'wd-input__count-current' : '',
              String(inputValue).length > maxlength! ? 'is-error' : ''
            ]"
            >
              {{ String(inputValue).length }}
            </text>
            /{{ maxlength }}
          </view>
          <wd-icon v-if="suffixIcon && !$slots.suffix" custom-class="wd-input__icon" :name="suffixIcon" @click="onClickSuffixIcon" />
          <slot v-else name="suffix"></slot>
        </view>
      </view>
      <view v-if="errorMessage" class="wd-input__error-message">{{ errorMessage }}</view>
    </view>
  </view>
</template>

<script lang="ts">
export default {
  name: 'wd-input',
  options: {
    virtualHost: true,
    addGlobalClass: true,
    styleIsolation: 'shared'
  }
}
</script>

<script lang="ts" setup>
import { computed, ref, watch, useSlots, type Slots } from 'vue'
import wdIcon from '../wd-icon/wd-icon.vue'
import { isDef, objToStyle, pause, isEqual } from '../common/util'
import { useCell } from '../composables/useCell'
import { FORM_KEY, type FormItemRule } from '../wd-form/types'
import { useParent } from '../composables/useParent'
import { useTranslate } from '../composables/useTranslate'
import { inputProps } from './types'

interface InputSlots extends Slots {
  prefix?: () => any
  suffix?: () => any
  label?: () => any
}

const props = defineProps(inputProps)
const emit = defineEmits([
  'update:modelValue',
  'clear',
  'blur',
  'focus',
  'input',
  'keyboardheightchange',
  'confirm',
  'clicksuffixicon',
  'clickprefixicon',
  'click'
])
const slots = useSlots() as InputSlots
const { translate } = useTranslate('input')

const isPwdVisible = ref<boolean>(false)
const clearing = ref<boolean>(false) // 是否正在清空操作，避免重复触发失焦
const focused = ref<boolean>(false) // 控制聚焦
const focusing = ref<boolean>(false) // 当前是否激活状态
const inputValue = ref<string | number>(getInitValue()) // 输入框的值
const cell = useCell()

watch(
  () => props.focus,
  (newValue) => {
    focused.value = newValue
  },
  { immediate: true, deep: true }
)

watch(
  () => props.modelValue,
  (newValue) => {
    inputValue.value = isDef(newValue) ? String(newValue) : ''
  }
)

const { parent: form } = useParent(FORM_KEY)

const placeholderValue = computed(() => {
  return isDef(props.placeholder) ? props.placeholder : translate('placeholder')
})

/**
 * 展示清空按钮
 */
const showClear = computed(() => {
  const { disabled, readonly, clearable, clearTrigger } = props
  if (clearable && !readonly && !disabled && inputValue.value && (clearTrigger === 'always' || (props.clearTrigger === 'focus' && focusing.value))) {
    return true
  } else {
    return false
  }
})

/**
 * 展示字数统计
 */
const showWordCount = computed(() => {
  const { disabled, readonly, maxlength, showWordLimit } = props
  return Boolean(!disabled && !readonly && isDef(maxlength) && maxlength > -1 && showWordLimit)
})

/**
 * 表单错误提示信息
 */
const errorMessage = computed(() => {
  if (form && props.prop && form.errorMessages && form.errorMessages[props.prop]) {
    return form.errorMessages[props.prop]
  } else {
    return ''
  }
})

// 是否展示必填
const isRequired = computed(() => {
  let formRequired = false
  if (form && form.props.rules) {
    const rules = form.props.rules
    for (const key in rules) {
      if (Object.prototype.hasOwnProperty.call(rules, key) && key === props.prop && Array.isArray(rules[key])) {
        formRequired = rules[key].some((rule: FormItemRule) => rule.required)
      }
    }
  }
  return props.required || props.rules.some((rule) => rule.required) || formRequired
})

const rootClass = computed(() => {
  return `wd-input  ${props.label || slots.label ? 'is-cell' : ''} ${props.center ? 'is-center' : ''} ${cell.border.value ? 'is-border' : ''} ${
    props.size ? 'is-' + props.size : ''
  } ${props.error ? 'is-error' : ''} ${props.disabled ? 'is-disabled' : ''}  ${
    inputValue.value && String(inputValue.value).length > 0 ? 'is-not-empty' : ''
  }  ${props.noBorder ? 'is-no-border' : ''} ${props.customClass}`
})

const labelClass = computed(() => {
  return `wd-input__label ${props.customLabelClass}`
})

const inputPlaceholderClass = computed(() => {
  return `wd-input__placeholder  ${props.placeholderClass}`
})

const labelStyle = computed(() => {
  return props.labelWidth
    ? objToStyle({
        'min-width': props.labelWidth,
        'max-width': props.labelWidth
      })
    : ''
})

// 状态初始化
function getInitValue() {
  const formatted = formatValue(props.modelValue)
  if (!isValueEqual(formatted, props.modelValue)) {
    emit('update:modelValue', formatted)
  }
  return formatted
}

function formatValue(value: string | number) {
  const { maxlength } = props
  if (isDef(maxlength) && maxlength !== -1 && String(value).length > maxlength) {
    return value.toString().slice(0, maxlength)
  }
  return value
}

function togglePwdVisible() {
  isPwdVisible.value = !isPwdVisible.value
}
async function handleClear() {
  focusing.value = false
  inputValue.value = ''
  if (props.focusWhenClear) {
    clearing.value = true
    focused.value = false
  }
  await pause()
  if (props.focusWhenClear) {
    focused.value = true
    focusing.value = true
  }
  emit('update:modelValue', inputValue.value)
  emit('clear')
}
async function handleBlur() {
  // 等待150毫秒，clear执行完毕
  await pause(150)
  if (clearing.value) {
    clearing.value = false
    return
  }
  focusing.value = false
  emit('blur', {
    value: inputValue.value
  })
}
function handleFocus({ detail }: any) {
  focusing.value = true
  emit('focus', detail)
}
function handleInput({ detail }: any) {
  emit('update:modelValue', inputValue.value)
  emit('input', detail)
}
function handleKeyboardheightchange({ detail }: any) {
  emit('keyboardheightchange', detail)
}
function handleConfirm({ detail }: any) {
  emit('confirm', detail)
}
function onClickSuffixIcon() {
  emit('clicksuffixicon')
}
function onClickPrefixIcon() {
  emit('clickprefixicon')
}
function handleClick(event: MouseEvent) {
  emit('click', event)
}
function isValueEqual(value1: number | string, value2: number | string) {
  return isEqual(String(value1), String(value2))
}
</script>

<style lang="scss" scoped>
@import './index.scss';
</style>
<style lang="scss">
@import './placeholder.scss';
</style>
