<template>
  <div
    class="l-select-container"
    :class="[
      'l-select-container--' + state,
      'size--' + size,
      focused ? 'l-select-container--focused' : '',
      { 'l-select-container--disabled': disabled }
    ]"
    :style="{
      '--input-bg': inputBG,
      '--input-border': inputBorder,
      '--input-text': inputText,
      '--input-opacity': inputOpacity,
      '--input-hover': inputHover,
      '--input-hover-text': inputFocusText,
      '--input-size': inputSize,
    }"
  >
    <multiselect
      ref="select"
      class="l-select"
      :class="{ 'l-select--with-label': showLabel }"
      :value="inputValue"
      :multiple="multiple"
      :track-by="trackBy"
      :custom-label="customLabel"
      :searchable="true"
      :show-labels="false"
      :taggable="taggable"
      :internal-search="internalSearch"
      :tag-placeholder="tagPlaceholder"
      :group-label="groupLabel"
      :group-values="groupValues"
      :group-select="groupSelect"
      open-direction="bottom"
      v-bind="$props"
      @input="update"
      @open="open"
      @close="close"
      @search-change="searchChange"
      @select="select"
      @remove="remove"
      @tag="tag"
    >
      <template
        slot="option"
        slot-scope="props"
      >
        <slot
          :option="props.option"
          name="option"
        />
      </template>
      <template
        slot="singleLabel"
        slot-scope="props"
      >
        <slot
          :option="props.option"
          name="singleLabel"
        />
      </template>
      <template
        v-if="groupLabel"
        slot="optionGroupLabel"
        slot-scope="props"
      >
        <slot
          :group="props"
          name="optionGroupLabel"
        >
          {{ props[groupLabel] }}
        </slot>
      </template>
    </multiselect>
    <div
      v-if="disabled"
      class="l-select-lock"
    >
      <l-icon
        type="neutral"
        shade="900"
        label="locked"
        view-box="0 0 17 16"
      >
        <icon-lock-light />
      </l-icon>
    </div>
    <span
      v-if="showLabel"
      class="l-select-label"
      :class="
        focused || value || placeholder
          ? 'l-select-label--outside'
          : 'l-select-label--inside'
      "
    >
      {{ title }}
    </span>
    <span
      v-if="note"
      :id="selectNoteId"
      class="l-select-note"
    >
      {{ note }}
    </span>
  </div>
</template>

<script>
import Multiselect from "vue-multiselect";
import LIcon from "./LIcon.vue";
import IconLockLight from "../../icons/icon-lock-light.vue";

