<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref, watch } from "vue";
import {
  WarningFilled,
  Close,
  Bell,
  UploadFilled,
  CircleCheckFilled,
  CircleCloseFilled,
  Loading
} from "@element-plus/icons-vue";
import { useAlertMarquee, type AlertMessage } from "@/composables/useAlertMarquee";
import { useImportTaskStore, type ImportTask } from "@/store/importTasks";
import { useAppStore } from "@/store";
import { useFloatingDrag } from "@/composables/useFloatingDrag";

const {
  messages,
  messagesReversed,
  latestMessage,
  messageCount,
  hasMessages,
  latestDangerMessage,
  dangerCount,
  hasDangerMessages,
  drawerVisible,
  detailTarget,
  detailVisible,
  position,
  showDetail,
  closeDetail,
  removeAlert,
  clearAll,
  startPolling,
  stopPolling
} = useAlertMarquee();

const importStore = useImportTaskStore();

// ---- 悬浮滚动条拖拽 ----

const scrollbarRef = ref<HTMLElement | null>(null);

const { isDragging, dragMoved, onPointerDown } = useFloatingDrag(position, scrollbarRef);

// ---- 滚动条手动关闭后，有新通知时自动弹出 ----

const scrollbarDismissed = ref(false);

function dismissScrollbar(): void {
  scrollbarDismissed.value = true;
}

function onViewDetail(): void {
  if (latestDangerMessage.value) {
    showDetail(latestDangerMessage.value);
  }
}

// 监听紧急通知数量变化：有新紧急通知时重新显示滚动条
watch(dangerCount, (now, prev) => {
  if (now > prev) {
    scrollbarDismissed.value = false;
  }
});

// 紧急通知全部清空/过期后，重置 scrollbar 状态，确保不会残留
watch(hasDangerMessages, (val) => {
  if (!val) {
    scrollbarDismissed.value = true;
  }
});

const appStore = useAppStore();
const showScrollbar = computed(() => appStore.state.appIsLogin && hasDangerMessages.value && !scrollbarDismissed.value);

// ---- 拖拽时跳过按钮点击 ----

const INTERACTIVE_SEL = "button, a, [role=button]";

function onScrollbarPointerDown(e: PointerEvent): void {
  if (e.target instanceof HTMLElement && e.target.closest(INTERACTIVE_SEL)) return;
  onPointerDown(e);
}

// ---- 初始位置 ----

const initialized = ref(false);

function initPosition(): void {
  if (initialized.value) return;
  initialized.value = true;
  if (position.value.x === 0 && position.value.y === 0) {
    position.value = {
      x: (window.innerWidth - 640) / 2,
      y: 56
    };
  }
}

// ---- 窗口大小变化时钳制位置 ----

function clampPosition(): void {
  const w = 640;
  const h = 43;
  position.value = {
    x: Math.max(0, Math.min(position.value.x, window.innerWidth - w)),
    y: Math.max(52, Math.min(position.value.y, window.innerHeight - h - 20))
  };
}

// ---- 窗口 resize 时保持居中 ----

function recenter(): void {
  const w = 640;
  position.value = {
    x: (window.innerWidth - w) / 2,
    y: position.value.y
  };
}

onMounted(() => {
  startPolling(30000);
  initPosition();
  window.addEventListener("resize", recenter);
});

onUnmounted(() => {
  stopPolling();
  window.removeEventListener("resize", recenter);
});

// ---- 位置样式 ----

const positionStyle = computed(() => ({
  left: position.value.x + "px",
  top: position.value.y + "px"
}));

// ---- 统一时间线：警告 + 导入任务，按时间倒序 ----

type TimelineItem =
  | { kind: "alert"; data: AlertMessage; ts: string }
  | { kind: "import"; data: ImportTask; ts: number };

