<script setup lang="ts">
/**
 * 通知详情页（路由 /notice/detail/:id）
 * 与收件箱 / 场景弹窗同一套视觉语言：氛围渐变 + hero 卡片 + 主题变量配色（全量适配暗色）
 * 保留原有逻辑：VIP content JSON 解析、未读人员名单、Markdown/富文本双渲染
 */
import { computed, onMounted, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';

import { Page, useVbenModal } from '@vben/common-ui';
import { useTabs } from '@vben/hooks';
import { usePreferences } from '@vben/preferences';

import {
  ArrowLeft,
  Bell,
  CalendarClock,
  Clock,
  Crown,
  Megaphone,
  User,
  Users,
} from 'lucide-vue-next';
import { MdPreview } from 'md-editor-v3';

import { Icon } from '#/components/icon';
import VipBadgeCombo from '#/components/vip/VipBadgeCombo.vue';
import { formatTimeToRelative } from '#/util/tool';
import { getNoticeDetailApi } from '#/views/notice/api';

import UnreadUserList from './UnreadUserList.vue';

// eslint-disable-next-line n/no-extraneous-import
import 'md-editor-v3/lib/style.css';

const router = useRouter();
const route = useRoute();
const noticeId = ref(route.params.id);

const notice = ref<Record<string, any> | null>(null);
const loading = ref(true);
const error = ref<null | string>(null);

const { setTabTitle } = useTabs();
/** Markdown 预览主题必须跟随系统亮/暗切换，不能写死 dark */
const { isDark } = usePreferences();
const mdTheme = computed(() => (isDark.value ? 'dark' : 'light'));

/**
 * 消息类型定义（含 VIP 通知 type=3）
 * tone 为 HSL 三元组字符串，通过 CSS 变量注入，亮暗两种主题下均有足够对比度
 */
const messageTypes = [
  { id: 0, name: '系统公告', icon: Megaphone, tone: '199 89% 48%' },
  { id: 1, name: '系统通知', icon: Bell, tone: '38 92% 50%' },
  { id: 2, name: '周报提醒', icon: CalendarClock, tone: '160 60% 40%' },
  { id: 3, name: 'VIP通知', icon: Crown, tone: '258 70% 60%' },
];

/** 当前通知的类型信息（默认回落到系统公告） */
const typeInfo = computed(() => {
  const typeId = Number(notice.value?.type);
  return messageTypes.find((t) => t.id === typeId) || messageTypes[0];
});

/** 解析 VIP 站内信 content JSON */
const vipContent = computed(() => {
  if (!notice.value || Number(notice.value.type) !== 3) return null;
  const raw = notice.value.content;
  if (!raw) return null;
  if (typeof raw === 'object') return raw;
  try {
    return JSON.parse(raw);
  } catch {
    return null;
  }
});

const vipSceneLabel = computed(() => {
  const type = vipContent.value?.type;
  if (type === 'vip_open_success') return '开通成功';
  if (type === 'vip_expiring') return '即将到期';
  if (type === 'vip_expired') return '已到期';
  return 'VIP通知';
});

/** 获取通知详情，成功后同步 Tab 标题 */
const getNoticeDetail = async () => {
  loading.value = true;
  error.value = null;

  try {
    const res = await getNoticeDetailApi(noticeId.value);
    notice.value = res;
    setTabTitle(`通知详情-【${res.id}】`);
    loading.value = false;
  } catch (error_) {
    console.error('获取通知详情失败:', error_);
    error.value = '获取通知详情失败，请稍后重试';
    loading.value = false;
  }
};

const goBack = () => {
  router.push('/notice');
};

/** 富文本内容换行符转 <br>（后端存的是纯文本换行） */
const formatContent = (content: string) => {
  return content ? content.replaceAll('\n', '<br>') : '';
};

onMounted(() => {
  getNoticeDetail();
});

const [UnreadUserListModal, UnreadUserListModalApi] = useVbenModal({
  connectedComponent: UnreadUserList,
});

const showUnreadList = () => {
  UnreadUserListModalApi.setData({
    values: notice.value?.user_list,
    unread_count: notice.value?.unread_count,
  });
  UnreadUserListModalApi.open();
};
</script>

<template>
  <Page auto-content-height content-class="!p-0">
    <UnreadUserListModal />
    <div class="notice-detail" :style="{ '--tone': typeInfo.tone }">
      <!-- 顶部氛围渐变：跟消息类型色走 -->
      <div class="detail-atmosphere" aria-hidden="true"></div>

      <div class="detail-wrap">
        <!-- 顶栏：返回 + 页面标识 -->
        <header class="detail-topbar">
          <button type="button" class="back-btn" aria-label="返回列表" @click="goBack">
            <ArrowLeft class="size-4" />
            <span>消息</span>
          </button>
        </header>

        <!-- 加载状态 -->
        <div v-if="loading" class="state-box">
          <div class="state-spinner"></div>
          <p>正在加载通知…</p>
        </div>

        <!-- 错误状态 -->
        <div v-else-if="error" class="state-box is-error">
          <p>{{ error }}</p>
          <button type="button" class="retry-btn" @click="getNoticeDetail">重试</button>
        </div>

        <!-- 通知详情 -->
        <template v-else-if="notice">
          <!-- Hero：类型徽标 + 标题 + 元信息 -->
          <section class="hero-card">
            <div class="hero-kicker">
              <span class="type-pill">
                <component :is="typeInfo.icon" class="size-3.5" />
                {{ typeInfo.name }}
              </span>
              <time class="hero-time">
                <Clock class="size-3.5" />
                {{ notice.created_at }} · {{ formatTimeToRelative(notice.created_at) }}
              </time>
            </div>
            <h1 class="hero-title">{{ notice.title }}</h1>
            <p v-if="notice.detail" class="hero-desc">{{ formatContent(notice.detail).replaceAll('<br>', ' ') }}</p>
            <div class="hero-meta">
              <span class="meta-chip">
                <Icon icon="svg:logo" />
                萧康云医
              </span>
              <span class="meta-chip">
                <User class="size-3.5" />
                {{ notice.admin?.nick_name || '系统' }}
              </span>
            </div>
          </section>

          <!-- VIP 通知：解析 content JSON，展示时效徽标 + 等级徽标 -->
          <section v-if="vipContent" class="body-card vip-card">
            <div class="vip-scene">{{ vipSceneLabel }}</div>
            <div class="vip-main">
              <VipBadgeCombo
                size="lg"
                :badge-url="vipContent.badge_url"
                :duration-badge-url="vipContent.duration_badge_url"
                :level-name="vipContent.level_name"
                :duration-label="vipContent.duration_label"
              />
              <div class="vip-info">
                <div class="vip-line">
                  {{ vipContent.duration_label || '-' }} · {{ vipContent.level_name || '-' }}（{{ vipContent.level_code || '-' }}）
                </div>
                <div class="vip-line is-sub">门店：{{ vipContent.store_name || '-' }}</div>
              </div>
            </div>
            <div class="vip-price">
              原价 ¥{{ vipContent.original_price || '0.00' }}
              · 实付 ¥{{ vipContent.pay_amount || '0.00' }}
            </div>
          </section>

          <!-- 富文本 / Markdown 内容 -->
          <section v-else class="body-card">
            <div
              v-if="notice.edit_type === 0"
              class="prose prose-sm dark:prose-invert content-text max-w-none"
              v-html="formatContent(notice.content)"
            ></div>
            <MdPreview
              v-else-if="notice.edit_type === 1"
              :model-value="String(notice.content || '')"
              :theme="mdTheme"
              class="md-body"
            />
          </section>

          <!-- 底部操作 -->
          <footer class="detail-actions">
            <button type="button" class="ghost-btn" @click="goBack">
              <ArrowLeft class="size-4" />
              返回列表
            </button>
            <button
              v-if="notice.is_my === 1"
              type="button"
              class="ghost-btn"
              :class="{ 'is-accent': notice.is_all_read !== 1 }"
              @click="showUnreadList"
            >
              <Users class="size-4" />
              {{
                notice.is_all_read === 1
                  ? '全部已读'
                  : `有 ${notice.unread_count} 人未读`
              }}
            </button>
          </footer>
        </template>

        <!-- 通知不存在 -->
        <div v-else class="state-box">
          <div class="state-ico">
            <Bell class="size-7" />
          </div>
          <p class="state-title">通知不存在</p>
          <p>该通知可能已被删除或您没有权限查看</p>
          <button type="button" class="retry-btn" @click="goBack">返回通知列表</button>
        </div>
      </div>
    </div>
  </Page>
</template>

<style scoped>
.notice-detail {
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  position: relative;
  min-height: 100%;
  padding: 24px 20px 48px;
  overflow: hidden;
}

/* 顶部氛围渐变：按消息类型色晕染，暗色下同样成立（低透明度） */
.detail-atmosphere {
  pointer-events: none;
  position: absolute;
  inset: 0 0 auto 0;
  height: 240px;
  background:
    radial-gradient(55% 90% at 15% 0%, hsl(var(--tone) / 0.14), transparent 70%),
    radial-gradient(40% 60% at 85% 8%, hsl(var(--tone) / 0.07), transparent 65%);
  mask-image: linear-gradient(to bottom, #000 40%, transparent);
}

.detail-wrap {
  position: relative;
  z-index: 1;
  max-width: 760px;
  margin: 0 auto;
}

.detail-topbar {
  margin-bottom: 16px;
}

.back-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 34px;
  padding: 0 12px;
  border: 1px solid hsl(var(--border) / 0.8);
  border-radius: 999px;
  background: hsl(var(--card, var(--background)) / 0.7);
  backdrop-filter: blur(8px);
  color: hsl(var(--foreground));
  font-size: 13px;
  cursor: pointer;
  transition:
    background 0.2s var(--ease),
    border-color 0.2s var(--ease);
}

.back-btn:hover {
  background: hsl(var(--muted) / 0.45);
  border-color: hsl(var(--foreground) / 0.18);
}

/* ===== Hero 卡片 ===== */
.hero-card {
  padding: 22px 24px;
  border: 1px solid hsl(var(--border) / 0.8);
  border-radius: 18px;
  background:
    radial-gradient(80% 130% at 0% 0%, hsl(var(--tone) / 0.08), transparent 60%),
    hsl(var(--card, var(--background)));
  box-shadow: 0 1px 2px rgb(0 0 0 / 4%);
  animation: rise 0.4s var(--ease) both;
}

.hero-kicker {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}

.type-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 24px;
  padding: 0 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  color: hsl(var(--tone));
  background: hsl(var(--tone) / 0.12);
}

