<template>
  <label
    :class="{
      'tao-checkbox--disabled cursor-not-allowed opacity-high-min': disabled
    }"
    class="tao-checkbox mx-1-2 p-1 inline-block inline-flex
    align-center user-select-none cursor-pointer">
    <input
      :value="value"
      :true-value="trueValue"
      :false-value="falseValue"
      :checked="isChecked"
      :disabled="disabled"
      v-on="listeners"
      :class="{
        'text-brand-darker': isChecked || indeterminate,
        'text-02': !isChecked && !indeterminate,
        'cursor-not-allowed': disabled,
      }"
      type="checkbox"
      class="tao-checkbox__input bg-white rounded w-2 h-2 cursor-pointer">
    <span
      v-show="hasLabel"
      :class="{
        'text-brand-darker': isChecked,
        'text-02': !isChecked
      }"
      class="tao-checkbox__label inline-block ml-1 font-medium">
      <slot>{{ value }}</slot>
    </span>
  </label>
</template>

<script>
// @flow
import { isArray, isEqual } from 'utils';

function hasValue(array, item) {
  return JSON.stringify(array).includes(JSON.stringify(item));
}

export default {
  name: 'TaoCheckbox',
  model: {
    prop: 'checked',
    event: 'change',
  },
  props: {
    checked: {}, // eslint-disable-line
    value: {}, // eslint-disable-line
    trueValue: { // eslint-disable-line
      default: true,
    },
    falseValue: { // eslint-disable-line
      default: false,
    },
    indeterminate: {
      type: Boolean,
      default: false,
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    label: {
      type: String,
      default: null,
    },
    hasLabel: {
      type: Boolean,
      default: true,
    },
  },
  computed: {
    listeners() {
      return {
        ...this.$listeners,
        change: this.onChange,
      };
    },
    isMultiple() {
      return isArray(this.checked);
    },
    isChecked() {
      if (this.isMultiple) {
        return hasValue(this.checked, this.value);
      }
      return this.trueValue === this.checked;
    },
    checkedIndex() {
      if (this.isMultiple) {
        return this.checked.findIndex(item => isEqual(item, this.value));
      }
      return -1;
    },
    input() {
      return this.$el.querySelector('input');
    },
  },
  mounted() {
    this.$watch('indeterminate', (value) => {
      this.input.indeterminate = value;
    }, { immediate: true });
  },
  methods: {
    onChange() {
      if (this.disabled) return;

      if (this.isMultiple) {
        const checked = [...this.checked];

        if (this.isChecked) {
          checked.splice(this.checkedIndex, 1);
        } else {
          checked.push(this.value);
        }
        this.$emit('change', checked);
      } else {
        this.$emit('change', this.checked ? this.falseValue : this.trueValue);
      }
    },
  },
};
</script>
