import type { ExtractPropTypes, InjectionKey, Ref } from 'vue'

import type { MouseEventHandler } from '../_util/EventInterface'
import type { VueNode } from '../_util/type'
import { arrayType, booleanType, functionType, stringType } from '../_util/type'
import PropTypes from '../_util/vue-types'

export type CheckboxValueType = string | number | boolean
export interface CheckboxOptionType {
  label?: VueNode
  value: CheckboxValueType
  disabled?: boolean
  indeterminate?: boolean
  onChange?: (e: CheckboxChangeEvent) => void
}

export interface CheckboxChangeEvent {
  target: CheckboxChangeEventTarget
  stopPropagation: () => void
  preventDefault: () => void
  nativeEvent: MouseEvent
}

export interface CheckboxChangeEventTarget extends CheckboxProps {
  checked: boolean
}

export const abstractCheckboxGroupProps = () => {
  return {
    name: String,
    prefixCls: String,
    options: arrayType<Array<CheckboxOptionType | string | number>>(
      [] as Array<CheckboxOptionType | string | number>,
    ),
    disabled: Boolean,
    id: String,
  }
}

export const checkboxGroupProps = () => {
  return {
    ...abstractCheckboxGroupProps(),
    defaultValue: arrayType<Array<CheckboxValueType>>(),
    value: arrayType<Array<CheckboxValueType>>(),
    onChange: functionType<(checkedValue: Array<CheckboxValueType>) => void>(),
    'onUpdate:value': functionType<(checkedValue: Array<CheckboxValueType>) => void>(),
  }
}

export type CheckboxGroupProps = Partial<ExtractPropTypes<ReturnType<typeof checkboxGroupProps>>>

export const abstractCheckboxProps = () => {
  return {
    prefixCls: String,
    defaultChecked: booleanType(),
    checked: booleanType(),
    disabled: booleanType(),
    isGroup: booleanType(),
    value: PropTypes.any,
    name: String,
    id: String,
    indeterminate: booleanType(),
    type: stringType('checkbox'),
    autofocus: booleanType(),
    onChange: functionType<(e: CheckboxChangeEvent) => void>(),
    'onUpdate:checked': functionType<(checked: boolean) => void>(),
    onClick: functionType<MouseEventHandler>(),
    skipGroup: booleanType(false),
  }
}

export const checkboxProps = () => {
  return {
    ...abstractCheckboxProps(),
    indeterminate: booleanType(false),
  }
}

export type CheckboxProps = Partial<ExtractPropTypes<ReturnType<typeof checkboxProps>>>

export interface CheckboxGroupContext {
  cancelValue: (id: symbol) => void
  registerValue: (id: symbol, value: string) => void
  toggleOption: (option: CheckboxOptionType) => void
  name: Ref<string>
  disabled: Ref<boolean>
  mergedValue: Ref<CheckboxValueType[]>
}
export const CheckboxGroupContextKey: InjectionKey<CheckboxGroupContext> =
  Symbol('CheckboxGroupContext')