export default {
  name: "LSelect",
  components: {
    Multiselect,
    LIcon,
    IconLockLight
  },
  props: {
    /**
     * The title of the select - similar to lable on input component.
     */
    title: {
      type: String,
    },
    /**
     * String to show when highlighting a potential tag.
     */
    tagPlaceholder: {
      type: String,
      default: "Press enter to create",
    },
    /**
     * Disable / Enable tagging.
     */
    taggable: {
      type: Boolean,
      required: true,
    },
    /**
     * Boolean whether label should be displayed or not. Default true.
     */
    showLabel: {
      type: Boolean,
      default: true,
    },
    /**
     * Function used to create a custom label.
     */
    customLabel: {
      type: Function,
    },
    /**
     * Used to compare objects. Only use if options are objects.
     */
    trackBy: {
      type: [String, Number],
      default: "",
    },
    /**
     * An array of strings or objects to be used as dropdown choices. If you are using an array of objects, l-select will look for a label key (ex. [{label: 'Canada', value: 'CA'}]). A custom label key can be set with the label prop.
     */
    options: {
      type: Array,
      default: () => [],
    },
    /**
     * The note of the form select field, it could be a hint, error or success message.
     */
    note: {
      type: String,
      default: "",
    },
    /**
     * The size of the select.
     */
    size: {
      type: String,
      default: "large",
      validator: function (value) {
        return ["small", "medium", "large"].indexOf(value) !== -1;
      },
    },
    /**
     * The colour/state of the select.
     */
    state: {
      type: String,
      default: "neutral",
      validator: function (value) {
        return (
          [
            "success",
            "warning",
            "danger",
            "primary",
            "secondary",
            "tertiary",
            "neutral",
            "white",
            "black",
          ].indexOf(value) !== -1
        );
      },
    },
    /**
     * Disable the entire component.
     */
    disabled: {
      type: Boolean,
      default: false,
    },
    /**
     * Tells vue multi-select what key to use when generating option labels when each option is an object.
     */
    label: {
      type: String,
      default: "label",
    },
    /**
     * Show spinner if the component is in a loading state.
     */
    loading: {
      type: Boolean,
      default: false,
    },
    /**
     * Equivalent to the multiple attribute on a <select> input.
     */
    multiple: {
      type: Boolean,
      default: false,
    },
    /**
     * Equivalent to the placeholder attribute on an <input>.
     */
    placeholder: {
      type: String,
      default: "",
    },
    /**
     * Enable/disable filtering the options.
     */
    searchable: {
      type: Boolean,
      default: true,
    },
    /**
     * Contains the currently selected value. Very similar to a value attribute on an <input>. You can listen for changes using the 'input' event.
     */
    value: {
      default: null,
    },
    /**
     * Decide whether to filter the results internally based on search query. Useful for async filtering, where we search through more complex data.
     */
    internalSearch: {
      type: Boolean,
      default: true,
    },
    /**
     * String to identify groups. Used when options are grouped.
     */
    groupLabel: {
      type: String,
      default: "",
    },
    /**
     * String to identify which property contains the group's options. Used when options are grouped.
     */
    groupValues: {
      type: String,
      default: "",
    },
    /**
     * Whether selecting a group label should select/unselect all options in that group. Used when options are grouped.
     */
    groupSelect: {
      type: Boolean,
      default: false,
    },
     /**
     * ID used to identify the select note, useful for testing or tracking purposes
     */
    selectNoteId: {
      type: String,
      equired: false,
      default: ""
    }
  },
  data() {
    return {
      focused: false,
    };
  },
  computed: {
    inputValue: {
      get() {
        return this.value;
      },
      set(value) {
        this.$emit("input", value);
      },
    },
    inputBG() {
      if (this.state === "white" || this.state === "black") {
        return `var(--${this.state})`;
      }
      return `var(--${this.state}-100)`;
    },
    inputHover() {
      if (this.state === "white" || this.state === "black") {
        return `var(--${this.state})`;
      }
      return `var(--${this.state}-100)`;
    },
    inputBorder() {
      if (this.state === "white") {
        return `var(--black)`;
      } else if (this.state === "black") {
        return `var(--white)`;
      }
      return `var(--${this.state}-200)`;
    },
    inputText() {
      if (this.state === "white") {
        return `var(--black)`;
      } else if (this.state === "black") {
        return `var(--white)`;
      }
      return `var(--${this.state}-700)`;
    },
    inputFocusText() {
      if (this.state === "white" || this.state === "black") {
        return `var(--${this.state})`;
      }
      return `var(--${this.state}-800)`;
    },
    inputOpacity() {
      // Don't apply opacity reduction if in danger state
      if (this.state === 'danger') {
        return '1';
      }
      
      // Return lower opacity when there's no value
      if (Array.isArray(this.inputValue)) {
        // For multiple select, check if array is empty
        return this.inputValue.length === 0 ? '0.5' : '1';
      } else if (!this.inputValue && this.inputValue !== 0) {
        // For single select, check if value is falsy (but not 0)
        return '0.5';
      }
      // Return full opacity when there's a value
      return '1';
    },
    inputSize() {
      if (this.size === "small") {
        return `var(--sizing-xs)`;
      } else if (this.size === "large") {
        return `var(--sizing-base)`;
      }
      return `var(--sizing-sm)`;
    },
  },
  mounted() {
    this.$children[0].$el.setAttribute("tabindex", 0);
  },
  methods: {
    update(newValue) {
      /**
       * Triggered when the selected value changes. Used internally for v-model.
       */
      this.$emit("input", newValue);
    },
    open() {
      /**
       * Triggered when the dropdown is open.
       */
      this.$emit("open");
      this.focused = true;
    },
    close() {
      /**
       * Triggered when the dropdown is closed.
       */
      this.$emit("close");
      this.focused = false;
    },
    select(option) {
      /**
       * Emitted after selecting an option.
       */
      this.$emit("select", option);
    },
    remove(option) {
      /**
       * Emitted after removing an option.
       */
      this.$emit("remove", option);
    },
    tag(option) {
      /**
       * Emitted after user attempts to add a tag.
       */
      this.$emit("tag", option);
    },
    searchChange(search) {
      /**
       * 	Emitted after the search query changes.
       */
      this.$emit("search-change", search);
    },
  },
};
</script>

