<template>
  <div :class="{ '_custom-switch': true, 'custom-switch-aside': aside }">
    <label class="block" v-if="!aside && caption" v-html="caption"></label>
    <input 
      type="checkbox" 
      :id="fieldInputId" 
      :switch="switchType"
      :checked="boolValue"
      @change="updateValue"
    />
    <label :for="fieldInputId" :data-on-label="customLabel1" :data-off-label="customLabel2" />
    <span class="caption" v-if="aside && caption" v-html="caption"></span>
    <small class="block text-muted form-group-description" v-if="description">{{ description }}</small>
  </div>
</template>

<script lang="ts">
import { defineComponent, PropType, ref, watch, computed } from 'vue'
import { generateId } from '@/tools/util'

interface SwitchProps {
  modelValue?: boolean
  value?: boolean | number
  switchType?: 'default' | 'bool' | 'primary' | 'success' | 'info' | 'warning' | 'danger' | 'dark' | 'pink' | 'purple' | 'orange' | 'brown' | 'teal' | 'indigo' | 'blue-grey'
  disabled?: boolean
  required?: boolean
  name?: string
  id?: string
  label?: string
  switchAside?: string
  caption?: string
  captionAside?: string
  description?: string
  customLabel1?: string
  customLabel2?: string
}

export default defineComponent({
  name: 'Checkbox',
  props: {
    modelValue: {
      type: Boolean as PropType<boolean>,
      required: false,
      default: undefined
    },
    value: {
      type: [Boolean, Number] as PropType<boolean | number>,
      required: false,
      default: undefined
    },
    switchType: {
      type: String as PropType<SwitchProps['switchType']>,
      default: 'success'
    },
    disabled: {
      type: Boolean as PropType<boolean>,
      default: false
    },
    required: {
      type: Boolean as PropType<boolean>,
      default: false
    },
    id: {
      type: String as PropType<string>,
      default: ''
    },
    caption: {
      type: String as PropType<string>,
      required: false
    },
    captionAside: {
      type: Boolean as PropType<boolean>,
      required: false
    },
    description: {
      type: String as PropType<string>,
      required: false
    },
    customLabel1: {
      type: String as PropType<string>,
      default: ''
    },
    customLabel2: {
      type: String as PropType<string>,
      default: ''
    }
  },
  emits: ['input'],
  setup(props, { emit }) {
    const boolValue = ref(props.modelValue !== undefined ? props.modelValue : Boolean(props.value))
    const fieldInputId = ref(props.id || generateId())

    const updateValue = (event: Event) => {
      const target = event.target as HTMLInputElement
      boolValue.value = target.checked
      emit('input', target.checked)
    }

    watch(() => props.modelValue, (newVal) => {
      if (newVal !== undefined) {
        boolValue.value = newVal
      }
    })

    watch(() => props.value, (newVal) => {
      if (newVal !== undefined) {
        boolValue.value = Boolean(newVal)
      }
    })

    const aside = computed((): boolean => Boolean(props.captionAside))

    return {
      updateValue,
      boolValue,
      aside,
      fieldInputId
    }
  }
})
</script>

<style scoped lang="scss">
label {
  margin-bottom: 0;
}

.custom-switch-aside {
  span.caption {
    display: inline-block;
    position: absolute;
    padding-left: 10px;
  }
}

.block {
  display: block;
}

// Variables
$white: #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #e9ecef !default;
$gray-300: #dee2e6 !default;
$gray-400: #ced4da !default;
$gray-500: #adb5bd !default;
$gray-600: #6c757d !default;
$gray-700: #495057 !default;
$gray-800: #343a40 !default;
$gray-900: #212529 !default;
$black: #000 !default;

$blue: #007bff !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #e83e8c !default;
$red: #dc3545 !default;
$orange: #fd7e14 !default;
$yellow: #ffc107 !default;
$green: #28a745 !default;
$teal: #20c997 !default;
$cyan: #17a2b8 !default;

$lightgray: #dddddd;
$light5: #f5f5f5;
$brown: #8d6e63;
$blue-grey: #90a4ae;

$primary: $blue !default;
$secondary: $gray-600 !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-100 !default;
$dark: $gray-800 !default;

// Switch styles
input[switch] {
  display: none;

  & + label {
    font-size: 1em;
    line-height: 1;
    width: 56px;
    height: 24px;
    background-color: $lightgray;
    background-image: none;
    border-radius: 2rem;
    padding: 0.16667rem;
    cursor: pointer;
    display: inline-block;
    text-align: center;
    position: relative;
    font-weight: 500;
    transition: all 0.1s ease-in-out;

    &:before {
      color: $dark;
      content: attr(data-off-label);
      display: block;
      font-family: inherit;
      font-weight: 500;
      font-size: 12px;
      line-height: 20px;
      position: absolute;
      right: 1px;
      margin: 3px;
      top: 0;
      text-align: center;
      min-width: 1.66667rem;
      overflow: hidden;
      transition: all 0.1s ease-in-out;
    }

    &:after {
      content: '';
      position: absolute;
      left: 3px;
      background-color: $light5;
      box-shadow: none;
      border-radius: 2rem;
      height: 20px;
      width: 20px;
      top: 2px;
      transition: all 0.1s ease-in-out;
    }
  }

  &:checked + label {
    background-color: $primary;

    &:before {
      color: $white;
      content: attr(data-on-label);
      right: auto;
      left: 3px;
    }

    &:after {
      left: 33px;
      background-color: $light5;
    }
  }

  &[switch="bool"] {
    & + label {
      background-color: $danger;
    }

    &:checked + label {
      background-color: $success;
    }
  }

  &[switch="bool"] + label:before,
  &[switch="bool"]:checked + label:before,
  &[switch="default"]:checked + label:before {
    color: $white;
  }

  &[switch="default"]:checked + label {
    background-color: #a2a2a2;
  }

  &[switch="primary"]:checked + label {
    background-color: $primary;
  }

  &[switch="success"]:checked + label {
    background-color: $success;
  }

  &[switch="info"]:checked + label {
    background-color: $info;
  }

  &[switch="warning"]:checked + label {
    background-color: $warning;
  }

  &[switch="danger"]:checked + label {
    background-color: $danger;
  }

  &[switch="dark"]:checked + label {
    background-color: $dark;
  }

  &[switch="pink"]:checked + label {
    background-color: $pink;
  }

  &[switch="purple"]:checked + label {
    background-color: $purple;
  }

  &[switch="orange"]:checked + label {
    background-color: $orange;
  }

  &[switch="brown"]:checked + label {
    background-color: $brown;
  }

  &[switch="teal"]:checked + label {
    background-color: $teal;
  }

  &[switch="indigo"]:checked + label {
    background-color: $indigo;
  }

  &[switch="blue-grey"]:checked + label {
    background-color: $blue-grey;
  }
}
</style>