import {
  type PropType,
  computed,
  defineComponent,
  ref,
  watch,
  toRaw,
  provide,
  inject
} from 'vue';
import Popover from 'ant-design-vue/es/popover';
import Button from 'ant-design-vue/es/button';
import Menu, { MenuItem } from 'ant-design-vue/es/menu';
import { CaretDownOutlined } from '@ant-design/icons-vue';
import 'ant-design-vue/es/popover/style';
import 'ant-design-vue/es/button/style';
import 'ant-design-vue/es/menu/style';
// @ts-ignore
import style from './style/index.module.less';
import { highlightRowFnKey } from '@kt/unity-table-layout';
import { getGuid } from '@kt/unity-utils';

// 📝 需要携带 export 否则 ts 打包会有问题！！！
export interface FieldNames {
  label: string;
  value?: string;
  disabled?: boolean;
}
const DropdownButton = defineComponent({
  name: 'DropdownButton',
  inheritAttrs: false,
  props: {
    text: {
      type: String,
      default: ''
    },
    options: {
      type: Array as PropType<Record<string, any>[]>,
      default: () => []
    },
    fieldNames: {
      type: Object as PropType<FieldNames>,
      default: () => ({})
    },
    icon: {
      type: Boolean,
      default: true
    },

    // 是否无边框，适合表格内部的更多按钮
    bordered: {
      type: Boolean,
      default: true
    }
  },
  emits: ['visibleChange', 'select'],
  setup(props, { attrs, emit, slots }) {
    const clsGuid = `unity-dropdown-button-${getGuid()}`;
    const visible = ref(false);
    const mergedFieldNames = computed(() => fillFieldNames(props.fieldNames));
    const handleHover = () => {
      visible.value = true;
    };
    const handleVisibleChange = (_visible: boolean) => {
      visible.value = _visible;
    };
    const handleItemClick = (
      value: string | number,
      option: Record<string, any>
    ) => {
      if (inTableAction.value) {
        // ✨ 处理抽屉表格高亮
        const dBtnEl = document.querySelector(`.${clsGuid}`);
        highlightRowFn?.(
          dBtnEl?.closest('.ant-table-row') as HTMLElement | null
        );
      }

      visible.value = false;
      emit('select', value, option);
    };
    watch(visible, val => {
      emit('visibleChange', val);
    });
    // provide to DropdownButtonOption
    provide('dropdownButtonOptionClickKey', handleItemClick);

    // from Table provide
    const highlightRowFn =
      inject<($row: HTMLElement | null, dataRowKey?: string | number) => void>(
        highlightRowFnKey
      );
    const inTableAction = computed(() => highlightRowFn !== undefined);

    return () => (
      <Popover
        class={['unity-dropdown-button', style['dropdown-button']]}
        overlayClassName={'unity-dropdown-button-popover'}
        align={{
          // 偏移到比较合适的位置
          offset: inTableAction.value || !props.bordered ? [2, -6] : [-2, -2]
        }}
        placement="bottomRight"
        {...attrs}
        title=""
        visible={visible.value}
        onVisibleChange={handleVisibleChange}
        // 强制 浮层渲染父节点，默认渲染到 body 上，避免被全局的 getPopupContainer 影响
        getPopupContainer={() => document.body}
        v-slots={{
          content: () => (
            <Menu>
              {/* options 优先于插槽，参考 antd select */}
              {props.options?.length > 0
                ? props.options.map((item, index) => (
                    <MenuItem
                      key={item[mergedFieldNames.value.value]}
                      disabled={item.disabled}
                      onClick={() =>
                        handleItemClick(
                          item[mergedFieldNames.value.value],
                          Object.assign({ disabled: false, index }, toRaw(item))
                        )
                      }
                    >
                      {item[mergedFieldNames.value.label]}
                    </MenuItem>
                  ))
                : slots.default?.()}
            </Menu>
          )
        }}
      >
        <Button
          class={[clsGuid]}
          type={inTableAction.value || !props.bordered ? 'link' : 'default'}
          // @ts-ignore
          onMouseover={handleHover}
        >
          {props.text ? props.text : slots.text?.()}
          {!inTableAction.value && props.bordered && props.icon ? (
            <CaretDownOutlined />
          ) : null}
        </Button>
      </Popover>
    );
  }
});

const DropdownButtonOption = defineComponent({
  name: 'DropdownButtonOption',
  props: {
    value: {
      type: [String, Number],
      default: ''
    },
    disabled: {
      type: Boolean,
      default: false
    }
  },
  emits: ['click'],
  setup(props, { slots, emit }) {
    const dropdownButtonOptionClick = inject<
      (value: string | number, option: Record<string, any>) => void
    >('dropdownButtonOptionClickKey');
    const handleClick = () => {
      const value = props.value;
      const option = {
        // 一般不会用到这个属性
        label: slots.default?.()?.[0]?.children || '',
        value: props.value,
        disabled: props.disabled
      };
      emit('click', value, option);
      dropdownButtonOptionClick?.(value, option);
    };
    return () => (
      <MenuItem
        key={props.value}
        disabled={props.disabled}
        onClick={handleClick}
      >
        {slots.default?.()}
      </MenuItem>
    );
  }
});

export default DropdownButton;
export { DropdownButtonOption };

function fillFieldNames(fieldNames: FieldNames | undefined) {
  const { label, value } = fieldNames || {};
  return {
    label: label || 'label',
    value: value || 'value'
  };
}
