<script lang="ts" setup>
import { twMerge, twJoin } from 'tailwind-merge'
import AAlert from '#adata-ui/components/elements/alert/AAlert.vue'

interface Props {
  disabled?: boolean
  label?: string
  size?: 'sm' | 'md'
  error?: string | boolean
  required?: boolean
  readonly?: boolean
  clearable?: boolean
  resizeable?: boolean | 'none' | 'both' | 'x' | 'y'
  startIcon?: string | object
  colorClasses?: string
}

const props = withDefaults(defineProps<Props>(), {
  disabled: false,
  label: '',
  size: 'md',
  error: false,
  required: false,
  readonly: false,
  clearable: false,
  resizeable: true,
  startIcon: '',
  colorClasses: ''
})

const uiConfig = {
  wrapper: 'transition duration-500 w-full',
  'input-wrapper': {
    base: 'relative inline-block h-full w-full text-sm sm:min-w-full pt-5 hover:outline hover:outline-1 outline-offset-[-1px] hover:outline-blue-700 hover:dark:outline-blue-500 focus:outline focus:outline-blue-700 focus:dark:outline-blue-500',
    readonly: 'pointer-events-none user-select-none',
    disabled: 'pointer-events-none user-select-none opacity-40',
    color: 'bg-deepblue-900/5 dark:bg-gray-200/5'
  },
  base: 'w-full border-0 rounded-md text-deepblue-900 dark:text-gray-200 outline-none mt-0',
  size: {
    sm: 'h-8 px-4 py-1.5 sm',
    md: 'h-10 px-4 pb-1.5 pt-[8px] md'
  },
  color: 'bg-deepblue-900/0 dark:bg-gray-200/0',
  error:
    'outline outline-1 outline-red-500 focus:outline-0 focus:border-red-500 hover:border-red-500',
  readonly: 'bg-white opacity-30',
  label: {
    base: 'absolute left-4 top-5 d-flex text-gray-500 pointer-events-none transition-all ease duration-300 transform translate-y-[-50%] whitespace-nowrap',
    'move-label': '!left-10'
  },
  default: {
    size: 'md',
    color: 'gray'
  },
  resize: {
    none: 'resize-none',
    both: 'resize',
    x: 'resize-x',
    y: 'resize-y'
  },
  'move-input': '!ps-10'
}

const modelValue = defineModel<string | number>({ default: '' })

const isClearable = computed<boolean>(
  () => props.clearable && !props.disabled && !!modelValue.value
)
const isResizeable = computed<boolean>(
  () => props.resizeable && props.resizeable !== 'none' && !props.disabled && !!modelValue.value
)

const resizeable = computed(() => {
  if (typeof props.resizeable === 'boolean') return props.resizeable ? 'both' : 'none'
  return props.resizeable
})

const wrapperClass = uiConfig.wrapper

const inputWrapperClass = computed(() =>
  twMerge(
    twJoin(
      uiConfig['input-wrapper'].base,
      uiConfig.base,
      props.colorClasses ? props.colorClasses : uiConfig['input-wrapper'].color,
      props.error ? uiConfig.error : '',
      props.readonly ? uiConfig['input-wrapper'].readonly : '',
      props.disabled ? uiConfig['input-wrapper'].disabled : ''
    )
  )
)

const inputClass = computed(() =>
  twMerge(
    twJoin(
      uiConfig.base,
      uiConfig.color,
      uiConfig.size[props.size],
      props.startIcon ? uiConfig['move-input'] : '',
      props.readonly ? uiConfig.readonly : '',
      isResizeable.value ? uiConfig.resize[resizeable] : uiConfig.resize.none
    )
  )
)

const labelClass = computed(() =>
  twMerge(twJoin(uiConfig.label.base, props.startIcon ? uiConfig.label['move-label'] : ''))
)
</script>

<template>
  <div :class="wrapperClass">
    <div :class="inputWrapperClass">
      <textarea
        :id="label"
        ref="input"
        v-model="modelValue"
        :class="inputClass"
        :tabindex="disabled ? -1 : 0"
        class="input"
        required
        v-bind="$attrs"
      />
      <label :class="labelClass" :for="label" class="label cursor-pointer">
        <span class="text">{{ label }}</span>
        <span v-if="required" class="text-red-600"> *</span>
      </label>

      <component
        :is="startIcon"
        v-if="startIcon"
        class="pointer-events-none absolute left-4 top-5 translate-y-[-50%] transform fill-gray-500 text-base text-gray-500"
        filled
      />
      <button
        v-if="isClearable"
        class="pointer-events-click absolute right-4 top-5 translate-y-[-50%] transform rounded-full bg-deepblue-900 bg-opacity-10 p-1 text-2xl hover:opacity-80 dark:bg-gray-200 dark:bg-opacity-10"
        type="button"
        @click="modelValue = ''"
      >
        <a-icon-x-mark class="!mb-0 fill-gray-600 dark:fill-gray-300" filled />
      </button>
      <slot name="endButton" />
    </div>
    <Transition name="slide-in">
      <slot name="alert">
        <div v-if="error && typeof error === 'string'" class="mt-1">
          <a-alert :color="'red'" :size="size === 'sm' ? 'sm' : 'lg'" icon-type="triangle">
            <template #default>
              <span v-for="(err, index) in error.split(', ')" :key="index">{{ err }}<br /></span>
            </template>
          </a-alert>
        </div>
      </slot>
    </Transition>
  </div>
</template>

<style scoped>
.input {
  &::-webkit-scrollbar {
    display: none;
  }

  &:focus ~ .label,
  &:not(:focus):valid ~ .label,
  &:-webkit-autofill ~ .label {
    font-size: 10px;
    transform: translateY(-17px);
  }
}

.slide-in-enter-active {
  z-index: 0;
  opacity: 0;
  transform: translateY(-50%);
  transition: transform 0.5s;
}

.slide-in-enter-to {
  z-index: auto;
  opacity: 1;
  transform: translateY(0);
}

.slide-in-leave-active {
  opacity: 1;
  transform: translateY(0);
}

.slide-in-leave-to {
  opacity: 0;
  transform: translateY(-100%);
}

.move-input {
  padding-left: 40px !important;
}
</style>
