<script lang="ts" setup>
/**
 * @deprecated 工作台公告已改用单行轮播条 NoticeTicker.vue（列表卡占一整列空间浪费），
 * 本组件不再被布局引用，保留文件仅供回滚参考，勿再新增引用
 *
 * 最新动态（Premium）：紧凑公告列表，tinted 图标 + 类型 pill + 点击弹详情
 * 类型为什么前端推导：announcement/latest（xk_notice 表）没有类型字段，
 * 按标题关键词映射出「更新/活动/维护/公告」纯展示标签，后端无需改动
 * 详情为什么不请求接口：latest 已全量返回 content，点击直接弹层展示即可
 */
import { computed, onMounted, ref } from 'vue';

import { useVbenModal } from '@vben/common-ui';
import { IconifyIcon as VbenIcon } from '@vben/icons';

import { getLatestNotice } from '#/views/system/notice/api';

interface Props {
  title: string;
}
defineProps<Props>();

/** 公告项（announcement/latest 返回结构） */
type NoticeItem = {
  avatar: string;
  content: string;
  date: string;
  title: string;
};

/** 展示用公告项：附加前端推导的类型标签 */
type DisplayNoticeItem = NoticeItem & {
  typeLabel: string;
  typeTone: 'danger' | 'info' | 'primary' | 'warning';
};

/**
 * 按标题关键词推导公告类型（纯前端展示，后端无类型字段）
 * 顺序：维护类优先（最需要注意）→ 更新 → 活动 → 默认公告
 */
function resolveNoticeType(title: string): Pick<DisplayNoticeItem, 'typeLabel' | 'typeTone'> {
  const t = title || '';
  if (/维护|停机|故障/.test(t)) return { typeLabel: '维护', typeTone: 'danger' };
  if (/更新|升级|版本|上线/.test(t)) return { typeLabel: '更新', typeTone: 'info' };
  if (/活动|福利|优惠|节/.test(t)) return { typeLabel: '活动', typeTone: 'warning' };
  return { typeLabel: '公告', typeTone: 'primary' };
}

const items = ref<DisplayNoticeItem[]>([]);
/** 当前弹层展示的公告 */
const activeItem = ref<DisplayNoticeItem | null>(null);

/** 公告详情弹层：只读展示，关闭默认页脚按钮 */
const [DetailModal, detailModalApi] = useVbenModal({
  footer: false,
  header: false,
  closable: true,
  class: 'w-[560px]',
});

/**
 * 拉取最新公告并附加类型标签；失败静默展示空态
 */
async function fetchLatest() {
  try {
    const res = await getLatestNotice(10);
    const list: NoticeItem[] = Array.isArray(res) ? res : [];
    items.value = list.map((it) => ({ ...it, ...resolveNoticeType(it.title) }));
  } catch {
    items.value = [];
  }
}

/**
 * 点击公告行：打开详情弹层（content 已全量在手，无需再请求）
 */
function openDetail(item: DisplayNoticeItem) {
  activeItem.value = item;
  detailModalApi.open();
}

/** 弹层类型 pill 的 tone class（避免模板里拼接字符串） */
const activeToneClass = computed(() =>
  activeItem.value ? `pill--${activeItem.value.typeTone}` : '',
);

onMounted(fetchLatest);
</script>

<template>
  <div class="notice-widget">
    <div class="notice-widget__title-wrap">
      <span class="notice-widget__title-bar"></span>
      <span class="notice-widget__title">{{ title }}</span>
    </div>
    <ul v-if="items.length > 0" class="notice-widget__list">
      <li
        v-for="item in items"
        :key="item.title + item.date"
        class="notice-widget__item"
        role="button"
        tabindex="0"
        @click="openDetail(item)"
        @keydown.enter="openDetail(item)"
      >
        <span class="notice-widget__icon-box">
          <VbenIcon
            :icon="item.avatar || 'lucide:megaphone'"
            class="notice-widget__icon"
          />
        </span>
        <div class="notice-widget__body">
          <div class="notice-widget__item-head">
            <span class="pill" :class="`pill--${item.typeTone}`">
              {{ item.typeLabel }}
            </span>
            <span class="notice-widget__item-title">{{ item.title }}</span>
          </div>
          <!-- 公告内容后端可控，沿用原工作台渲染方式 -->
          <!-- eslint-disable-next-line vue/no-v-html -->
          <div class="notice-widget__content" v-html="item.content"></div>
        </div>
        <span class="notice-widget__date">{{ item.date }}</span>
      </li>
    </ul>
    <div v-else class="notice-widget__empty">
      <VbenIcon class="notice-widget__empty-icon" icon="lucide:inbox" />
      暂无公告
    </div>

    <!-- 公告详情弹层：premium 风格 hero 头 + 富文本正文 -->
    <DetailModal>
      <div v-if="activeItem" class="notice-detail">
        <div class="notice-detail__hero">
          <span class="notice-detail__hero-icon">
            <VbenIcon :icon="activeItem.avatar || 'lucide:megaphone'" />
          </span>
          <div class="notice-detail__hero-meta">
            <div class="notice-detail__hero-top">
              <span class="pill" :class="activeToneClass">
                {{ activeItem.typeLabel }}
              </span>
              <span class="notice-detail__date">{{ activeItem.date }}</span>
            </div>
            <div class="notice-detail__title">{{ activeItem.title }}</div>
          </div>
        </div>
        <!-- 公告内容后端可控，沿用列表同源富文本渲染 -->
        <!-- eslint-disable-next-line vue/no-v-html -->
        <div class="notice-detail__content" v-html="activeItem.content"></div>
      </div>
    </DetailModal>
  </div>
