<template>
  <n-drawer
    v-bind="$attrs"
    v-model:show="show"
    :width="drawerWidth"
    :show-mask="props.showMask"
    :placement="props.placement"
    :auto-focus="false"
    class="crm-drawer"
    @after-leave="emit('cancel')"
    @esc="emit('esc')"
    @mask-click="emit('maskClick')"
  >
    <n-drawer-content
      :title="props.title"
      :closable="props.closable"
      :header-class="`${props.headerClass} crm-drawer-header-class ${
        !props.closable ? 'crm-drawer-header-class-no-close' : ''
      }`"
      :body-content-class="`${props.noPadding ? 'crm-no-padding-drawer' : ''} ${props.bodyContentClass || ''}`"
    >
      <template #header>
        <slot name="header">
          <div class="flex w-full items-center justify-between gap-[24px] overflow-hidden">
            <n-button v-if="props.showBack" text class="mr-[4px] w-[32px]" @click="handleCancel">
              <n-icon size="16">
                <ChevronBackOutline />
              </n-icon>
            </n-button>
            <div class="one-line-text flex flex-1 items-center gap-[8px]">
              <slot name="titleLeft"></slot>
              <slot name="title">
                <n-tooltip trigger="hover" :delay="300" :disabled="!props.title">
                  <template #trigger>
                    <div class="one-line-text !leading-[20px]">{{ props.title }}</div>
                  </template>
                  {{ props.title }}
                </n-tooltip>
              </slot>
            </div>
            <div class="flex flex-shrink-0 justify-end">
              <slot name="titleRight"></slot>
            </div>
          </div>
        </slot>
      </template>
      <div v-if="!props.disabledWidthDrag" class="crm-drawer-handle" @mousedown="startResize">
        <CrmIcon type="iconicon_move" class="absolute left-[-3px] top-[50%] w-[14px]" :size="14" />
      </div>
      <n-spin :show="props.loading" class="h-full">
        <n-scrollbar
          x-scrollable
          content-class="h-full !w-full"
          :content-style="{ minWidth: props.minWidth ? `${props.minWidth}px` : 'auto' }"
        >
          <slot />
        </n-scrollbar>
      </n-spin>
      <template v-if="footer" #footer>
        <slot name="footer">
          <div class="flex w-full items-center justify-between">
            <slot name="footerLeft"></slot>
            <div class="ml-auto flex gap-[8px]">
              <n-button :disabled="props.loading" secondary @click="handleCancel">
                {{ t(props.cancelText || 'common.cancel') }}
              </n-button>
              <n-button
                v-if="props.showContinue"
                type="primary"
                ghost
                class="n-btn-outline-primary"
                :loading="props.loading"
                :disabled="okDisabled"
                @click="handleContinue"
              >
                {{ t(props.saveContinueText || 'common.saveAndContinue') }}
              </n-button>
              <n-button type="primary" :disabled="okDisabled" :loading="props.loading" @click="handleOk">
                {{ t(props.okText || 'common.add') }}
              </n-button>
            </div>
          </div>
        </slot>
      </template>
    </n-drawer-content>
  </n-drawer>
</template>

<script setup lang="ts">
  import { NButton, NDrawer, NDrawerContent, NIcon, NScrollbar, NSpin, NTooltip } from 'naive-ui';
  import { ChevronBackOutline } from '@vicons/ionicons5';

  import { useI18n } from '@lib/shared/hooks/useI18n';
  import type { FormViewSize } from '@lib/shared/models/system/module';

  import CrmIcon from '@/components/pure/crm-icon-font/index.vue';

  const { t } = useI18n();
  const props = withDefaults(
    defineProps<{
      width?: string | number;
      placement?: 'left' | 'right' | 'top' | 'bottom';
      showMask?: boolean | 'transparent';
      title?: string;
      cancelText?: string;
      saveContinueText?: string;
      okText?: string;
      showContinue?: boolean; // 是否显示保存并继续添加按钮
      okDisabled?: boolean;
      headerClass?: string; // 头部的class
      bodyContentClass?: string; // 内容区的class
      footer?: boolean; // 是否展示footer
      loading?: boolean;
      closable?: boolean;
      showBack?: boolean; // 显示返回关闭按钮
      noPadding?: boolean; // 无内边距
      disabledWidthDrag?: boolean; // 禁止拖拽宽度
      minWidth?: number;
      viewSize?: FormViewSize;
    }>(),
    {
      placement: 'right',
      showMask: true,
      footer: true,
      showBack: false,
      noPadding: false,
      closable: true,
      disabledWidthDrag: false,
    }
  );

  const emit = defineEmits<{
    (e: 'continue'): void;
    (e: 'confirm'): void;
    (e: 'cancel'): void;
    (e: 'esc'): void;
    (e: 'maskClick'): void;
  }>();

  const show = defineModel<boolean>('show', {
    required: true,
    default: false,
  });

  const getWindowWidth = () => window.innerWidth;

  function calculateWidth(width?: string | number) {
    if (typeof width === 'number') {
      return width;
    }
    if (!width || typeof width !== 'string') {
      return 0;
    }
    const match = width.trim().match(/^(\d+(?:\.\d+)?)%$/);
    if (!match) {
      return 0;
    }
    return Math.round((Number(match[1]) / 100) * getWindowWidth());
  }

  const resizing = ref(false); // 是否正在拖拽
  const drawerInitWidth = computed(() => {
    switch (props.viewSize) {
      case 'small':
        return '50%';
      case 'medium':
        return '75%';
      case 'large':
        return '100%';
      default:
        return props.width;
    }
  });
  const drawerWidth = ref(drawerInitWidth.value); // 抽屉初始宽度

  /**
   * 鼠标单击开始监听拖拽移动
   */
  const startResize = (event: MouseEvent) => {
    let initialWidth = 0;
    if (typeof drawerWidth.value === 'number') {
      initialWidth = drawerWidth.value;
    } else {
      initialWidth = calculateWidth(drawerWidth.value);
    }
    resizing.value = true;
    const startX = event.clientX;

    // 计算鼠标移动距离
    const handleMouseMove = (_event: MouseEvent) => {
      if (resizing.value) {
        const newWidth = initialWidth + (startX - _event.clientX); // 新的宽度等于当前抽屉宽度+鼠标移动的距离
        if (newWidth >= (props.minWidth || 480) && newWidth <= window.innerWidth) {
          // 最大最小宽度限制，最小宽度为480，最大宽度为视图窗口宽度的90%
          drawerWidth.value = newWidth;
        }
      }
    };

    // 松开鼠标按键，拖拽结束
    const handleMouseUp = () => {
      if (resizing.value) {
        // 如果当前是在拖拽，则重置拖拽状态，且移除鼠标监听事件
        resizing.value = false;
        window.removeEventListener('mousemove', handleMouseMove);
        window.removeEventListener('mouseup', handleMouseUp);
      }
    };

    window.addEventListener('mousemove', handleMouseMove);
    window.addEventListener('mouseup', handleMouseUp);
  };

  watch(
    () => drawerInitWidth.value,
    (newWidth) => {
      drawerWidth.value = newWidth;
    },
    {
      immediate: true,
    }
  );

  function handleContinue() {
    emit('continue');
  }

  function handleOk() {
    emit('confirm');
  }

  function handleCancel() {
    show.value = false;
    emit('cancel');
  }
</script>

<style lang="less">
  .crm-drawer {
    .crm-drawer-handle {
      @apply absolute left-0 top-0 flex h-full items-center;

      z-index: 200;
      width: 10px;
      background-color: var(--text-n8);
      cursor: col-resize;
    }
    .n-spin-content {
      @apply h-full;
    }
  }
  .crm-drawer-header-class {
    .n-drawer-header__main {
      max-width: calc(100% - 28px);
    }
    &-no-close {
      .n-drawer-header__main {
        max-width: 100%;
      }
    }
  }
  .crm-no-padding-drawer {
    padding: 0 !important;
  }
</style>
