<template>
  <div class="ivyforms-file-upload ivyforms-width-100" :class="`ivyforms-file-upload--${tone}`">
    <input
      :id="inputId"
      ref="inputRef"
      type="file"
      class="ivyforms-file-upload__input"
      :disabled="disabled"
      :multiple="multiple"
      :accept="accept"
      tabindex="-1"
      @change="onChange"
    />
    <div
      v-if="variant === 'dropzone'"
      :class="[
        'ivyforms-file-upload__dropzone ivyforms-flex ivyforms-flex-direction-column ivyforms-justify-content-center ivyforms-align-items-center ivyforms-align-self-stretch ivyforms-py-16 ivyforms-px-20',
        {
          'ivyforms-file-upload__dropzone--drag': isDragging,
          'ivyforms-file-upload__dropzone--disabled': disabled,
        },
      ]"
      role="button"
      :tabindex="disabled ? -1 : 0"
      :aria-disabled="disabled ? 'true' : 'false'"
      :aria-label="textContent.ariaLabel"
      :aria-describedby="hintText ? hintId : undefined"
      @dragenter.prevent="onDragEnter"
      @dragleave.prevent="onDragLeave"
      @dragover.prevent="onDragOver"
      @drop.prevent="onDrop"
      @click="open"
      @keydown.enter.prevent="open"
      @keydown.space.prevent="open"
    >
      <div
        class="ivyforms-file-upload__dropzone-inner ivyforms-flex ivyforms-flex-direction-column ivyforms-align-items-center ivyforms-justify-content-center ivyforms-gap-8 ivyforms-width-100"
        aria-hidden="true"
      >
        <div
          class="ivyforms-file-upload__dropzone-art ivyforms-flex ivyforms-align-items-center ivyforms-justify-content-center"
        >
          <IvyIcon
            name="cloud-upload"
            category="global"
            type="fill"
            size="d"
            outer-size="72px"
            color="var(--map-base-dusk-symbol-2, #394452)"
          />
        </div>
        <p class="ivyforms-file-upload__dropzone-text">
          <template v-if="textContent.split">
            <span class="ivyforms-file-upload__dropzone-muted">{{ textContent.muted }}</span
            ><span class="ivyforms-file-upload__dropzone-link">{{ textContent.accent }}</span>
          </template>
          <template v-else>
            <span class="ivyforms-file-upload__dropzone-single">{{ textContent.single }}</span>
          </template>
        </p>
      </div>
    </div>
    <div v-else class="ivyforms-file-upload__button ivyforms-flex ivyforms-align-items-start">
      <IvyButtonAction
        type="border"
        priority="tertiary"
        :disabled="disabled"
        :aria-label="chooseLabel"
        @click="open"
      >
        {{ chooseLabel }}
      </IvyButtonAction>
    </div>
    <p v-if="hintText" :id="hintId" class="ivyforms-file-upload__hint ivyforms-mt-8">
      {{ hintText }}
    </p>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, useId } from 'vue'
import IvyButtonAction from '@/views/_components/button/IvyButtonAction.vue'

/** First `|` splits muted (left) and accent (right); pipe is not shown. */
const PLACEHOLDER_SPLIT_CHAR = '|'

type DropzoneTextContent = {
  split: boolean
  muted: string
  accent: string
  single: string
  ariaLabel: string
}

const props = withDefaults(
  defineProps<{
    variant?: 'dropzone' | 'button'
    /** `neutral` for public forms; `brand` for form-builder chrome. */
    tone?: 'neutral' | 'brand'
    disabled?: boolean
    multiple?: boolean
    accept?: string
    hintText?: string
    dragPrefix?: string
    clickPhrase?: string
    chooseLabel?: string
  }>(),
  {
    variant: 'dropzone',
    tone: 'neutral',
    disabled: false,
    multiple: false,
    accept: '',
    hintText: '',
    dragPrefix: '',
    clickPhrase: '',
    chooseLabel: '',
  },
)

const emit = defineEmits<{
  'files-selected': [files: FileList | null]
}>()

const inputRef = ref<HTMLInputElement | null>(null)
const isDragging = ref(false)
const dragDepth = ref(0)
const vueId = useId()
const inputId = `ivyforms-fu-in-${vueId}`
const hintId = `ivyforms-fu-hint-${vueId}`

const dragPrefix = computed(() => props.dragPrefix.trim())
const clickPhrase = computed(() => props.clickPhrase.trim())
const hintText = computed(() => props.hintText.trim())

