import {
  App,
  computed,
  defineComponent,
  onMounted,
  PropType,
  ref,
  render,
  VNode,
  watchEffect
} from 'vue';
import dayjs, { Dayjs } from 'dayjs';
import { _t } from '@kt/unity-locale';
import { getGuid } from '@kt/unity-utils';
import config from './config';
import { PickerSeparator, PickerSuffix, PickerClear } from './components/Icons';
// @ts-ignore
import style from './style/index.module.less';

// import { ElDatePicker } from 'element-plus';
import { ElDatePicker } from 'element-plus/es/components/date-picker/index';
// el-reset.css 重置 body、h1...、p，a 等浏览器原生标签
// import 'element-plus/theme-chalk/el-reset.css';
// 一个完整的 ElDatePicker 需要包含这些 css，参考 element-plus/es/components/date-picker/style/css.mjs
import 'element-plus/theme-chalk/base.css';
import 'element-plus/theme-chalk/el-date-picker.css';
import 'element-plus/theme-chalk/el-input.css';
import 'element-plus/theme-chalk/el-scrollbar.css';
import 'element-plus/theme-chalk/el-popper.css';
import 'element-plus/theme-chalk/el-button.css';

const DEFAULT_FORMAT = 'YYYY-MM-DD HH:mm:ss';
const SIZE_MAP: Record<string, 'large' | 'default' | 'small'> = {
  large: 'large',
  middle: 'default',
  small: 'small'
};