const timeline = computed<TimelineItem[]>(() => {
  const items: TimelineItem[] = [];

  for (const msg of messages.value) {
    items.push({ kind: "alert", data: msg, ts: msg.publishTime });
  }

  for (const task of importStore.recentTasks) {
    items.push({ kind: "import", data: task, ts: task.createdAt });
  }

  // 按时间倒序：alert 用 publishTime 字符串不好比，放前面；
  // import 用 createdAt 数字好排序
  items.sort((a, b) => {
    const ta = a.kind === "import" ? (a.data as ImportTask).createdAt : 0;
    const tb = b.kind === "import" ? (b.data as ImportTask).createdAt : 0;
    // alert 没有精确时间戳，统一用 0 兜底；实际排序以 createdAt 为主
    return tb - ta;
  });

  return items;
});

const hasTimeline = computed(() => timeline.value.length > 0);

// ---- 级别标签类型映射 ----

function tagType(level: string): "info" | "warning" | "danger" {
  if (level === "danger") return "danger";
  if (level === "warning") return "warning";
  return "info";
}

// ---- 导入任务状态辅助 ----

function importStatusText(status: ImportTask["status"]): string {
  const map: Record<string, string> = {
    pending: "等待中",
    uploading: "上传中",
    processing: "处理中",
    success: "已完成",
    error: "失败"
  };
  return map[status] ?? status;
}

function importProgressPercent(task: ImportTask): number {
  if (task.totalRows <= 0) return 0;
  return Math.round((task.processedRows / task.totalRows) * 100);
}

function formatImportTime(ts: number): string {
  const d = new Date(ts);
  return d.toLocaleTimeString("zh-CN", { hour12: false });
}

// ---- 清空全部（仅清空警告，导入任务由各自逻辑管理） ----

function handleClearAll(): void {
  clearAll();
  importStore.clearCompleted();
}
</script>

