<script setup lang="ts">
import { Input as ShadcnInput } from '@/components/core/input';
import { UiButton } from '@/components/UiButton';
import { UiIcon } from '@/components/UiIcon';
import { computed, ref, useAttrs } from 'vue';
import type { UiInputProps } from './types';

defineOptions({
  name: 'UiInput',
  inheritAttrs: false,
});

const props = withDefaults(defineProps<UiInputProps>(), {
  type: 'text',
  disabled: false,
  placeholder: undefined,
  required: false,
  accept: undefined,
  multiple: false,
  uploadButtonLabel: 'Upload',
});

const emit = defineEmits<{
  /** Emitted when the user selects files in `type="file"` mode. */
  'update:files': [files: File[]];
}>();

const model = defineModel<string>();

const attrs = useAttrs();
const isFile = computed(() => props.type === 'file');

const selectedFiles = ref<File[]>([]);

const filePlaceholder = computed(() => props.placeholder ?? 'No file chosen');

const fileDisplayValue = computed(() => {
  if (selectedFiles.value.length === 0) return '';
  if (selectedFiles.value.length === 1)
    return selectedFiles.value[0]?.name ?? '';
  return `${selectedFiles.value.length} files selected`;
});

const fileInputId = computed(() => `${props.name}-file-input`);

function handleFilesChange(e: Event) {
  const target = e.target as HTMLInputElement;
  const files = Array.from(target.files ?? []);
  selectedFiles.value = files;
  emit('update:files', files);
}
</script>

<template>
  <!--
    File mode: a flex wrapper styled like a regular input. The upload button
    sits on the left and the visible filename/placeholder follows with an
    8px (`gap-2`) gap. The real <input type="file"> is visually hidden and
    triggered by the button via a wrapping <label>.
  -->
  <div
    v-if="isFile"
    v-bind="attrs"
    class="flex h-9 w-full min-w-0 items-center gap-2 rounded-md border border-input bg-background-input-default px-1 transition-[color] outline-none focus-within:border-ring focus-within:ring-ring/50 focus-within:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
    :class="{
      'pointer-events-none cursor-not-allowed opacity-50': props.disabled,
    }"
  >
    <input
      :id="fileInputId"
      type="file"
      class="sr-only"
      :name="props.name"
      :disabled="props.disabled"
      :required="props.required"
      :accept="props.accept"
      :multiple="props.multiple"
      @change="handleFilesChange"
    />
    <UiButton as-child variant="secondary" size="sm" :disabled="props.disabled">
      <label :for="fileInputId" class="cursor-pointer">
        <UiIcon name="upload" />
        {{ props.uploadButtonLabel }}
      </label>
    </UiButton>
    <span
      class="placeholder:text-muted-foreground flex-1 truncate pr-2 text-base md:text-sm"
      :class="{ 'text-muted-foreground': fileDisplayValue === '' }"
      :aria-controls="fileInputId"
    >
      {{ fileDisplayValue || filePlaceholder }}
    </span>
  </div>
  <div v-else-if="$slots.end" class="relative">
    <ShadcnInput
      v-model="model"
      v-bind="{ ...attrs, ...props }"
      class="pr-14"
    />
    <div
      class="pointer-events-none absolute inset-y-0 right-2 flex items-center"
    >
      <slot name="end" />
    </div>
  </div>
  <ShadcnInput v-else v-model="model" v-bind="{ ...attrs, ...props }" />
</template>
