<template>
  <div
    class="vc-form-check text-sm"
    data-test="checkbox"
    :class="[{ disabled }, checkboxClass ? checkboxClass : 'pl-0']"
    @keydown.space.prevent
  >
    <label
      class="vc-form-check-label cursor-pointer inline-flex relative select-none mb-0"
      :for="labelId"
      :tabindex="disabled ? -1 : 0"
      @keyup.stop.prevent="changeChecked"
      @click.prevent="changeModel"
    >
      <input
        :id="labelId"
        v-model="model"
        class="vc-form-check-input"
        tabindex="-1"
        type="checkbox"
        :class="{ indeterminate }"
        :data-test="`checkbox-${dataTestName}`"
        :disabled="disabled"
      >
      <span
        class="vc-form-check-sign"
        :class="{ 'vc-icon-checkmark-solid text-white': model && !indeterminate, indeterminate, 'vc-icon-minus-solid': indeterminate }"
      />
      <span
        v-if="$slots.default || label"
        class="vc-form-check-label-text"
      >
        <slot>
          <div
            class="vc-checkbox-label"
            :class="checkboxLabelClass || CHECKBOX_DEFAULT_LABEL_CLASS"
          >
            <div class="text-overflow">
              {{ label }}
            </div>
          </div>
        </slot>
      </span>
    </label>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

const CHECKBOX_DEFAULT_LABEL_CLASS = 'vc-checkbox-default-label'

export default defineComponent({
  name: 'VcCheckbox',
  model: {
    prop: 'checked'
  },
  props: {
    checked: {
      type: Boolean,
      default: false
    },
    indeterminate: {
      type: Boolean,
      default: false
    },
    disabled: {
      type: Boolean,
      default: false
    },
    checkboxClass: {
      type: String,
      default: ''
    },
    label: {
      type: String,
      default: '',
      description: 'Checkbox label'
    },
    checkboxLabelClass: {
      type: String,
      default: ''
    },
    handUpdate: {
      type: Boolean,
      default: false
    },
    dataTestName: {
      type: String,
      default: 'default'
    },
    onInput: {
      type: Function,
      default: null,
      description: 'Temporary @input method'
    }
  },
  emits: ['input', 'update:checked', 'changed'],
  data () {
    return {
      labelId: '',
      model: false,
      CHECKBOX_DEFAULT_LABEL_CLASS
    }
  },
  watch: {
    checked: {
      handler (newV: boolean) {
        this.model = newV
      },
      immediate: true
    },
    model (newV: boolean) {
      if (this.handUpdate) {
        return
      }
      this.update(newV)
    }
  },
  created () {
    this.labelId = Math.random()
      .toString(16)
      .slice(2)
  },
  methods: {
    changeModel (): void {
      if (this.disabled) {
        return
      }
      if (this.handUpdate) {
        this.update(this.model)
      } else {
        this.model = !this.model
      }
    },
    changeChecked (e: KeyboardEvent): void {
      if (e.key === '32' || e.keyCode === 32) {
        this.changeModel()
      }
    },
    update (value: boolean): void {
      if (this.$attrs && this.$attrs.onInput) {
        this.$emit('input', value)
      } else if (this.onInput && typeof this.onInput === 'function') {
        this.onInput(value)
      } else {
        this.$emit('update:checked', value)
      }
      this.$emit('changed', value)
    }
  }
})
</script>

<style lang="scss" scoped>
.vc-form-check {
  line-height: 1rem;
  @apply py-1 min-h-6.5;

  &.disabled .vc-form-check-label {
    @apply text-default-text cursor-not-allowed opacity-50 outline-none;
  }

  .vc-form-check-label {
    @apply text-default-text pl-0 pr-0 h-5 items-center outline-none;
  }

  .vc-checkbox-label {
    @apply inline-flex;

    &.vc-checkbox-default-label {
      @apply text-left font-normal;
    }
  }

  .vc-form-check-label-text {
    @apply inline-flex ml-3;
  }

  .vc-form-check-sign {
    width: 18px;
    height: 18px;
    @apply border-2 rounded-sm border-inactive-elements inline-block relative transition-all duration-300 ease-in;
  }

  .vc-form-check-sign::before {
    transform: translateX(-50%) translateY(-50%);
    @apply absolute left-2/4 top-2/4 origin-center text-white;
  }

  input[type="checkbox"]:not(:checked):not(.indeterminate) {
    ~ .vc-form-check-sign::before {
      content: '';
    }
  }

  input[type="checkbox"]:checked,
  input[type="checkbox"].indeterminate {
    + .vc-form-check-sign {
      @apply border-none bg-active-elements;
    }

    &:hover {
      + .vc-form-check-sign {
        @apply bg-active-elements--focus;
      }

      &:focus {
        + .vc-form-check-sign {
          @apply bg-active-elements--pressed;
        }
      }
    }

    + .vc-form-check-sign {
      @apply opacity-100 mt-0;
    }
  }

  input[type="checkbox"]:not([disabled]):hover + .vc-form-check-sign {
    @apply border-2 border-active-elements--focus shadow-hover;
  }

  input[type="checkbox"]:not([disabled]):hover:focus + .vc-form-check-sign {
    @apply border-2 border-active-elements--pressed shadow-focus;
  }

  input[type="checkbox"] {
    z-index: unset;
    @apply pointer-events-none absolute opacity-0 outline-none m-0 w-0 h-0;
  }

  .vc-form-check-label {
    &:focus-visible .vc-form-check-sign {
      @apply shadow-hover-outer;
    }
  }
}

[dir="rtl"] {
  .vc-form-check {
    .vc-form-check-label {
      @apply pl-0 pr-0;
    }

    .vc-form-check-label-text {
      @apply ml-0 mr-3;
    }
  }
}
</style>