.hero-time {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  color: hsl(var(--muted-foreground));
  font-variant-numeric: tabular-nums;
}

.hero-title {
  margin: 0;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.3;
  color: hsl(var(--foreground));
}

.hero-desc {
  margin: 10px 0 0;
  font-size: 13.5px;
  line-height: 1.55;
  color: hsl(var(--muted-foreground));
}

.hero-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 14px;
}

.meta-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 26px;
  padding: 0 10px;
  border-radius: 999px;
  font-size: 12px;
  color: hsl(var(--muted-foreground));
  background: hsl(var(--muted) / 0.5);
}

/* ===== 内容卡片 ===== */
.body-card {
  margin-top: 14px;
  padding: 20px 24px;
  border: 1px solid hsl(var(--border) / 0.8);
  border-radius: 18px;
  background: hsl(var(--card, var(--background)));
  box-shadow: 0 1px 2px rgb(0 0 0 / 4%);
  animation: rise 0.4s var(--ease) 0.06s both;
}

.content-text {
  color: hsl(var(--foreground) / 0.85);
  white-space: pre-line;
  line-height: 1.65;
}

/* MdPreview 背景交给卡片，避免深浅两层底色打架 */
.md-body {
  background: transparent;
}

.md-body :deep(.md-editor-preview-wrapper) {
  padding: 0;
}