const DateTimeRangePicker = defineComponent({
  name: 'DateTimeRangePicker',
  props: {
    value: {
      type: Object as PropType<[Dayjs, Dayjs]>
    },
    inputReadOnly: {
      type: Boolean,
      default: false
    },
    // 排除
    readOnly: null,
    allowClear: {
      type: Boolean,
      default: true
    },
    // 排除
    clearable: null,
    size: {
      type: String as PropType<'large' | 'middle' | 'small'>,
      default: 'middle'
    },
    placeholder: {
      type: [String, Array] as PropType<string | [string, string]>
    },
    startPlaceholder: null,
    endPlaceholder: null,
    valueFormat: {
      type: String
    },
    format: {
      type: String,
      default: DEFAULT_FORMAT
    },
    dropdownClassName: { type: String },
    popperClass: null,
    showTime: {
      type: [Boolean, Object] as PropType<
        | boolean
        | {
            defaultValue: [Dayjs, Dayjs] | null | undefined;
          }
      >,
      default: () => config.props.showTime
    },
    defaultTime: null,

    ranges: {
      type: [Boolean, Object] as PropType<
        | boolean
        | { [range: string]: Dayjs[] }
        | { [range: string]: () => Dayjs[] }
      >,
      default: () => config.props.ranges
    },
    shortcuts: null,

    disabledDate: {
      type: Function as PropType<(currentDate: Dayjs) => boolean>
    },

    // 业务需求的自定义扩展
    // 📝 antd 有提供了 props 和 插槽 对于页脚的两个处理
    renderExtraFooter: {
      type: Function as PropType<() => VNode>
    }
  },
  emits: ['update:value', 'calendar-change', 'change', 'ok', 'open-change'],
  setup(props, { attrs, emit, slots }) {
    const guid = getGuid();
    const myId = `el-date-editor-id--${guid}`;
    const myPopperId = `el-popper-id--${guid}`;

    const myCls = [myId, style['el-date-editor-extend']].join(' ');

    const dropdownClassName = computed(() =>
      [myPopperId, props.dropdownClassName].join(' ')
    );

    onMounted(() => {
      const elDateEditor = document.querySelector(`.${myId}`);
      const elPopper = document.querySelector(`.${myPopperId}`);

      // 替换分隔符
      const elRangeSeparator = elDateEditor?.querySelector(
        '.el-range-separator'
      );
      if (elRangeSeparator) {
        render(<PickerSeparator />, elRangeSeparator);
      }

      // 替换后缀 日历 icon 和 clear icon
      const elRangeCloseIcon = elDateEditor?.querySelector(
        '.el-range__close-icon'
      );
      if (elRangeCloseIcon) {
        elRangeCloseIcon.innerHTML = '';
        render(
          <>
            <PickerSuffix />
            {props.allowClear ? <PickerClear /> : null}
          </>,
          elRangeCloseIcon
        );
      }

      // 删除 el 自带的前缀
      const elRangeIcon = elDateEditor?.querySelector('.el-range__icon');
      elRangeIcon?.remove();

      // 替换弹层左右箭头
      const dArrowLeft = elPopper?.querySelector('.d-arrow-left');
      const arrowLeft = elPopper?.querySelector('.arrow-left');
      const dArrowRight = elPopper?.querySelector('.d-arrow-right');
      const arrowRight = elPopper?.querySelector('.arrow-right');
      if (dArrowLeft) dArrowLeft.innerHTML = '«';
      if (arrowLeft) arrowLeft.innerHTML = '‹';
      if (dArrowRight) dArrowRight.innerHTML = '»';
      if (arrowRight) arrowRight.innerHTML = '›';

      // 渲染额外的底部元素
      if (props.renderExtraFooter || slots.renderExtraFooter) {
        // 先获取 props，再获取 slots
        const ExtraFooter = props.renderExtraFooter
          ? props.renderExtraFooter?.()
          : slots.renderExtraFooter?.();
        const panelFooter = elPopper?.querySelector('.el-picker-panel__footer');
        const firstButton = panelFooter?.querySelectorAll('button')[0];
        if (ExtraFooter && firstButton && panelFooter) {
          // 创建一个额外的 div 容器
          const container = document.createElement('div');
          container.className = 'extra-footer-wrapper';
          render(<>{ExtraFooter}</>, container);
          panelFooter.insertBefore(container, firstButton);
        }
      }
    });

    const startPlaceholder = ref('');
    const endPlaceholder = ref('');
    watchEffect(() => {
      // 主动权交给外部
      if (props.placeholder) {
        let ph = props.placeholder;
        ph = Array.isArray(ph) ? ph : ph.slice(0, 2);
        startPlaceholder.value = props.placeholder[0];
        endPlaceholder.value = props.placeholder[1];
      } else {
        // 缺省处理
        startPlaceholder.value = _t('KTUnity.DateTimeRangePicker.startDate');
        endPlaceholder.value = _t('KTUnity.DateTimeRangePicker.endDate');
      }
    });

    const defaultTime = computed(() => {
      // 为了兼容之前写的 showTime ，这里判断如果 showTime 如果传入的是对象才会把主动权交给外部，否则内部处理缺省值
      if (typeof props.showTime === 'object') {
        // 如果外部不想要约束时间 00:00:00 - 11:59:59，直接传入 defaultValue null or undefined
        if (
          ([null, undefined] as unknown[]).includes(props.showTime.defaultValue)
        ) {
          return undefined;
        }
        return props.showTime.defaultValue;
      } else {
        return [dayjs('00:00:00', 'HH:mm:ss'), dayjs('11:59:59', 'HH:mm:ss')];
      }
    });

    const shortcuts = computed(() => {
      if (props.ranges === false) return undefined;

      // ant 规范转成 el 规范
      const ant2El = (
        data: { [range: string]: Dayjs[] } | { [range: string]: () => Dayjs[] }
      ) => {
        return Object.keys(data).map(key => ({
          text: key,
          value: data[key]
        }));
      };

      if (([true] as unknown[]).includes(props.ranges)) {
        // today: '今天',
        // yesterday: '昨天',
        // thisWeek: '本周',
        // lastWeek: '上周',
        // thisMonth: '本月',
        // lastMonth: '上月',
        // lastTwoMonths: '近两月'
        return ant2El({
          [_t('KTUnity.DateTimeRangePicker.today')]: [
            dayjs().startOf('day'),
            dayjs().endOf('day')
          ],
          [_t('KTUnity.DateTimeRangePicker.yesterday')]: [
            dayjs().subtract(1, 'day').startOf('day'),
            dayjs().subtract(1, 'day').endOf('day')
          ],
          [_t('KTUnity.DateTimeRangePicker.thisWeek')]: [
            dayjs().startOf('week'),
            dayjs().endOf('week')
          ],
          [_t('KTUnity.DateTimeRangePicker.lastWeek')]: [
            dayjs().subtract(1, 'week').startOf('week'),
            dayjs().subtract(1, 'week').endOf('week')
          ],
          [_t('KTUnity.DateTimeRangePicker.thisMonth')]: [
            dayjs().startOf('month'),
            dayjs().endOf('month')
          ],
          [_t('KTUnity.DateTimeRangePicker.lastMonth')]: [
            dayjs().subtract(1, 'month').startOf('month'),
            dayjs().subtract(1, 'month').endOf('month')
          ],
          [_t('KTUnity.DateTimeRangePicker.lastTwoMonths')]: [
            dayjs().subtract(1, 'month').startOf('month'),
            dayjs().endOf('month')
          ]
        });
      }
      return ant2El(
        props.ranges as
          | { [range: string]: Dayjs[] }
          | { [range: string]: () => Dayjs[] }
      );
    });

    const disabledDate = (currentDate: Date) => {
      if (props.disabledDate) return !!props.disabledDate(dayjs(currentDate));
      return false;
    };

    // Date to Dayjs
    const d2D = (date: Date | null, format?: string) => {
      if (date) {
        // @ts-ignore
        date = dayjs(date);
        if (format) {
          // @ts-ignore
          date = date.format(format);
        }
      }
      return date;
    };

    // 清空时 value 为 null
    const handleUpdateModelValue = (value: [any, any] | null) => {
      let dates = value;
      if (value && value.length > 0) {
        dates = [
          d2D(value[0], props.valueFormat),
          d2D(value[1], props.valueFormat)
        ];
      }
      emit('update:value', dates);
    };

    const handleCalendarChange = (value: [any | null, any | null]) => {
      const dates = [
        d2D(value[0], props.valueFormat),
        d2D(value[1], props.valueFormat)
      ];
      const dateStrings = [
        d2D(value[0], props.format) ?? '',
        d2D(value[1], props.format) ?? ''
      ];
      emit('calendar-change', dates, dateStrings);
    };

    const handleChange = (value: [any, any] | null) => {
      if (value && value.length > 0) {
        const dates = [
          d2D(value[0], props.valueFormat),
          d2D(value[1], props.valueFormat)
        ];
        const dateStrings = [
          d2D(value[0], props.format) ?? '',
          d2D(value[1], props.format) ?? ''
        ];
        emit('change', dates, dateStrings);
        // 这里的 ok 意义不大，但是也保持上发
        emit('ok', dates);
      } else {
        emit('change', null, ['', '']);
        emit('ok', null);
      }
    };
    const handleVisibleChange = (val: boolean) => {
      emit('open-change', val);
    };
    return () => (
      // 📝 <></> fragment 才可以处理好 {...attrs} 的具体位置，让内部组件属性来覆盖，否则会默认”反覆盖“
      <>
        <ElDatePicker
          {...attrs}
          class={myCls}
          type={'datetimerange'}
          model-value={props.value}
          onUpdate:modelValue={handleUpdateModelValue}
          value-format={props.valueFormat}
          format={props.format}
          readonly={props.inputReadOnly}
          clearable={props.allowClear}
          size={SIZE_MAP[props.size]}
          start-placeholder={startPlaceholder.value}
          end-placeholder={endPlaceholder.value}
          popper-class={dropdownClassName.value}
          // TODO:el 存在 bug 后续跟踪，ElPopperOptions
          // popper-options={{ placement: 'bottom' }}
          range-separator={''}
          default-time={defaultTime.value}
          shortcuts={shortcuts.value}
          // 动态 bind，提升一定性能
          {...(props.disabledDate ? { disabledDate } : {})}
          // @ts-ignore
          onCalendarChange={handleCalendarChange}
          // @ts-ignore
          onChange={handleChange}
          // @ts-ignore
          onVisibleChange={handleVisibleChange}
        />
      </>
    );
  }
});

export default DateTimeRangePicker as typeof DateTimeRangePicker & {
  install: (app: App, ...options: any[]) => any;
};