<template>
  <!-- ===== 悬浮滚动条（仅展示最新警告） ===== -->
  <div
    v-show="showScrollbar"
    ref="scrollbarRef"
    class="alert-scrollbar"
    :class="{ 'is-dragging': isDragging }"
    :style="positionStyle"
    role="alert"
    aria-live="assertive"
    @pointerdown="onScrollbarPointerDown"
  >
    <span class="alert-scrollbar__icon">
      <el-icon :size="16"><WarningFilled /></el-icon>
    </span>
    <div class="alert-scrollbar__text-wrap">
      <span
        class="alert-scrollbar__text"
        :class="{ 'is-scroll': latestDangerMessage && latestDangerMessage.content.length > 60 }"
      >{{ latestDangerMessage?.content ?? "" }}</span>
    </div>
    <span class="alert-scrollbar__badge">{{ dangerCount }}</span>
    <button class="alert-scrollbar__btn-detail" @click.stop="onViewDetail">查看详情</button>
    <button class="alert-scrollbar__btn-close" @click.stop="dismissScrollbar">关闭</button>
  </div>

  <!-- ===== 通知中心抽屉 ===== -->
  <el-drawer
    v-model="drawerVisible"
    direction="rtl"
    size="420px"
    :with-header="true"
  >
    <template #header>
      <div class="drawer-header">
        <span class="drawer-header__title">
          <el-icon :size="18"><Bell /></el-icon>
          通知中心
        </span>
        <el-button
          v-if="hasTimeline"
          text
          type="danger"
          size="small"
          @click="handleClearAll"
        >
          清空全部
        </el-button>
      </div>
    </template>

    <!-- 统一时间线 -->
    <div v-if="hasTimeline" class="drawer-list">
      <template v-for="item in timeline" :key="item.kind === 'alert' ? item.data.id : item.data.id">
        <!-- ===== 警告消息 ===== -->
        <div
          v-if="item.kind === 'alert'"
          class="drawer-item drawer-item--clickable"
          @click="showDetail(item.data)"
        >
          <div class="drawer-item__left">
            <span class="drawer-item__dot" :class="'dot--' + item.data.level"></span>
            <div class="drawer-item__body">
              <p class="drawer-item__content">{{ item.data.content }}</p>
              <span class="drawer-item__time">{{ item.data.publishTime }}</span>
            </div>
          </div>
          <button
            class="drawer-item__close"
            title="移除"
            @click.stop="removeAlert(item.data.id)"
          >
            <el-icon :size="12"><Close /></el-icon>
          </button>
        </div>

        <!-- ===== 导入任务 ===== -->
        <div
          v-else
          class="drawer-item drawer-item--import"
        >
          <div class="drawer-item__left">
            <!-- 状态图标 -->
            <span class="drawer-item__import-icon" :class="'import--' + item.data.status">
              <el-icon :size="16">
                <CircleCheckFilled v-if="item.data.status === 'success'" />
                <CircleCloseFilled v-else-if="item.data.status === 'error'" />
                <Loading v-else />
              </el-icon>
            </span>
            <div class="drawer-item__body">
              <p class="drawer-item__content">
                {{ item.data.fileName }}
                <span class="import-status-tag" :class="'import-status--' + item.data.status">
                  {{ importStatusText(item.data.status) }}
                </span>
              </p>
              <!-- 进度条（仅处理中显示） -->
              <div
                v-if="item.data.status === 'processing' && item.data.totalRows > 0"
                class="import-progress"
              >
                <el-progress
                  :percentage="importProgressPercent(item.data)"
                  :stroke-width="4"
                  :show-text="true"
                />
              </div>
              <!-- 失败消息 -->
              <p
                v-if="item.data.status === 'error' && item.data.message"
                class="import-error-msg"
              >{{ item.data.message }}</p>
              <span class="drawer-item__time">{{ formatImportTime(item.data.createdAt) }}</span>
            </div>
          </div>
          <!-- 仅已完成/失败的任务可关闭 -->
          <button
            v-if="item.data.status === 'success' || item.data.status === 'error'"
            class="drawer-item__close"
            title="移除"
            @click.stop="importStore.removeTask(item.data.id)"
          >
            <el-icon :size="12"><Close /></el-icon>
          </button>
        </div>
      </template>
    </div>

    <!-- 空状态 -->
    <div v-else class="drawer-empty">
      <el-icon :size="48" color="#c0c4cc"><Bell /></el-icon>
      <p>暂无通知</p>
    </div>
  </el-drawer>

  <!-- ===== 详情弹窗（仅警告消息） ===== -->
  <el-dialog
    v-model="detailVisible"
    title="通知详情"
    width="520px"
    :close-on-click-modal="true"
    destroy-on-close
  >
    <template v-if="detailTarget">
      <div class="detail-level">
        <el-tag :type="tagType(detailTarget.level)" size="small">
          {{ detailTarget.level === "danger" ? "紧急" : detailTarget.level === "warning" ? "警告" : "提示" }}
        </el-tag>
      </div>
      <div class="detail-time">
        发布时间：{{ detailTarget.publishTime }}
      </div>
      <div class="detail-content">
        {{ detailTarget.content }}
      </div>
    </template>
    <template #footer>
      <el-button @click="closeDetail">关闭</el-button>
    </template>
  </el-dialog>
</template>

<style scoped>
/* ================================================
   悬浮滚动条
   ================================================ */
.alert-scrollbar {
  position: fixed;
  z-index: 1990;
  display: flex;
  align-items: center;
  gap: 10px;
  height: 43px;
  width: 640px;
  max-width: calc(100vw - 32px);
  padding: 0 14px;
  background: rgba(245, 108, 108, 0.85);
  border-radius: 18px;
  box-shadow: 0 2px 10px rgba(245, 108, 108, 0.35);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  cursor: pointer;
  user-select: none;
  touch-action: none;
  transition: opacity 0.2s, box-shadow 0.2s;
}

.alert-scrollbar:hover {
  box-shadow: 0 4px 16px rgba(245, 108, 108, 0.5);
}

.alert-scrollbar.is-dragging {
  opacity: 0.7;
  transition: none !important;
  cursor: grabbing;
}

.alert-scrollbar__icon {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  color: #fff;
}

.alert-scrollbar__text-wrap {
  flex: 1;
  overflow: hidden;
  white-space: nowrap;
  min-width: 0;
}

.alert-scrollbar__text {
  display: inline-block;
  white-space: nowrap;
  font-size: 12px;
  color: #fff;
  line-height: 43px;
}

