<template>
  <div :class="classes" ref="parentElement">
    <div class="field__wrapper">
      <span class="field__label">
        <span
          class="field__label__title"
          :class="{ ellipsis: ellipsisLabel }"
          :title="ellipsisLabel ? label : undefined"
        >
          {{ label }}
        </span>

        <span v-if="required" class="field__label-required">*</span>
        <span v-if="optional && !required" class="field__label-optional">
          (Optionnel)
        </span>
        <BmsTooltip v-if="helperText" :tooltipText="helperText">
          <span class="field__label-helper--icon">
            <HelpCircle />
          </span>
        </BmsTooltip>
      </span>

      <span class="field__input">
        <SkeletonField v-if="loading" />
        <slot v-else></slot>
      </span>
      <span ref="datalist">
        <span class="field__datalist" :class="{ top: openTop }">
          <slot name="datalist"></slot>
        </span>
      </span>
    </div>

    <div v-if="captions?.length || errors?.length" class="field__captions">
      <div
        v-if="captions?.length"
        v-for="caption in captions"
        :key="getCaptionIdentifier(caption)"
        class="information field__caption"
      >
        <BmsCaption :caption="caption" />
      </div>
      <div
        v-if="errors?.length"
        v-for="error in computedErrors"
        :key="error.label"
        class="field__error"
      >
        <BmsCaption :caption="error" />
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { computed, ComputedRef, onMounted, ref, Ref } from 'vue';
import { HelpCircle } from 'lucide-vue-next';
import { BmsTooltip, convertStringToCaption, StatusType } from '@/index';
import { useElementBounding } from '@vueuse/core';
import { Caption } from '@/models/caption.model';
import BmsCaption from '@/components/feedback/BmsCaption.vue';
import { FieldComponentProps } from './field-component.model';
import SkeletonField from './SkeletonField.vue';

const props = withDefaults(defineProps<FieldComponentProps>(), {
  label: '',
  optional: false,
  small: false,
  loading: false,
  ellipsisLabel: false,
});

const datalist: Ref<HTMLSpanElement | null> = ref<HTMLSpanElement | null>(null);

const { y } = useElementBounding(datalist);
const parentElement = ref<HTMLElement | null>(null);

function getScrollParentBottom(element: HTMLElement | null): number {
  if (
    !element ||
    element === document.documentElement ||
    element === document.body
  ) {
    return window.innerHeight;
  }
  const { overflow, overflowY } = window.getComputedStyle(element);
  if (/(auto|scroll|hidden)/.test(overflow + overflowY)) {
    return element.getBoundingClientRect().bottom;
  }
  return getScrollParentBottom(element.parentElement);
}

const classes = computed(() => {
  return {
    field: true,
    'is-error': props.errors?.length,
    'is-disabled': props.disabled,
    'is-small': props.small,
  };
});

const computedErrors: ComputedRef<Caption[]> = computed(() => {
  return !props.errors
    ? []
    : props.errors.map((e) => {
        return {
          ...convertStringToCaption(e),
          mode: StatusType.Danger,
        };
      });
});
const datalistHeight: Ref<number | null> = ref<number | null>(null);

// not a computed for ResizeObserver problem in cypress
const setDataListHeight = () => {
  const defaultDataListHeight = 150;
  const datalistContent: Ref<HTMLElement | null> = ref<HTMLElement | null>(
    datalist.value?.firstChild as HTMLElement,
  );
  const { height } = useElementBounding(datalistContent);
  datalistHeight.value =
    height.value !== 0 ? height.value : defaultDataListHeight;
};

onMounted(() => {
  setDataListHeight();
});

const openTop = computed(() => {
  if (!datalist.value) {
    return false;
  }
  const containerBottom = getScrollParentBottom(datalist.value.parentElement);
  return y.value + (datalistHeight.value ?? 0) > containerBottom;
});

const getCaptionIdentifier = (caption: string | Caption): string => {
  return convertStringToCaption(caption).label;
};
</script>

<style lang="scss">
.field {
  --field-border-color: light-dark(var(--bms-grey-50), var(--bms-grey-100));
  --field-border-color-active: var(--bms-main-100);
  --input-background-color: var(--bms-white);
  --field-label-color: var(--bms-font-color);
  background: transparent;

  --field-height: 48px;
  --field-padding: 1em;
  --field-margin: 0.5em 0;
  --field-label-font-weight: bold;
  --field-datalist-bottom: calc(var(--field-height) + 1em);

  &__errors {
    font-size: 14px;
    color: var(--bms-red-75);
    margin-bottom: var(--field-margin);
  }

  &__captions {
    margin-bottom: var(--field-margin);
  }

  &__wrapper {
    display: inline-block;
    position: relative;
    width: 100%;
    background-color: transparent;
  }

  &__label {
    display: flex;
    align-items: center;

    &__title {
      display: inline-block;
      white-space: nowrap;

      font-size: 1em;
      font-weight: var(--field-label-font-weight);
      color: var(--field-label-color);

      &.ellipsis {
        overflow: hidden;
        text-overflow: ellipsis;
      }
    }

    &-helper--icon {
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      margin-left: 0.5em;

      width: 1em;
      height: 1em;
    }

    &-required {
      color: var(--bms-red-100);
    }

    &-optional {
      font-style: italic;
      font-size: 14px;
      color: var(--bms-grey-75);
    }

    &:empty {
      display: none;
    }
  }

  &.is-small {
    --field-height: 1.5em;
    --field-padding: 0.5em;
    --field-margin: 0;
    --field-label-font-weight: normal;

    .field__captions {
      margin-top: 0.5rem;
    }
  }

  &.is-error {
    --field-label-color: var(--bms-danger-color);
  }

  &.is-disabled {
    --field-label-color: light-dark(var(--bms-grey-50), var(--bms-grey-75));
  }

  &__datalist {
    position: absolute;
    display: block;
    padding: 0;
    margin: 0;
    background: var(--bms-white);
    width: 100%;
    z-index: var(--bms-z-index-tooltip);
    max-height: 300px;
    overflow-y: auto;

    &.top {
      bottom: var(--field-datalist-bottom);
    }
  }

  &__input {
    display: flex;
    align-items: center;
    margin: var(--field-margin);
  }
}
</style>