const textContent = computed((): DropzoneTextContent => {
  const prefix = dragPrefix.value
  const phrase = clickPhrase.value
  const hint = hintText.value
  const singleLine = prefix.replace(/\|/g, ' ').replace(/\s+/g, ' ').trim()

  const withHint = (main: string) => (hint ? `${main}. ${hint}` : main)

  if (phrase !== '') {
    const main = [prefix, phrase].filter(Boolean).join(' ')
    return {
      split: true,
      muted: prefix,
      accent: phrase,
      single: '',
      ariaLabel: withHint(main),
    }
  }

  const pipeIdx = prefix.indexOf(PLACEHOLDER_SPLIT_CHAR)
  if (pipeIdx !== -1) {
    const muted = prefix.slice(0, pipeIdx).trim()
    const accent = prefix.slice(pipeIdx + PLACEHOLDER_SPLIT_CHAR.length).trim()
    if (accent !== '') {
      const main = `${muted} ${accent}`.trim()
      return {
        split: true,
        muted,
        accent,
        single: '',
        ariaLabel: withHint(main),
      }
    }
  }

  return {
    split: false,
    muted: '',
    accent: '',
    single: singleLine,
    ariaLabel: withHint(singleLine),
  }
})

function open() {
  if (props.disabled) return
  inputRef.value?.click()
}

function onChange(ev: Event) {
  const t = ev.target as HTMLInputElement
  emit('files-selected', t.files)
  t.value = ''
}

function onDragEnter() {
  if (props.disabled || props.variant !== 'dropzone') return
  dragDepth.value++
  isDragging.value = true
}

function onDragLeave() {
  if (props.disabled || props.variant !== 'dropzone') return
  dragDepth.value = Math.max(0, dragDepth.value - 1)
  if (dragDepth.value === 0) isDragging.value = false
}

function onDragOver() {
  if (props.disabled || props.variant !== 'dropzone') return
  isDragging.value = true
}

function onDrop(ev: DragEvent) {
  dragDepth.value = 0
  isDragging.value = false
  if (props.disabled || props.variant !== 'dropzone') return
  emit('files-selected', ev.dataTransfer?.files ?? null)
}
</script>

<style scoped lang="scss">
.ivyforms-file-upload {
  position: relative;

  &__input {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }

  &__dropzone {
    position: relative;
    box-sizing: border-box;
    height: 200px;
    border-radius: 4px;
    border: 1px dashed var(--map-base-dusk-stroke--2, #c5cad1);
    background: var(--map-ground-level-2-foreground, var(--map-ground-level-1-background, #fff));
    cursor: pointer;
    outline: none;
    transition:
      border-color 0.15s ease,
      background 0.15s ease;

    &:hover:not(&--disabled),
    &:focus-visible {
      border-color: var(--map-base-dusk-stroke-0, #9ca3af);
      box-shadow: 0 0 0 2px rgba(107, 114, 128, 0.12);
    }

    &--drag {
      border-color: var(--map-base-dusk-stroke-0, #9ca3af);
      background: var(--map-ground-level-2-background, #f3f4f6);
    }

    &--disabled {
      opacity: 0.5;
      cursor: not-allowed;
    }

    &-inner {
      min-height: 0;
      text-align: center;
    }

    &-art {
      --ivyforms-dropzone-icon-size: 72px;

      :deep(.ivyforms-icon) {
        width: var(--ivyforms-dropzone-icon-size);
        height: var(--ivyforms-dropzone-icon-size);
        flex-shrink: 0;
      }

      :deep(.ivyforms-icon__svg) {
        width: 68px !important;
        height: 68px !important;
        display: flex;
        align-items: center;
        justify-content: center;
      }

      :deep(.ivyforms-icon__svg svg) {
        display: block;
        width: 68px !important;
        height: 68px !important;
        max-width: 100%;
        max-height: 100%;
        box-sizing: border-box;
      }
    }

    &-text {
      margin: 0;
      font-size: 14px;
      line-height: 22px;
    }

    &-muted {
      color: var(--map-base-dusk-symbol-1, #6b7280);
    }

    &-link {
      &::before {
        content: '\0020';
        white-space: pre;
      }
      color: var(--map-base-dusk-symbol-2, #394452);
      font-weight: 500;
    }

    &-single {
      color: var(--map-base-dusk-symbol-1, #6b7280);
    }
  }

  &__hint {
    font-size: 12px;
    line-height: 18px;
    color: var(--map-base-dusk-symbol-1, #6b7280);
  }

  &--brand &__dropzone {
    &:hover:not(&--disabled),
    &:focus-visible {
      border-color: var(--map-base-brand-stroke-0, #6366f1);
      box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.15);
    }

    &--drag {
      border-color: var(--map-base-brand-stroke-0, #6366f1);
      background: var(--map-base-brand-fill--4, #eef2ff);
    }
  }

  &--brand &__dropzone-link {
    color: var(--map-base-purple-symbol-0, #4f46e5);
  }
}
</style>
