<template>
  <div
    ref="rootRef"
    class="announcement-preview h-full w-full"
    :class="{ 'is-resizing': isResizing }"
  >
    <template v-if="isSplitMode">
      <ElContainer class="h-full w-full overflow-hidden">
        <ElMain class="h-full overflow-auto pr-4">
          <slot name="editor" />
        </ElMain>

        <div
          class="preview-resizer"
          role="separator"
          :aria-label="t('announcement.preview.resizeHandle')"
          @pointerdown="handleResizeStart"
        ></div>

        <ElAside
          class="preview-aside flex h-full items-center justify-center border-l border-[var(--el-border-color)] bg-[var(--el-fill-color-blank)]"
        >
          <div class="flex h-full w-full items-center justify-center p-4">
            <div
              class="preview-phone flex h-full max-h-[720px] w-full max-w-[380px] flex-col overflow-hidden rounded-[32px] border border-[var(--el-border-color)] bg-[var(--el-bg-color)] shadow-xl"
            >
              <div class="border-b border-[var(--el-border-color)] px-4 py-3">
                <div class="text-base font-semibold text-[var(--el-text-color-primary)]">
                  {{ titleText }}
                </div>
                <div class="mt-2 flex flex-wrap items-center gap-2">
                  <ElTag size="small" :type="typeTagType">{{ typeLabel }}</ElTag>
                  <ElTag size="small" :type="priorityTagType">{{ priorityText }}</ElTag>
                </div>
                <div class="mt-2 text-xs text-[var(--el-text-color-secondary)]">
                  <span class="mr-1">{{ $t('announcement.preview.publishAt') }}</span>
                  <span>{{ publishTimeText }}</span>
                </div>
              </div>

              <ElScrollbar class="flex-1">
                <div
                  class="announcement-preview__content px-4 py-4 text-sm leading-6 text-[var(--el-text-color-regular)]"
                >
                  <div v-if="hasContent" v-html="sanitizedContent"></div>
                  <div v-else class="text-sm text-[var(--el-text-color-secondary)]">
                    {{ $t('announcement.preview.emptyContent') }}
                  </div>
                </div>
              </ElScrollbar>
            </div>
          </div>
        </ElAside>
      </ElContainer>
    </template>

    <template v-else>
      <div class="h-full w-full">
        <slot name="editor" />
      </div>

      <div
        class="announcement-preview__action-bar sticky bottom-0 z-20 border-t border-[var(--el-border-color)] bg-[var(--el-bg-color)] px-4 py-3"
      >
        <ElButton type="primary" class="w-full" @click="drawerVisible = true">
          {{ $t('announcement.preview.openPreview') }}
        </ElButton>
      </div>

      <ElDrawer
        v-model="drawerVisible"
        :title="t('announcement.preview.drawerTitle')"
        direction="btt"
        :size="drawerSize"
        append-to-body
      >
        <div class="flex w-full justify-center px-4 pb-4">
          <div
            class="preview-phone flex h-full max-h-[720px] w-full max-w-[380px] flex-col overflow-hidden rounded-[32px] border border-[var(--el-border-color)] bg-[var(--el-bg-color)] shadow-xl"
          >
            <div class="border-b border-[var(--el-border-color)] px-4 py-3">
              <div class="text-base font-semibold text-[var(--el-text-color-primary)]">
                {{ titleText }}
              </div>
              <div class="mt-2 flex flex-wrap items-center gap-2">
                <ElTag size="small" :type="typeTagType">{{ typeLabel }}</ElTag>
                <ElTag size="small" :type="priorityTagType">{{ priorityText }}</ElTag>
              </div>
              <div class="mt-2 text-xs text-[var(--el-text-color-secondary)]">
                <span class="mr-1">{{ $t('announcement.preview.publishAt') }}</span>
                <span>{{ publishTimeText }}</span>
              </div>
            </div>

            <ElScrollbar class="flex-1">
              <div
                class="announcement-preview__content px-4 py-4 text-sm leading-6 text-[var(--el-text-color-regular)]"
              >
                <div v-if="hasContent" v-html="sanitizedContent"></div>
                <div v-else class="text-sm text-[var(--el-text-color-secondary)]">
                  {{ $t('announcement.preview.emptyContent') }}
                </div>
              </div>
            </ElScrollbar>
          </div>
        </div>
      </ElDrawer>
    </template>
  </div>
</template>