<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

<style>
.l-select-container {
  display: grid;
  grid-template-columns: 1fr;
  font-size: var(--input-size);
  cursor: pointer;
  position: relative;
}
.multiselect--active {
  z-index: var(--layer-1);
}

.l-select-container--disabled {
  cursor: not-allowed;
}
.multiselect__select:before {
  border-color: var(--input-hover-text) transparent transparent;
}
.multiselect__single {
  font-size: inherit;
  background: transparent;
  display: contents;
}
.multiselect__option {
  font-size: inherit;
}
.multiselect__input {
  background: transparent;
  margin-bottom: 0;
  padding: 0;
  opacity: 1;
  cursor: pointer;
  font-weight: 500;
  font-size: inherit;
  width: 93%;
}
.multiselect__input::placeholder {
  color: var(--input-text) !important;
  font-weight: 400 !important;
  opacity: var(--input-opacity, 0.5) !important;
}
.l-select-container--white .multiselect__input::placeholder {
  color: var(--neutral-500) !important;
}
.l-select-container--black .multiselect__input::placeholder {
  color: var(--white) !important;
}
.multiselect__option--highlight {
  background: var(--input-bg);
  color: inherit;
}
.multiselect__option--selected {
  background: var(--input-border);
  color: var(--input-hover-text);
}
.multiselect__option--selected.multiselect__option--highlight {
  background: var(--input-border);
  color: inherit;
}
.multiselect--disabled {
  border-radius: var(--radius-lg);
}
.multiselect__spinner {
  background: var(--input-bg);
}
.multiselect__spinner:before {
  border-color: var(--input-text) transparent transparent;
}
.multiselect__spinner:after {
  border-color: var(--input-text) transparent transparent;
}
.multiselect__tag {
  background: var(--input-border);
  color: inherit;
  margin-bottom: 0;
  opacity: var(--input-opacity);
  display: inline-flex;
  align-items: center;
}
.multiselect__tag-icon:focus,
.multiselect__tag-icon:hover {
  background: transparent;
}
.multiselect__tag-icon:after {
  color: inherit;
}
.multiselect__tags-wrap {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
}
.multiselect__tags {
  opacity: var(--input-opacity);
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  display: flex;
  align-items: center;
  gap: var(--spacing-2);
  padding: var(--spacing-2) var(--spacing-3);
  background-color: var(--input-bg);
  border: 1px solid var(--input-bg);
  color: var(--input-text);
  border-radius: var(--radius-lg);
  font-weight: 500;
  width: 100%;
  caret-color: var(--input-text);
  transition: all var(--duration-100) ease-in-out;
  min-height: var(--input-height, 40px);
}
/* Size classes for select tags/input/option */
.l-select-container.size--small .multiselect__tags {
  padding: var(--spacing-1-5) var(--spacing-3);
  font-size: var(--sizing-xs);
  min-height: var(--input-height-small, 32px);
}
.l-select-container.size--medium .multiselect__tags {
  padding: var(--spacing-2) var(--spacing-3);
  font-size: var(--sizing-sm);
  min-height: var(--input-height, 40px);
}
.l-select-container.size--large .multiselect__tags {
  padding: var(--spacing-2) var(--spacing-3);
  font-size: var(--sizing-base);
  min-height: var(--input-height-large, 48px);
}
.l-select-container.size--small .multiselect__input,
.l-select-container.size--small .multiselect__single,
.l-select-container.size--small .multiselect__option {
  font-size: var(--sizing-xs);
}
.l-select-container.size--small .multiselect__select {
  height: var(--input-height-small, 32px);
}
.l-select-container.size--medium .multiselect__input,
.l-select-container.size--medium .multiselect__single,
.l-select-container.size--medium .multiselect__option {
  font-size: var(--sizing-sm);
}
.l-select-container.size--medium .multiselect__select {
  height: var(--input-height, 40px);
}
.l-select-container.size--large .multiselect__input,
.l-select-container.size--large .multiselect__single,
.l-select-container.size--large .multiselect__option {
  font-size: var(--sizing-base);
}
.l-select-container.size--large .multiselect__select {
  height: var(--input-height-large, 48px);
}
.l-select--with-label {
  margin-top: var(--spacing-6);
}
.l-select-container.size--small .l-select--with-label {
  margin-top: var(--spacing-6);
}
.l-select-container.size--medium .l-select--with-label {
  margin-top: var(--spacing-6);
}
.multiselect__tags:hover {
  background-color: var(--input-hover);
  border-color: var(--input-hover);
}
.multiselect__tags:focus-within {
  background-color: var(--input-hover);
  border-color: var(--input-border);
  color: var(--input-hover-text);
}

