import type { CSSProperties, PropType } from 'vue';
import { computed, ref, defineComponent, nextTick } from 'vue';
import type { MouseEventHandler } from '../_util/EventInterface';
import Transition, { getTransitionProps } from '../_util/transition';
import dialogPropTypes from './IDialogPropTypes';
import { offset } from './util';
const sentinelStyle = { width: 0, height: 0, overflow: 'hidden', outline: 'none' };

export type ContentRef = {
  focus: () => void;
  changeActive: (next: boolean) => void;
};
export default defineComponent({
  name: 'Content',
  inheritAttrs: false,
  props: {
    ...dialogPropTypes(),
    motionName: String,
    ariaId: String,
    onVisibleChanged: Function as PropType<(visible: boolean) => void>,
    onMousedown: Function as PropType<MouseEventHandler>,
    onMouseup: Function as PropType<MouseEventHandler>,
  },
  setup(props, { expose, slots, attrs }) {
    const sentinelStartRef = ref<HTMLDivElement>();
    const sentinelEndRef = ref<HTMLDivElement>();
    const dialogRef = ref<HTMLDivElement>();
    expose({
      focus: () => {
        sentinelStartRef.value?.focus();
      },
      changeActive: next => {
        const { activeElement } = document;
        if (next && activeElement === sentinelEndRef.value) {
          sentinelStartRef.value.focus();
        } else if (!next && activeElement === sentinelStartRef.value) {
          sentinelEndRef.value.focus();
        }
      },
    });
    const transformOrigin = ref<string>();
    const contentStyleRef = computed(() => {
      const { width, height } = props;
      const contentStyle: CSSProperties = {};
      if (width !== undefined) {
        contentStyle.width = typeof width === 'number' ? `${width}px` : width;
      }
      if (height !== undefined) {
        contentStyle.height = typeof height === 'number' ? `${height}px` : height;
      }
      if (transformOrigin.value) {
        contentStyle.transformOrigin = transformOrigin.value;
      }
      return contentStyle;
    });

    const onPrepare = () => {
      nextTick(() => {
        if (dialogRef.value) {
          const elementOffset = offset(dialogRef.value);
          transformOrigin.value = props.mousePosition
            ? `${props.mousePosition.x - elementOffset.left}px ${
                props.mousePosition.y - elementOffset.top
              }px`
            : '';
        }
      });
    };
    const onVisibleChanged = (visible: boolean) => {
      props.onVisibleChanged(visible);
    };
    return () => {
      const {
        prefixCls,
        footer = slots.footer?.(),
        title = slots.title?.(),
        ariaId,
        closable,
        closeIcon = slots.closeIcon?.(),
        onClose,
        bodyStyle,
        bodyProps,
        onMousedown,
        onMouseup,
        visible,
        modalRender = slots.modalRender,
        destroyOnClose,
        motionName,
      } = props;
      let footerNode: any;
      if (footer) {
        footerNode = <div class={`${prefixCls}-footer`}>{footer}</div>;
      }

      let headerNode: any;
      if (title) {
        headerNode = (
          <div class={`${prefixCls}-header`}>
            <div class={`${prefixCls}-title`} id={ariaId}>
              {title}
            </div>
          </div>
        );
      }

      let closer: any;
      if (closable) {
        closer = (
          <button type="button" onClick={onClose} aria-label="Close" class={`${prefixCls}-close`}>
            {closeIcon || <span class={`${prefixCls}-close-x`} />}
          </button>
        );
      }

      const content = (
        <div class={`${prefixCls}-content`}>
          {closer}
          {headerNode}
          <div class={`${prefixCls}-body`} style={bodyStyle} {...bodyProps}>
            {slots.default?.()}
          </div>
          {footerNode}
        </div>
      );
      const transitionProps = getTransitionProps(motionName);
      return (
        <Transition
          {...transitionProps}
          onBeforeEnter={onPrepare}
          onAfterEnter={() => onVisibleChanged(true)}
          onAfterLeave={() => onVisibleChanged(false)}
        >
          {visible || !destroyOnClose ? (
            <div
              {...attrs}
              ref={dialogRef}
              v-show={visible}
              key="dialog-element"
              role="document"
              style={[contentStyleRef.value, attrs.style as CSSProperties]}
              class={[prefixCls, attrs.class]}
              onMousedown={onMousedown}
              onMouseup={onMouseup}
            >
              <div tabindex={0} ref={sentinelStartRef} style={sentinelStyle} aria-hidden="true" />
              {modalRender ? modalRender({ originVNode: content }) : content}
              <div tabindex={0} ref={sentinelEndRef} style={sentinelStyle} aria-hidden="true" />
            </div>
          ) : null}
        </Transition>
      );
    };
  },
});