/* ===== VIP 卡片：紫调走类型 tone 变量 ===== */
.vip-card {
  background:
    radial-gradient(90% 140% at 100% 0%, hsl(var(--tone) / 0.1), transparent 55%),
    hsl(var(--card, var(--background)));
}

.vip-scene {
  margin-bottom: 12px;
  font-size: 13px;
  font-weight: 650;
  color: hsl(var(--tone));
}

.vip-main {
  display: flex;
  align-items: center;
  gap: 16px;
}

.vip-line {
  font-size: 14px;
  color: hsl(var(--foreground));
}

.vip-line.is-sub {
  margin-top: 4px;
  font-size: 13px;
  color: hsl(var(--muted-foreground));
}

.vip-price {
  margin-top: 12px;
  font-size: 12px;
  color: hsl(var(--muted-foreground));
}

/* ===== 底部操作 ===== */
.detail-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 16px;
  animation: rise 0.4s var(--ease) 0.12s both;
}

.ghost-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 36px;
  padding: 0 14px;
  border: 1px solid hsl(var(--border) / 0.8);
  border-radius: 999px;
  background: hsl(var(--card, var(--background)) / 0.7);
  color: hsl(var(--foreground));
  font-size: 13px;
  cursor: pointer;
  transition:
    background 0.2s var(--ease),
    border-color 0.2s var(--ease),
    color 0.2s var(--ease);
}

