import { h, defineComponent, computed, inject, ref, toRef, renderSlot } from 'vue';
import { useMergedState, useMemo } from 'vooks';
import { createId } from 'seemly';
import { useConfig, useFormItem, useTheme } from '../../_mixins';
import { NIconSwitchTransition } from '../../_internal';
import { warn, call, createKey } from '../../_utils';
import { checkboxLight } from '../styles';
import CheckMark from './CheckMark';
import LineMark from './LineMark';
import { checkboxGroupInjectionKey } from './CheckboxGroup';
import style from './styles/index.cssr';
const checkboxProps = Object.assign(Object.assign({}, useTheme.props), { size: String, checked: {
        type: Boolean,
        default: undefined
    }, defaultChecked: Boolean, value: [String, Number], disabled: {
        type: Boolean,
        default: undefined
    }, indeterminate: Boolean, label: String, focusable: {
        type: Boolean,
        default: true
    }, 'onUpdate:checked': [Function, Array], onUpdateChecked: [Function, Array], 
    // private
    privateTableHeader: Boolean, 
    // deprecated
    onChange: {
        type: [Function, Array],
        validator: () => {
            warn('checkbox', '`on-change` is deprecated, please use `on-update:checked` instead.');
            return true;
        },
        default: undefined
    } });
export default defineComponent({
    name: 'Checkbox',
    props: checkboxProps,
    setup(props) {
        const { mergedClsPrefixRef } = useConfig(props);
        const formItem = useFormItem(props, {
            mergedSize(NFormItem) {
                const { size } = props;
                if (size !== undefined)
                    return size;
                if (NCheckboxGroup) {
                    const { value: mergedSize } = NCheckboxGroup.mergedSizeRef;
                    if (mergedSize !== undefined) {
                        return mergedSize;
                    }
                }
                if (NFormItem) {
                    const { mergedSize } = NFormItem;
                    if (mergedSize !== undefined)
                        return mergedSize.value;
                }
                return 'medium';
            },
            mergedDisabled(NFormItem) {
                const { disabled } = props;
                if (disabled !== undefined)
                    return disabled;
                if (NCheckboxGroup) {
                    if (NCheckboxGroup.disabledRef.value)
                        return true;
                    const { maxRef: { value: max }, checkedCountRef } = NCheckboxGroup;
                    if (max !== undefined &&
                        checkedCountRef.value >= max &&
                        !renderedCheckedRef.value) {
                        return true;
                    }
                    const { minRef: { value: min } } = NCheckboxGroup;
                    if (min !== undefined &&
                        checkedCountRef.value <= min &&
                        renderedCheckedRef.value) {
                        return true;
                    }
                }
                if (NFormItem) {
                    return NFormItem.disabled.value;
                }
                return false;
            }
        });
        const { mergedDisabledRef, mergedSizeRef } = formItem;
        const NCheckboxGroup = inject(checkboxGroupInjectionKey, null);
        const uncontrolledCheckedRef = ref(props.defaultChecked);
        const controlledCheckedRef = toRef(props, 'checked');
        const mergedCheckedRef = useMergedState(controlledCheckedRef, uncontrolledCheckedRef);
        const renderedCheckedRef = useMemo(() => {
            if (NCheckboxGroup) {
                const groupValueSet = NCheckboxGroup.valueSetRef.value;
                if (groupValueSet && props.value !== undefined) {
                    return groupValueSet.has(props.value);
                }
                return false;
            }
            else {
                return mergedCheckedRef.value;
            }
        });
        const themeRef = useTheme('Checkbox', 'Checkbox', style, checkboxLight, props, mergedClsPrefixRef);
        function toggle(e) {
            if (NCheckboxGroup && props.value !== undefined) {
                NCheckboxGroup.toggleCheckbox(!renderedCheckedRef.value, props.value);
            }
            else {
                const { onChange, 'onUpdate:checked': _onUpdateCheck, onUpdateChecked } = props;
                const { nTriggerFormInput, nTriggerFormChange } = formItem;
                const nextChecked = !renderedCheckedRef.value;
                if (_onUpdateCheck)
                    call(_onUpdateCheck, nextChecked, e);
                if (onUpdateChecked)
                    call(onUpdateChecked, nextChecked, e);
                if (onChange)
                    call(onChange, nextChecked); // deprecated
                nTriggerFormInput();
                nTriggerFormChange();
                uncontrolledCheckedRef.value = nextChecked;
            }
        }
        function handleClick(e) {
            if (!mergedDisabledRef.value) {
                toggle(e);
            }
        }
        function handleKeyUp(e) {
            if (mergedDisabledRef.value)
                return;
            switch (e.code) {
                case 'Space':
                case 'Enter':
                case 'NumpadEnter':
                    toggle(e);
            }
        }
        function handleKeyDown(e) {
            switch (e.code) {
                case 'Space':
                    e.preventDefault();
            }
        }
        return Object.assign(formItem, {
            mergedClsPrefix: mergedClsPrefixRef,
            mergedDisabled: mergedDisabledRef,
            renderedChecked: renderedCheckedRef,
            mergedTheme: themeRef,
            labelId: createId(),
            handleClick,
            handleKeyUp,
            handleKeyDown,
            cssVars: computed(() => {
                const { value: mergedSize } = mergedSizeRef;
                const { common: { cubicBezierEaseInOut }, self: { borderRadius, color, colorChecked, colorDisabled, colorTableHeader, colorTableHeaderModal, colorTableHeaderPopover, checkMarkColor, checkMarkColorDisabled, border, borderFocus, borderDisabled, borderChecked, boxShadowFocus, textColor, textColorDisabled, checkMarkColorDisabledChecked, colorDisabledChecked, borderDisabledChecked, labelPadding, [createKey('fontSize', mergedSize)]: fontSize, [createKey('size', mergedSize)]: size } } = themeRef.value;
                return {
                    '--size': size,
                    '--bezier': cubicBezierEaseInOut,
                    '--border-radius': borderRadius,
                    '--border': border,
                    '--border-checked': borderChecked,
                    '--border-focus': borderFocus,
                    '--border-disabled': borderDisabled,
                    '--border-disabled-checked': borderDisabledChecked,
                    '--box-shadow-focus': boxShadowFocus,
                    '--color': color,
                    '--color-checked': colorChecked,
                    '--color-table-header': colorTableHeader,
                    '--color-table-header-modal': colorTableHeaderModal,
                    '--color-table-header-popover': colorTableHeaderPopover,
                    '--color-disabled': colorDisabled,
                    '--color-disabled-checked': colorDisabledChecked,
                    '--text-color': textColor,
                    '--text-color-disabled': textColorDisabled,
                    '--check-mark-color': checkMarkColor,
                    '--check-mark-color-disabled': checkMarkColorDisabled,
                    '--check-mark-color-disabled-checked': checkMarkColorDisabledChecked,
                    '--font-size': fontSize,
                    '--label-padding': labelPadding
                };
            })
        });
    },
    render() {
        const { $slots, renderedChecked, mergedDisabled, indeterminate, privateTableHeader, cssVars, labelId, label, mergedClsPrefix, focusable, handleKeyUp, handleKeyDown, handleClick } = this;
        return (h("div", { class: [
                `${mergedClsPrefix}-checkbox`,
                {
                    [`${mergedClsPrefix}-checkbox--checked`]: renderedChecked,
                    [`${mergedClsPrefix}-checkbox--disabled`]: mergedDisabled,
                    [`${mergedClsPrefix}-checkbox--indeterminate`]: indeterminate,
                    [`${mergedClsPrefix}-checkbox--table-header`]: privateTableHeader
                }
            ], tabindex: mergedDisabled || !focusable ? undefined : 0, role: "checkbox", "aria-checked": indeterminate ? 'mixed' : renderedChecked, "aria-labelledby": labelId, style: cssVars, onKeyup: handleKeyUp, onKeydown: handleKeyDown, onClick: handleClick, onMousedown: () => {
                const preventDefault = (e) => {
                    e.preventDefault();
                };
                window.addEventListener('selectstart', preventDefault);
                setTimeout(() => {
                    window.removeEventListener('selectstart', preventDefault);
                }, 0);
            } },
            h("div", { class: `${mergedClsPrefix}-checkbox-box` },
                h(NIconSwitchTransition, null, {
                    default: () => this.indeterminate ? (h("div", { key: "indeterminate", class: `${mergedClsPrefix}-checkbox-icon` }, LineMark)) : (h("div", { key: "check", class: `${mergedClsPrefix}-checkbox-icon` }, CheckMark))
                }),
                h("div", { class: `${mergedClsPrefix}-checkbox-box__border` })),
            label !== null || $slots.default ? (h("span", { class: `${mergedClsPrefix}-checkbox__label`, id: labelId }, renderSlot($slots, 'default', undefined, () => [label]))) : null));
    }
});