<script setup lang="ts">
  import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
  import { useWindowSize } from '@vueuse/core'
  import { useI18n } from 'vue-i18n'
  import DOMPurify from 'dompurify'
  import {
    ElAside,
    ElButton,
    ElContainer,
    ElDrawer,
    ElMain,
    ElScrollbar,
    ElTag
  } from 'element-plus'
  import type { AnnouncementFormData, TenantAnnouncementDto } from '@/types/announcement'
  import { TenantAnnouncementType } from '@/types/announcement'

  defineOptions({ name: 'AnnouncementPreview' })

  interface Props {
    announcement: Partial<AnnouncementFormData> | TenantAnnouncementDto
    mode?: 'split' | 'drawer'
  }

  // 1. 解析 Props 与基础依赖
  const { announcement, mode = 'split' } = defineProps<Props>()
  const { t, locale } = useI18n()
  const { width } = useWindowSize()

  // 2. 拖拽与布局状态
  const rootRef = ref<HTMLElement | null>(null)
  const isResizing = ref(false)
  const drawerVisible = ref(false)

  const PREVIEW_MIN_WIDTH = 320
  const PREVIEW_MAX_WIDTH = 520
  const PREVIEW_DEFAULT_WIDTH = 380
  const EDITOR_MIN_WIDTH = 360
  const DRAWER_BREAKPOINT = 1024

  const previewWidth = ref(PREVIEW_DEFAULT_WIDTH)

  // 3. 模式判定（桌面分栏 / 移动抽屉）
  const isDrawerMode = computed(() => mode === 'drawer' || width.value < DRAWER_BREAKPOINT)
  const isSplitMode = computed(() => !isDrawerMode.value)
  const drawerSize = computed(() => (width.value < 640 ? '90%' : '85%'))

  // 4. 预览数据统一读取
  const announcementData = computed(
    () => announcement as Partial<TenantAnnouncementDto> & Partial<AnnouncementFormData>
  )

  const titleText = computed(() => {
    // 1. 取标题或占位文案
    const title = announcementData.value.title?.trim()
    return title && title.length > 0 ? title : t('announcement.preview.titlePlaceholder')
  })

  const rawContent = computed(() => {
    // 1. 取原始内容
    return announcementData.value.content?.trim() || ''
  })

  const sanitizedContent = computed(() => {
    // 1. 使用 DOMPurify 清洗富文本
    return rawContent.value ? DOMPurify.sanitize(rawContent.value) : ''
  })

  const hasContent = computed(() => sanitizedContent.value.length > 0)

  const publishTimeText = computed(() => {
    // 1. 选择发布时间字段
    const candidate =
      announcementData.value.publishedAt ||
      announcementData.value.scheduledPublishAt ||
      announcementData.value.effectiveFrom ||
      null

    // 2. 格式化时间
    if (!candidate) {
      return t('announcement.preview.publishAtUnknown')
    }

    const date = new Date(candidate)
    if (Number.isNaN(date.getTime())) {
      return t('announcement.preview.publishAtUnknown')
    }

    return date.toLocaleString(locale.value)
  })

  const typeLabel = computed(() => {
    // 1. 根据枚举映射公告类型
    switch (announcementData.value.announcementType) {
      case TenantAnnouncementType.System:
        return t('announcement.type.system')
      case TenantAnnouncementType.Billing:
        return t('announcement.type.billing')
      case TenantAnnouncementType.Operation:
        return t('announcement.type.operation')
      case TenantAnnouncementType.SYSTEM_PLATFORM_UPDATE:
        return t('announcement.type.systemPlatformUpdate')
      case TenantAnnouncementType.SYSTEM_SECURITY_NOTICE:
        return t('announcement.type.systemSecurityNotice')
      case TenantAnnouncementType.SYSTEM_COMPLIANCE:
        return t('announcement.type.systemCompliance')
      case TenantAnnouncementType.TENANT_INTERNAL:
        return t('announcement.type.tenantInternal')
      case TenantAnnouncementType.TENANT_FINANCE:
        return t('announcement.type.tenantFinance')
      case TenantAnnouncementType.TENANT_OPERATION:
        return t('announcement.type.tenantOperation')
      default:
        return t('announcement.type.unknown')
    }
  })

  const typeTagType = computed(() => {
    // 1. 映射类型标签颜色
    switch (announcementData.value.announcementType) {
      case TenantAnnouncementType.System:
      case TenantAnnouncementType.SYSTEM_SECURITY_NOTICE:
      case TenantAnnouncementType.SYSTEM_COMPLIANCE:
        return 'danger'
      case TenantAnnouncementType.Billing:
        return 'warning'
      case TenantAnnouncementType.TENANT_FINANCE:
        return 'warning'
      case TenantAnnouncementType.Operation:
      case TenantAnnouncementType.SYSTEM_PLATFORM_UPDATE:
        return 'info'
      case TenantAnnouncementType.TENANT_INTERNAL:
      case TenantAnnouncementType.TENANT_OPERATION:
        return 'success'
      default:
        return 'info'
    }
  })

  const priorityValue = computed(() => {
    // 1. 解析优先级数值
    const value = Number(announcementData.value.priority)
    return Number.isFinite(value) ? value : null
  })

  const priorityText = computed(() => {
    // 1. 输出优先级文案
    if (priorityValue.value === null) {
      return t('announcement.preview.priorityUnknown')
    }

    return t('announcement.preview.priorityTag', { level: priorityValue.value })
  })

  const priorityTagType = computed(() => {
    // 1. 根据数值区间标识优先级
    if (priorityValue.value === null) {
      return 'info'
    }

    if (priorityValue.value >= 8) {
      return 'danger'
    }

    if (priorityValue.value >= 5) {
      return 'warning'
    }

    if (priorityValue.value >= 3) {
      return 'info'
    }

    return 'success'
  })

  // 5. 预览宽度计算与写入
  const resolveMaxWidth = () => {
    // 1. 读取容器宽度并扣除编辑区最小值
    const rect = rootRef.value?.getBoundingClientRect()
    if (!rect) {
      return PREVIEW_MAX_WIDTH
    }

    const maxByContainer = rect.width - EDITOR_MIN_WIDTH
    return Math.min(PREVIEW_MAX_WIDTH, Math.max(PREVIEW_MIN_WIDTH, maxByContainer))
  }

  const applyPreviewWidth = (value: number) => {
    // 1. 计算限制后的宽度
    const maxWidth = resolveMaxWidth()
    const nextWidth = Math.min(Math.max(value, PREVIEW_MIN_WIDTH), maxWidth)

    // 2. 写入 CSS 变量并同步缓存
    previewWidth.value = nextWidth
    rootRef.value?.style.setProperty('--preview-width', `${nextWidth}px`)
  }

  // 6. 拖拽调整宽度
  const handleResizeStart = (event: PointerEvent) => {
    // 1. 仅在分栏模式启用拖拽
    if (!isSplitMode.value) return

    // 2. 阻止选中文本
    event.preventDefault()

    // 3. 初始化拖拽状态
    isResizing.value = true
    const startX = event.clientX
    const startWidth = previewWidth.value

    // 4. 绑定全局拖拽监听
    const handleResizeMove = (moveEvent: PointerEvent) => {
      // 1. 计算拖拽偏移量
      const deltaX = startX - moveEvent.clientX
      const nextWidth = startWidth + deltaX

      // 2. 更新预览宽度
      applyPreviewWidth(nextWidth)
    }

    const handleResizeEnd = () => {
      // 1. 清理拖拽状态与监听
      isResizing.value = false
      window.removeEventListener('pointermove', handleResizeMove)
      window.removeEventListener('pointerup', handleResizeEnd)
    }

    window.addEventListener('pointermove', handleResizeMove)
    window.addEventListener('pointerup', handleResizeEnd)
  }

  // 7. 响应式监听与清理
  watch(isSplitMode, (value) => {
    // 1. 切回分栏时重置预览宽度
    if (value) {
      applyPreviewWidth(previewWidth.value)
      return
    }

    // 2. 切换到抽屉时关闭预览
    drawerVisible.value = false
  })

  watch(width, () => {
    // 1. 窗口变化时校正预览宽度
    if (isSplitMode.value) {
      applyPreviewWidth(previewWidth.value)
    }
  })

  onMounted(() => {
    // 1. 初始化默认宽度
    applyPreviewWidth(previewWidth.value)
  })

  onBeforeUnmount(() => {
    // 1. 清理拖拽状态
    isResizing.value = false
  })
</script>

<style scoped>
  .announcement-preview {
    --preview-width: 380px;
  }

  .preview-aside {
    width: var(--preview-width);
  }

  .preview-resizer {
    @apply relative w-2 shrink-0 cursor-col-resize;
  }

  .preview-resizer::before {
    content: '';

    @apply absolute left-1/2 top-2 h-[calc(100%-16px)] w-px -translate-x-1/2 bg-[var(--el-border-color)];
  }

  .announcement-preview.is-resizing {
    @apply cursor-col-resize select-none;
  }

  .announcement-preview__content :deep(p) {
    @apply mb-3 last:mb-0;
  }

  .announcement-preview__content :deep(ul) {
    @apply mb-3 list-inside list-disc;
  }

  .announcement-preview__content :deep(ol) {
    @apply mb-3 list-inside list-decimal;
  }

  .announcement-preview__content :deep(h1),
  .announcement-preview__content :deep(h2),
  .announcement-preview__content :deep(h3) {
    @apply mb-2 text-base font-semibold text-[var(--el-text-color-primary)];
  }
</style>