</template>

<style scoped>
.notice-widget {
  padding: 18px 20px;
  background: hsl(var(--card));
  border: 1px solid hsl(var(--border) / 0.7);
  border-radius: 12px;
}

.notice-widget__title-wrap {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-bottom: 8px;
}

.notice-widget__title-bar {
  width: 3px;
  height: 14px;
  background: linear-gradient(180deg, hsl(var(--primary)), hsl(var(--primary) / 0.4));
  border-radius: 2px;
}

.notice-widget__title {
  font-size: 15px;
  font-weight: 650;
  color: hsl(var(--foreground));
  letter-spacing: -0.01em;
}

.notice-widget__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.notice-widget__item {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  margin: 0 -10px;
  padding: 10px;
  border-radius: 10px;
  cursor: pointer;
  outline: none;
  transition: background-color 0.15s ease;
}

.notice-widget__item:hover,
.notice-widget__item:focus-visible {
  background: hsl(var(--muted) / 0.4);
}

.notice-widget__item + .notice-widget__item {
  border-top: 1px solid hsl(var(--border) / 0.5);
}

.notice-widget__icon-box {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  margin-top: 1px;
  background: hsl(var(--primary) / 0.09);
  border-radius: 9px;
  flex-shrink: 0;
}

.notice-widget__icon {
  width: 15px;
  height: 15px;
  color: hsl(var(--primary));
}

.notice-widget__body {
  flex: 1;
  min-width: 0;
}

.notice-widget__item-head {
  display: flex;
  gap: 6px;
  align-items: center;
  min-width: 0;
}

.notice-widget__item-title {
  overflow: hidden;
  font-size: 13px;
  font-weight: 550;
  color: hsl(var(--foreground));
  text-overflow: ellipsis;
  white-space: nowrap;
}

.notice-widget__content {
  overflow: hidden;
  margin-top: 2px;
  font-size: 12px;
  color: hsl(var(--muted-foreground));
  text-overflow: ellipsis;
  white-space: nowrap;
}

.notice-widget__content :deep(a) {
  color: hsl(var(--primary));
}

.notice-widget__date {
  margin-top: 2px;
  font-size: 12px;
  color: hsl(var(--muted-foreground) / 0.8);
  white-space: nowrap;
  flex-shrink: 0;
}

.notice-widget__empty {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
  padding: 28px 0;
  font-size: 13px;
  color: hsl(var(--muted-foreground));
}

.notice-widget__empty-icon {
  width: 22px;
  height: 22px;
  color: hsl(var(--muted-foreground) / 0.6);
}

/* ===== 类型 pill：主题变量着色，亮/暗自适应 ===== */
.pill {
  flex-shrink: 0;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  line-height: 16px;
}

.pill--primary {
  background: hsl(var(--primary) / 0.1);
  color: hsl(var(--primary));
}

.pill--info {
  background: hsl(210 90% 50% / 0.12);
  color: hsl(210 90% 45%);
}

.pill--warning {
  background: hsl(var(--warning, 38 92% 50%) / 0.14);
  color: hsl(var(--warning, 38 92% 40%));
}

.pill--danger {
  background: hsl(var(--destructive) / 0.1);
  color: hsl(var(--destructive));
}

/* ===== 详情弹层 ===== */
.notice-detail {
  padding: 4px 2px 8px;
}

/* hero 头：柔和主色光斑背景，呼应消息详情场景弹层的 premium 语言 */
.notice-detail__hero {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  margin-bottom: 16px;
  padding: 16px 18px;
  border: 1px solid hsl(var(--border));
  border-radius: 14px;
  background:
    radial-gradient(
      80% 120% at 0% 0%,
      hsl(var(--primary) / 0.14),
      transparent 60%
    ),
    linear-gradient(
      165deg,
      hsl(var(--muted) / 0.4),
      hsl(var(--card, var(--background)))
    );
}

.notice-detail__hero-icon {
  display: grid;
  flex-shrink: 0;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 12px;
  background: hsl(var(--primary) / 0.12);
  color: hsl(var(--primary));
}

.notice-detail__hero-icon :deep(svg) {
  width: 20px;
  height: 20px;
}

.notice-detail__hero-meta {
  flex: 1;
  min-width: 0;
}

.notice-detail__hero-top {
  display: flex;
  gap: 8px;
  align-items: center;
}

.notice-detail__date {
  font-size: 12px;
  color: hsl(var(--muted-foreground));
}

.notice-detail__title {
  margin-top: 6px;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: hsl(var(--foreground));
  overflow-wrap: break-word;
}

.notice-detail__content {
  max-height: 52vh;
  overflow-y: auto;
  padding: 0 2px;
  font-size: 13.5px;
  line-height: 1.75;
  color: hsl(var(--foreground) / 0.88);
  overflow-wrap: break-word;
}

.notice-detail__content :deep(a) {
  color: hsl(var(--primary));
}

.notice-detail__content :deep(img) {
  max-width: 100%;
  border-radius: 10px;
}

@media (prefers-reduced-motion: reduce) {
  .notice-widget__item {
    transition: none;
  }
}
</style>