.alert-scrollbar__text.is-scroll {
  animation: scrollbar-marquee 20s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .alert-scrollbar__text.is-scroll {
    animation: none;
  }
}

@keyframes scrollbar-marquee {
  0%   { transform: translateX(0); }
  80%  { transform: translateX(calc(-100% + 530px)); }
  100% { transform: translateX(calc(-100% + 530px)); }
}

.alert-scrollbar__badge {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.3);
  color: #fff;
  font-size: 11px;
  font-weight: 600;
  line-height: 1;
}

.alert-scrollbar__btn-detail,
.alert-scrollbar__btn-close {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  height: 26px;
  padding: 0 10px;
  border: none;
  border-radius: 13px;
  font-size: 12px;
  cursor: pointer;
  transition: background 0.15s;
  white-space: nowrap;
}

.alert-scrollbar__btn-detail {
  background: rgba(255, 255, 255, 0.25);
  color: #fff;
  margin-left: 4px;
}

.alert-scrollbar__btn-detail:hover {
  background: rgba(255, 255, 255, 0.4);
}

.alert-scrollbar__btn-close {
  background: rgba(0, 0, 0, 0.15);
  color: rgba(255, 255, 255, 0.85);
}

.alert-scrollbar__btn-close:hover {
  background: rgba(0, 0, 0, 0.3);
  color: #fff;
}

/* ================================================
   通知中心抽屉
   ================================================ */
.drawer-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
}

.drawer-header__title {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 16px;
  font-weight: 600;
}

.drawer-list {
  display: flex;
  flex-direction: column;
}

/* 基础条目 */
.drawer-item {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
  padding: 12px 0;
  border-bottom: 1px solid #ebeef5;
  transition: background 0.15s;
}

.drawer-item--clickable {
  cursor: pointer;
}

.drawer-item--clickable:hover {
  background: #f5f7fa;
  margin: 0 -20px;
  padding-left: 20px;
  padding-right: 20px;
}

.drawer-item__left {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  flex: 1;
  min-width: 0;
}

/* 警告色点 */
.drawer-item__dot {
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-top: 6px;
}

.dot--danger  { background: #f56c6c; }
.dot--warning { background: #e6a23c; }
.dot--info    { background: #409eff; }

/* 导入状态图标 */
.drawer-item__import-icon {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  margin-top: 2px;
}

.import--success  { color: #67c23a; }
.import--error    { color: #f56c6c; }
.import--uploading,
.import--processing,
.import--pending  { color: #409eff; }

.drawer-item__body {
  flex: 1;
  min-width: 0;
}

.drawer-item__content {
  margin: 0;
  font-size: 13px;
  color: #303133;
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* 导入状态标签 */
.import-status-tag {
  display: inline-block;
  margin-left: 6px;
  font-size: 11px;
  vertical-align: middle;
}

.import-status--uploading,
.import-status--processing,
.import-status--pending { color: #409eff; }
.import-status--success { color: #67c23a; }
.import-status--error   { color: #f56c6c; }

/* 导入进度条 */
.import-progress {
  margin-top: 6px;
}

/* 导入失败消息 */
.import-error-msg {
  margin: 4px 0 0;
  font-size: 12px;
  color: #f56c6c;
  line-height: 1.4;
}

.drawer-item__time {
  display: block;
  margin-top: 4px;
  font-size: 11px;
  color: #909399;
}

.drawer-item__close {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  margin-top: 2px;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: #c0c4cc;
  cursor: pointer;
  transition: all 0.15s;
}

.drawer-item__close:hover {
  background: #f56c6c;
  color: #fff;
}

.drawer-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 60px 0;
  color: #c0c4cc;
  font-size: 14px;
  gap: 12px;
}

/* ================================================
   详情弹窗
   ================================================ */
.detail-level {
  margin-bottom: 8px;
}

.detail-time {
  font-size: 12px;
  color: #909399;
  margin-bottom: 16px;
}

.detail-content {
  font-size: 14px;
  color: #303133;
  line-height: 1.7;
  white-space: pre-wrap;
  word-break: break-all;
}
</style>
