import type { App, ExtractPropTypes } from 'vue';
import { computed, defineComponent } from 'vue';
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
import CheckOutlined from '@ant-design/icons-vue/CheckOutlined';
import PropTypes, { withUndefined } from '../_util/vue-types';
import initDefaultProps from '../_util/props-util/initDefaultProps';
import VcSteps, { Step as VcStep } from '../vc-steps';
import { tuple } from '../_util/type';
import useConfigInject from '../_util/hooks/useConfigInject';
import useBreakpoint from '../_util/hooks/useBreakpoint';
import classNames from '../_util/classNames';
import Progress from '../progress';
import omit from '../_util/omit';
import { VcStepProps } from '../vc-steps/Step';

export const stepsProps = () => ({
  prefixCls: PropTypes.string,
  iconPrefix: PropTypes.string,
  current: PropTypes.number,
  initial: PropTypes.number,
  percent: PropTypes.number,
  responsive: PropTypes.looseBool,
  labelPlacement: PropTypes.oneOf(tuple('horizontal', 'vertical')).def('horizontal'),
  status: PropTypes.oneOf(tuple('wait', 'process', 'finish', 'error')),
  size: PropTypes.oneOf(tuple('default', 'small')),
  direction: PropTypes.oneOf(tuple('horizontal', 'vertical')),
  progressDot: withUndefined(PropTypes.oneOfType([PropTypes.looseBool, PropTypes.func])),
  type: PropTypes.oneOf(tuple('default', 'navigation')),
  onChange: PropTypes.func,
  'onUpdate:current': PropTypes.func,
});

export const stepProps = () => ({
  description: PropTypes.any,
  icon: PropTypes.any,
  status: PropTypes.oneOf(tuple('wait', 'process', 'finish', 'error')),
  disabled: PropTypes.looseBool,
  title: PropTypes.any,
  subTitle: PropTypes.any,
  onClick: PropTypes.func,
});

export type StepsProps = Partial<ExtractPropTypes<ReturnType<typeof stepsProps>>>;

export type StepProps = Partial<ExtractPropTypes<ReturnType<typeof stepProps>>>;

const Steps = defineComponent({
  name: 'ASteps',
  inheritAttrs: false,
  props: initDefaultProps(stepsProps(), {
    current: 0,
    responsive: true,
  }),
  slots: ['progressDot'],
  emits: ['update:current', 'change'],
  setup(props, { attrs, slots, emit }) {
    const { prefixCls, direction: rtlDirection, configProvider } = useConfigInject('steps', props);
    const screens = useBreakpoint();
    const direction = computed(() =>
      props.responsive && screens.value.xs ? 'vertical' : props.direction,
    );
    const iconPrefix = computed(() => configProvider.getPrefixCls('', props.iconPrefix));
    const handleChange = (current: number) => {
      emit('update:current', current);
      emit('change', current);
    };
    const stepIconRender = ({
      node,
      status,
    }: {
      node: any;
      index: number;
      status: string;
      title: any;
      description: any;
    }) => {
      if (status === 'process' && props.percent !== undefined) {
        // currently it's hard-coded, since we can't easily read the actually width of icon
        const progressWidth = props.size === 'small' ? 32 : 40;
        const iconWithProgress = (
          <div class={`${prefixCls}-progress-icon`}>
            <Progress
              type="circle"
              percent={props.percent}
              width={progressWidth}
              strokeWidth={4}
              format={() => null}
            />
            {node}
          </div>
        );
        return iconWithProgress;
      }
      return node;
    };
    return () => {
      const stepsClassName = classNames(
        {
          [`${prefixCls.value}-rtl`]: rtlDirection.value === 'rtl',
          [`${prefixCls.value}-with-progress`]: props.percent !== undefined,
        },
        attrs.class,
      );
      const icons = {
        finish: <CheckOutlined class={`${prefixCls}-finish-icon`} />,
        error: <CloseOutlined class={`${prefixCls}-error-icon`} />,
      };
      return (
        <VcSteps
          icons={icons}
          {...omit(props, ['percent', 'responsive'])}
          direction={direction.value}
          prefixCls={prefixCls.value}
          iconPrefix={iconPrefix.value}
          class={stepsClassName}
          onChange={handleChange}
          v-slots={{ ...slots, stepIcon: stepIconRender }}
        />
      );
    };
  },
});

/* istanbul ignore next */
export const Step = defineComponent({
  ...VcStep,
  name: 'AStep',
  props: VcStepProps(),
});
export default Object.assign(Steps, {
  Step,
  install: (app: App) => {
    app.component(Steps.name, Steps);
    app.component(Step.name, Step);
    return app;
  },
});