import { makeComponentProps } from '@/composables/component'
import { makeTagProps } from '@/composables/tag'
import { genericComponent, propsFactory } from '@/utils'
import { ExtractPropTypes } from 'vue'
import { computed, ref } from 'vue'
import { useEventListener } from '@vueuse/core'
import Sizes from '@/types/sizes'
import BaseCheckboxVariant from '@/types/baseCheckboxVariants'
import { setColorVolume, changeColorName } from '@/utils/useColors'

export const makeUCheckboxProps = propsFactory(
  {
    size: {
      type: String,
      default: Sizes.sm,
      required: false,
    },
    variant: {
      type: String,
      default: BaseCheckboxVariant.default,
      required: false,
    },
    disabled: {
      type: Boolean,
      default: false,
      required: false,
    },
    modelValue: {
      type: Boolean,
      default: false,
      required: false,
    },

    ...makeComponentProps(),
    ...makeTagProps(),
  },
  'UCheckbox'
)

export type UCheckboxProps = ExtractPropTypes<typeof makeUCheckboxProps>

export type UCheckboxSlots = {
  default: never
}

export const UCheckbox = genericComponent<UCheckboxSlots>()({
  name: 'UCheckbox',

  props: makeUCheckboxProps(),

  emits: {
    'update:modelValue': (value: boolean) => true,
    'keydown:enter': () => true,
  },

  setup(props, { emit, slots }) {
    const iconColor = computed(() => {
      if (!props.disabled === false && props.variant !== 'check') {
        return 'gray-300'
      }
      if (props.variant === 'check') {
        return 'white'
      }
      return 'primary-600'
    })

    const isFocused = ref(false)

    const handleKeyDown = (event: KeyboardEvent) => {
      if (isFocused.value && event.key === 'Enter' && !props.disabled) {
        emit('keydown:enter')
        onClick(props.modelValue)
      }
    }

    useEventListener('keydown', handleKeyDown)

    const defaultCheckedClassesCheckbox = computed(
      () =>
        `bg-${changeColorName(
          'primary-600',
          -550
        )} border-${'primary-600'} hover:bg-${setColorVolume(
          'primary-600',
          100
        )} hover:border-${changeColorName(
          'primary-600',
          0
        )} active:bg-${setColorVolume(
          'primary-600',
          50
        )} active:shadow-md active:shadow-${changeColorName(
          'primary-600',
          -500
        )} active:border-primary-600
        focus-visible:border-primary-600 focus-visible:bg-primary-100
          `
    )

    const defaultClassesCheckbox = computed(
      () =>
        `hover:bg-${setColorVolume(
          'primary-600',
          100
        )} hover:border-${changeColorName(
          'primary-600',
          0
        )} border-${'gray-300'}
          active:bg-${changeColorName('primary-600', -600)}
           active:shadow-md active:shadow-${changeColorName(
             'primary-600',
             -500
           )} active:border-${changeColorName('primary-600', -300)}
           focus-visible:border-primary-600 focus-visible:bg-primary-100
          `
    )

    const DisabledDefaultClassesCheckbox = computed(
      () => `bg-gray-100 border-gray-300 cursor-not-allowed`
    )

    const radioClassesCheckbox = computed(
      () =>
        `rounded-full border-gray-300 hover:bg-${setColorVolume(
          'primary-600',
          100
        )} hover:border-${changeColorName(
          'primary-600',
          0
        )} active:bg-${changeColorName('primary-600', -600)}
          active:shadow-md active:shadow-${changeColorName(
            'primary-600',
            -500
          )} active:border-${changeColorName('primary-600', -300)}
          focus-visible:border-primary-600 focus-visible:bg-primary-100
          `
    )

    const radioCheckedClassesCheckbox = computed(
      () =>
        `rounded-full bg-${changeColorName(
          'primary-600',
          -550
        )} border-${'primary-600'} hover:bg-${setColorVolume(
          'primary-600',
          100
        )} hover:border-${changeColorName(
          'primary-600',
          0
        )} active:bg-${setColorVolume(
          'primary-600',
          50
        )} active:shadow-md active:shadow-${changeColorName(
          'primary-600',
          -500
        )} active:border-${'primary-600'}
        focus-visible:border-primary-600 focus-visible:bg-primary-100
          `
    )

    const DisabledRadioClassesCheckbox = computed(
      () => `rounded-full bg-gray-100 border-gray-300 cursor-not-allowed`
    )

    const checkClassesCheckbox = computed(
      () =>
        `rounded-full border-gray-300 hover:bg-${setColorVolume(
          'primary-600',
          50
        )} hover:border-${changeColorName(
          'primary-600',
          0
        )} active:bg-${changeColorName('primary-600', -600)}
           active:shadow-md active:shadow-${changeColorName(
             'primary-600',
             -500
           )} active:border-${changeColorName('primary-600', -300)}
           focus-visible:border-primary-600 focus-visible:bg-primary-100
          `
    )

    const checkCheckedClassesCheckbox = computed(
      () =>
        `rounded-full bg-${'primary-600'} border-${'primary-600'} hover:bg-${setColorVolume(
          'primary-600',
          700
        )} hover:border-${setColorVolume(
          'primary-600',
          700
        )} active:shadow-md active:shadow-${changeColorName(
          'primary-600',
          -500
        )} active:bg-${setColorVolume('primary-600', 600)}
          active:border-${setColorVolume('primary-600', 600)}
          focus-visible:border-primary-600 focus-visible:bg-primary-700
          `
    )

    const DisabledCheckClassesCheckbox = computed(
      () => `rounded-full bg-gray-300 border-gray-300 cursor-not-allowed`
    )

    const toggleBgElementSize = computed(() => {
      return props.size === 'sm' ? 'w-36 h-20' : 'w-44 h-24'
    })

    const toggleBgClasses = computed(
      () =>
        `bg-gray-100 hover:bg-gray-200 ${toggleBgElementSize.value} rounded-12`
    )

    const toggleCheckedClasses = computed(
      () =>
        `bg-primary-600 hover:bg-primary-700 ${toggleBgElementSize.value} rounded-12`
    )

    const toggleDisabledPseudoClasses = computed(
      () => `bg-transparent ${toggleBgElementSize.value} rounded-12`
    )

    const toggleSize = computed(() => {
      return props.size === 'sm' ? 'w-4 h-4.5' : 'w-5 h-5.5'
    })

    const togglePositionClasses = computed(() => {
      return props.modelValue && props.size === 'sm'
        ? 'ml-4.6 my-0.5'
        : props.modelValue && props.size === 'md'
        ? 'ml-5.5 my-0.5'
        : 'my-0.5 mx-0.5'
    })

    const toggleClasses = computed(
      () =>
        `${toggleSize.value} ${togglePositionClasses.value} rounded-full bg-white shadow-sm `
    )

    const classes = computed(() => ({
      //general styling
      'box-border flex rounded border focus:outline-none':
        props.variant !== 'toggle',

      ...(props.variant === 'toggle' &&
        !props.disabled === true &&
        props.modelValue === false && {
          [toggleBgClasses.value]: true,
        }),

      ...(props.variant === 'toggle' &&
        !props.disabled === true &&
        props.modelValue === true && {
          [toggleCheckedClasses.value]: true,
        }),

      ...(props.variant === 'toggle' &&
        props.disabled === true && {
          [toggleDisabledPseudoClasses.value]: true,
        }),

      ...(!props.disabled === true && {
        'cursor-pointer': true,
      }),

      ...(props.variant === 'default' &&
        !props.disabled === true &&
        props.modelValue === false && {
          [defaultClassesCheckbox.value]: true,
        }),

      ...(props.variant === 'default' &&
        !props.disabled === true &&
        props.modelValue === true && {
          [defaultCheckedClassesCheckbox.value]: true,
        }),

      ...(!props.disabled === false &&
        props.variant === 'default' && {
          [DisabledDefaultClassesCheckbox.value]: true,
        }),

      ...(props.variant === 'radio' &&
        !props.disabled === true &&
        props.modelValue === false && {
          [radioClassesCheckbox.value]: true,
        }),

      ...(props.variant === 'radio' &&
        !props.disabled === true &&
        props.modelValue === true && {
          [radioCheckedClassesCheckbox.value]: true,
        }),

      ...(!props.disabled === false &&
        props.variant === 'radio' && {
          [DisabledRadioClassesCheckbox.value]: true,
        }),

      ...(props.variant === 'check' &&
        !props.disabled === true &&
        props.modelValue === false && {
          [checkClassesCheckbox.value]: true,
        }),

      ...(props.variant === 'check' &&
        !props.disabled === true &&
        props.modelValue === true && {
          [checkCheckedClassesCheckbox.value]: true,
        }),

      ...(!props.disabled === false &&
        props.variant === 'check' && {
          [DisabledCheckClassesCheckbox.value]: true,
        }),

      'h-[16px] w-[16px]': props.size === 'sm' && props.variant !== 'toggle',
      'h-[20px] w-[20px]': props.size === 'md' && props.variant !== 'toggle',
    }))

    const onClick = (modelValue: boolean) => {
      if (!props.disabled) {
        emit('update:modelValue', !props.modelValue)
      }
    }

    return () => (
      <div class="flex w-fit h-fit gap-1 items-center">
        <div
          class={classes.value}
          onClick={() => onClick(props.modelValue)}
          onFocus={() => (isFocused.value = true)}
          onBlur={() => (isFocused.value = false)}
        >
          {props.variant === 'toggle' ? (
            <div class={toggleClasses.value}></div>
          ) : null}
          {props.variant !== 'radio' &&
          props.variant !== 'toggle' &&
          props.modelValue &&
          props.size === 'sm' ? (
            <svg
              width="12"
              height="12"
              viewBox="0 0 12 12"
              fill="none"
              xmlns="http://www.w3.org/2000/svg"
              class={'m-auto'}
            >
              <path
                class={'stroke-' + iconColor.value}
                d="M10 3L4.5 8.5L2 6"
                stroke-width="1.6666"
                stroke-linecap="round"
                stroke-linejoin="round"
              />
            </svg>
          ) : null}
          {props.variant !== 'radio' &&
          props.variant !== 'toggle' &&
          props.modelValue &&
          props.size === 'md' ? (
            <svg
              width="14"
              height="14"
              viewBox="0 0 14 14"
              fill="none"
              xmlns="http://www.w3.org/2000/svg"
              class={'m-auto'}
            >
              <path
                class={'stroke-' + iconColor.value}
                d="M11.6666 3.5L5.24998 9.91667L2.33331 7"
                stroke-width="2"
                stroke-linecap="round"
                stroke-linejoin="round"
              />
            </svg>
          ) : null}
          {props.variant === 'radio' &&
          props.modelValue &&
          props.size === 'sm' ? (
            <div
              class={
                'h-[6px] w-[6px] m-auto rounded-full bg-' + iconColor.value
              }
            ></div>
          ) : null}
          {props.variant === 'radio' &&
          props.modelValue &&
          props.size === 'md' ? (
            <div
              class={
                'h-[8px] w-[8px] m-auto rounded-full bg-' + iconColor.value
              }
            ></div>
          ) : null}
        </div>
        <div class="cursor-pointer" onClick={() => onClick(props.modelValue)}>
          {slots.default?.()}
        </div>
      </div>
    )
  },
})

export type UCheckbox = InstanceType<typeof UCheckbox>