.ghost-btn:hover {
  background: hsl(var(--muted) / 0.45);
  border-color: hsl(var(--foreground) / 0.18);
}

/* 有未读时强调：主色描边提醒发送者跟进 */
.ghost-btn.is-accent {
  border-color: hsl(var(--primary) / 0.4);
  background: hsl(var(--primary) / 0.08);
  color: hsl(var(--primary));
}

.ghost-btn.is-accent:hover {
  background: hsl(var(--primary) / 0.14);
}

/* ===== 加载 / 错误 / 空状态 ===== */
.state-box {
  display: grid;
  place-items: center;
  gap: 8px;
  padding: 72px 20px;
  text-align: center;
  font-size: 13px;
  color: hsl(var(--muted-foreground));
}

.state-spinner {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  border: 2px solid hsl(var(--primary) / 0.25);
  border-top-color: hsl(var(--primary));
  animation: spin 0.8s linear infinite;
}

.state-ico {
  width: 64px;
  height: 64px;
  margin-bottom: 8px;
  border-radius: 22px;
  display: grid;
  place-items: center;
  background: hsl(var(--muted) / 0.45);
  color: hsl(var(--foreground) / 0.55);
}

.state-title {
  margin: 0;
  font-size: 16px;
  font-weight: 650;
  color: hsl(var(--foreground));
}

.state-box.is-error {
  color: hsl(var(--destructive));
}

.retry-btn {
  margin-top: 8px;
  height: 32px;
  padding: 0 16px;
  border: none;
  border-radius: 999px;
  background: hsl(var(--primary));
  color: hsl(var(--primary-foreground));
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: opacity 0.15s ease;
}

.retry-btn:hover {
  opacity: 0.88;
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero-card,
  .body-card,
  .detail-actions {
    animation: none;
  }
}

@media (max-width: 720px) {
  .notice-detail {
    padding: 16px 12px 36px;
  }

  .hero-card,
  .body-card {
    padding: 16px;
  }

  .hero-title {
    font-size: 19px;
  }
}
</style>
