import uniqueId from 'lodash/uniqueId';
import isBoolean from 'lodash/isBoolean';
import { looseEqual } from '../../../../vendor/bootstrap-vue/src/utils/loose-equal';
import { looseIndexOf } from '../../../../vendor/bootstrap-vue/src/utils/loose-index-of';
import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';

var script = {
  name: 'GlFormCheckbox',
  inject: {
    getGroup: {
      // When we remove BFormCheckboxGroup from GlFormCheckboxGroup, we can rename
      // the `getBvCheckGroup` provide to `getCheckGroup`.
      from: 'getBvCheckGroup',
      default: () => () => null
    }
  },
  inheritAttrs: false,
  model: {
    prop: 'checked',
    event: 'input'
  },
  props: {
    /**
     * Used to set the `id` attribute on the rendered content, and used as the base to generate any additional element IDs as needed.
     */
    id: {
      type: String,
      required: false,
      default: undefined
    },
    /**
     * The current value of the checkbox(es). Must be an array when there are multiple checkboxes bound to the same v-model.
     */
    checked: {
      type: undefined,
      required: false,
      default: null
    },
    /**
     * When set to `true`, disables the component's functionality and places it in a disabled state.
     */
    disabled: {
      type: Boolean,
      required: false,
      default: false
    },
    /**
     * Sets the value of the `name` attribute on the form control.
     */
    name: {
      type: String,
      required: false,
      default: undefined
    },
    /**
     * Adds the `required` attribute to the form control.
     */
    required: {
      type: Boolean,
      required: false,
      default: false
    },
    /**
     * Controls the validation state appearance of the component. `true` for valid, `false` for invalid, or `null` for no validation state.
     */
    state: {
      type: Boolean,
      required: false,
      default: null
    },
    /**
     * Sets the value of `aria-label` attribute on the rendered element.
     */
    ariaLabel: {
      type: String,
      required: false,
      default: undefined
    },
    /**
     * The ID of the element that provides a label for this component. Used as the value for the `aria-labelledby` attribute.
     */
    ariaLabelledby: {
      type: String,
      required: false,
      default: undefined
    },
    /**
     * Renders the checkbox in an indeterminate state. Syncable via the .sync modifier.
     */
    indeterminate: {
      type: Boolean,
      required: false,
      default: false
    },
    /**
     * Value returned when this checkbox is checked.
     */
    value: {
      type: [Array, Boolean, String],
      required: false,
      default: true
    },
    /**
     * Value returned when this checkbox is unchecked. Note not applicable when multiple checkboxes bound to the same v-model array.
     */
    uncheckedValue: {
      type: [Array, Boolean, String],
      required: false,
      default: false
    }
  },
  data() {
    const group = this.getGroup();
    return {
      internalId: this.id ? this.id : uniqueId('gitlab_ui_checkbox_'),
      localChecked: group ? group.checked : this.checked
    };
  },
  computed: {
    computedLocalChecked: {
      get() {
        return this.isGroup ? this.group.localChecked : this.localChecked;
      },
      set(value) {
        if (this.isGroup) {
          this.group.localChecked = value;
        } else {
          this.localChecked = value;
        }
      }
    },
    group() {
      return this.getGroup();
    },
    isGroup() {
      // Is this check a child of check-group?
      return Boolean(this.group);
    },
    computedState() {
      if (this.isGroup) return this.group.computedState;
      return isBoolean(this.state) ? this.state : null;
    },
    stateClass() {
      if (this.computedState === true) return 'is-valid';
      if (this.computedState === false) return 'is-invalid';
      return null;
    },
    computedAriaInvalid() {
      return this.computedState === false ? 'true' : null;
    },
    isChecked() {
      const {
        value,
        computedLocalChecked: checked
      } = this;
      return Array.isArray(checked) ? looseIndexOf(checked, value) > -1 : looseEqual(checked, value);
    },
    isDisabled() {
      // Child can be disabled while parent isn't, but is always disabled if group is
      return this.isGroup ? this.group.disabled || this.disabled : this.disabled;
    },
    isRequired() {
      // Required only works when a name is provided for the input(s)
      // Child can only be required when parent is
      // Groups will always have a name (either user supplied or auto generated)
      return this.computedName && (this.isGroup ? this.group.required : this.required);
    },
    computedName() {
      // Group name preferred over local name
      return (this.isGroup ? this.group.groupName : this.name) || null;
    },
    computedAttrs() {
      const {
        isDisabled: disabled,
        isRequired: required,
        value,
        isChecked: checked
      } = this;
      return {
        ...this.$attrs,
        id: this.internalId,
        name: this.computedName,
        disabled,
        required,
        value,
        checked,
        'aria-required': required || null,
        'aria-invalid': this.computedAriaInvalid,
        'aria-label': this.ariaLabel || null,
        'aria-labelledby': this.ariaLabelledby || null
      };
    }
  },
  watch: {
    checked() {
      this.checkedWatcher(...arguments);
    },
    indeterminate(newValue, oldValue) {
      if (!looseEqual(newValue, oldValue)) {
        this.setIndeterminate(newValue);
      }
    },
    computedLocalChecked() {
      this.computedLocalCheckedWatcher(...arguments);
    }
  },
  mounted() {
    // Set initial indeterminate state
    this.setIndeterminate(this.indeterminate);
  },
  methods: {
    checkedWatcher(newValue) {
      if (!looseEqual(newValue, this.computedLocalChecked)) {
        this.computedLocalChecked = newValue;
      }
    },
    computedLocalCheckedWatcher(newValue, oldValue) {
      if (!looseEqual(newValue, oldValue)) {
        this.$emit('input', newValue);
        const {
          input
        } = this.$refs;
        if (input) {
          this.$emit('update:indeterminate', input.indeterminate);
        }
      }
    },
    handleChange(_ref) {
      let {
        target: {
          checked,
          indeterminate
        }
      } = _ref;
      const {
        value,
        uncheckedValue
      } = this;

      // Update `computedLocalChecked`
      let localChecked = this.computedLocalChecked;
      if (Array.isArray(localChecked)) {
        const index = looseIndexOf(localChecked, value);
        if (checked && index < 0) {
          // Add value to array
          localChecked = localChecked.concat(value);
        } else if (!checked && index > -1) {
          // Remove value from array
          localChecked = localChecked.slice(0, index).concat(localChecked.slice(index + 1));
        }
      } else {
        localChecked = checked ? value : uncheckedValue;
      }
      this.computedLocalChecked = localChecked;

      // Fire events in a `$nextTick()` to ensure the `v-model` is updated
      this.$nextTick(() => {
        // Change is only emitted on user interaction
        this.$emit('change', localChecked);

        // If this is a child of a group, we emit a change event on it as well
        if (this.isGroup) {
          this.group.$emit('change', localChecked);
        }
        this.$emit('indeterminate', indeterminate);
      });
    },
    setIndeterminate(state) {
      // Indeterminate only supported in single checkbox mode
      const computedState = Array.isArray(this.computedLocalChecked) ? false : state;
      const {
        input
      } = this.$refs;
      if (input) {
        input.indeterminate = computedState;
        // Emit update event to prop
        this.$emit('update:indeterminate', computedState);
      }
    },
    focus() {
      if (!this.disabled) {
        var _this$$refs$input;
        (_this$$refs$input = this.$refs.input) === null || _this$$refs$input === void 0 ? void 0 : _this$$refs$input.focus();
      }
    },
    blur() {
      if (!this.disabled) {
        var _this$$refs$input2;
        (_this$$refs$input2 = this.$refs.input) === null || _this$$refs$input2 === void 0 ? void 0 : _this$$refs$input2.blur();
      }
    }
  }
};