.multiselect--disabled .multiselect__select {
  display: none;
}

.l-select-lock {
  position: absolute;
  right: var(--spacing-3);
  top: 50%;
  transform: translateY(-60%);
  pointer-events: none;
}

/* Label */
.l-select-label {
  padding-left: var(--spacing-2-5);
  transition: all var(--duration-150) ease-in-out;
  height: var(--spacing-6);
  line-height: var(--spacing-6);
  max-height: var(--spacing-6);
  color: var(--input-text);
  font-weight: 400;
  width: calc(100% - var(--spacing-8));
  overflow: hidden;
  pointer-events: none;
  position: absolute;
}
.l-select-label--outside {
  font-size: var(--sizing-sm);
}
.l-select-container.size--small .l-select-label--outside {
  font-size: var(--sizing-xs);
}
.l-select-label--inside {
  transform: translateY(calc(100% + var(--spacing-3)));
}
.l-select-container.size--small .l-select-label--inside {
  transform: translateY(calc(100% + var(--spacing-2)));
}
.l-select-container.size--medium .l-select-label--inside {
  transform: translateY(calc(100% + var(--spacing-2-5)));
}
.l-select-container--white .l-select-label {
  color: var(--neutral-500);
}
.l-select-container--black .l-select-label.l-select-label--inside {
  color: var(--white);
}
.l-select-container--black .multiselect__option--highlight {
  color: var(--white);
}
.l-select-container--black
  .multiselect__option--selected.multiselect__option--highlight {
  background: var(--black);
  color: var(--white);
}
.l-select-container--black .multiselect__tag {
  color: var(--black);
}
.l-select-container--black .multiselect__select:before {
  border-color: var(--white) transparent transparent;
}
.l-select-container--white .l-select-label.l-select-label--inside {
  color: var(--black);
}
.l-select-container--white .multiselect__option--highlight {
  background: var(--black);
  color: var(--white);
}
.l-select-container--white
  .multiselect__option--selected.multiselect__option--highlight {
  background: var(--black);
  color: var(--white);
}
.l-select-container--white .multiselect__tag {
  color: var(--white);
}
.l-select-container--white .multiselect__select:before {
  border-color: var(--black) transparent transparent;
}

/* Note */
.l-select-note {
  font-size: var(--sizing-xs);
  padding-left: var(--spacing-2-5);
  color: var(--input-text);
  opacity: 0.75;
  padding-top: var(--spacing-1);
}

.l-select-container--white .l-select-note {
  color: var(--neutral-400);
}

/* Option Groups - group headers are disabled options */
.multiselect__option--disabled {
  font-weight: 700;
  background: transparent;
  color: var(--neutral-700);
  opacity: 1 !important;
  cursor: default;
}

.multiselect__option--disabled:hover {
  background: transparent;
}
</style>
