<script lang="ts" setup>
/**
 * 消息专用场景弹层外壳（非 VbenModal）
 * 遮罩 + 类型色调面板 + 关闭；内容由各场景组件填充
 */
import { onMounted, onUnmounted, watch } from 'vue';

import { X } from 'lucide-vue-next';

import type { NoticeSceneSize, NoticeSceneTone } from './meta';

const props = withDefaults(
  defineProps<{
    open: boolean;
    title?: string;
    kicker?: string;
    tone?: NoticeSceneTone;
    size?: NoticeSceneSize;
    bareHeader?: boolean;
  }>(),
  {
    title: '消息详情',
    kicker: 'NOTICE',
    tone: 'default',
    size: 'md',
    bareHeader: false,
  },
);

const emit = defineEmits<{
  'update:open': [boolean];
  close: [];
}>();

function close() {
  emit('update:open', false);
  emit('close');
}

function onKeydown(e: KeyboardEvent) {
  if (e.key === 'Escape' && props.open) {
    close();
  }
}

watch(
  () => props.open,
  (v) => {
    document.body.style.overflow = v ? 'hidden' : '';
  },
);

onMounted(() => window.addEventListener('keydown', onKeydown));
onUnmounted(() => {
  window.removeEventListener('keydown', onKeydown);
  document.body.style.overflow = '';
});
</script>

<template>
  <Teleport to="body">
    <Transition name="ns">
      <div
        v-if="open"
        class="ns-root"
        role="presentation"
      >
        <div class="ns-mask" @click="close" />
        <div
          class="ns-panel"
          :class="[`tone-${tone}`, `size-${size}`, { bare: bareHeader }]"
          role="dialog"
          aria-modal="true"
          :aria-label="title"
          @click.stop
        >
          <button
            type="button"
            class="ns-close"
            aria-label="关闭"
            @click="close"
          >
            <X class="size-4" />
          </button>
          <header v-if="!bareHeader" class="ns-head">
            <div class="ns-kicker">{{ kicker }}</div>
            <h2 class="ns-title">{{ title }}</h2>
          </header>
          <div class="ns-body">
            <slot />
          </div>
        </div>
      </div>
    </Transition>
  </Teleport>
</template>

<style scoped>
.ns-root {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: grid;
  place-items: center;
  padding: 24px 16px;
}

.ns-mask {
  position: absolute;
  inset: 0;
  background: hsl(0 0% 0% / 0.48);
  backdrop-filter: blur(6px);
}

.ns-panel {
  position: relative;
  z-index: 1;
  width: min(720px, 96vw);
  max-height: min(88vh, 920px);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: 20px;
  border: 1px solid hsl(var(--border));
  background: hsl(var(--card, var(--background)));
  box-shadow:
    0 24px 64px hsl(0 0% 0% / 0.28),
    0 0 0 1px hsl(var(--foreground) / 0.03);
}

.ns-panel.size-lg {
  width: min(860px, 96vw);
}

.ns-panel.size-xl {
  width: min(960px, 96vw);
}

.ns-panel.tone-vip {
  border-color: hsl(160 50% 40% / 0.35);
  box-shadow:
    0 24px 64px hsl(160 40% 12% / 0.45),
    0 0 40px hsl(160 60% 40% / 0.12);
}

.ns-panel.tone-danger {
  border-color: hsl(0 72% 50% / 0.35);
  box-shadow:
    0 24px 64px hsl(0 40% 10% / 0.4),
    0 0 36px hsl(0 72% 50% / 0.12);
}

.ns-panel.tone-money {
  border-color: hsl(var(--primary) / 0.35);
}

.ns-panel.tone-report {
  border-color: hsl(160 60% 40% / 0.3);
}

.ns-panel.tone-invoice {
  border-color: hsl(250 60% 55% / 0.3);
}

.ns-panel.tone-audit {
  border-color: hsl(190 70% 42% / 0.28);
}

.ns-close {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 3;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  color: hsl(var(--muted-foreground));
  background: hsl(var(--muted) / 0.55);
  transition:
    background 0.15s ease,
    color 0.15s ease,
    transform 0.15s ease;
}

.ns-close:hover {
  color: hsl(var(--foreground));
  background: hsl(var(--muted));
  transform: scale(1.04);
}

.ns-head {
  flex-shrink: 0;
  padding: 20px 48px 0 22px;
}

.ns-kicker {
  font-size: 11px;
  font-weight: 750;
  letter-spacing: 0.12em;
  color: hsl(var(--primary));
}

.tone-danger .ns-kicker {
  color: hsl(0 72% 52%);
}

.tone-vip .ns-kicker {
  color: hsl(160 55% 42%);
}

.tone-invoice .ns-kicker {
  color: hsl(250 60% 55%);
}

.ns-title {
  margin: 6px 0 0;
  font-size: 18px;
  font-weight: 720;
  letter-spacing: -0.02em;
  color: hsl(var(--foreground));
}

.ns-body {
  flex: 1;
  overflow: auto;
  padding: 16px 22px 22px;
}

.ns-panel.bare .ns-body {
  padding-top: 18px;
}

/* enter / leave */
.ns-enter-active,
.ns-leave-active {
  transition: opacity 0.2s ease;
}

.ns-enter-active .ns-panel,
.ns-leave-active .ns-panel {
  transition:
    transform 0.22s cubic-bezier(0.22, 1, 0.36, 1),
    opacity 0.22s ease;
}

.ns-enter-from,
.ns-leave-to {
  opacity: 0;
}

.ns-enter-from .ns-panel,
.ns-leave-to .ns-panel {
  opacity: 0;
  transform: translateY(12px) scale(0.98);
}
</style>