/* script */
const __vue_script__ = script;

/* template */
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"gl-form-checkbox custom-checkbox custom-control"},[_c('input',_vm._b({key:"input",ref:"input",staticClass:"custom-control-input",class:_vm.stateClass,attrs:{"type":"checkbox"},on:{"change":_vm.handleChange}},'input',_vm.computedAttrs,false)),_vm._v(" "),_c('label',{staticClass:"custom-control-label",attrs:{"for":_vm.internalId}},[_vm._t("default"),_vm._v(" "),(Boolean(_vm.$scopedSlots.help))?_c('p',{staticClass:"help-text"},[_vm._t("help")],2):_vm._e()],2)])};
var __vue_staticRenderFns__ = [];

  /* style */
  const __vue_inject_styles__ = undefined;
  /* scoped */
  const __vue_scope_id__ = undefined;
  /* module identifier */
  const __vue_module_identifier__ = undefined;
  /* functional template */
  const __vue_is_functional_template__ = false;
  /* style inject */
  
  /* style inject SSR */
  
  /* style inject shadow dom */
  

  
  const __vue_component__ = /*#__PURE__*/__vue_normalize__(
    { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ },
    __vue_inject_styles__,
    __vue_script__,
    __vue_scope_id__,
    __vue_is_functional_template__,
    __vue_module_identifier__,
    false,
    undefined,
    undefined,
    undefined
  );

export { __vue_component__ as default };
