<script setup lang="ts">
// 공용 폼 모달 셸 — backdrop + 헤더(제목/닫기) + 본문 슬롯 + 푸터 슬롯.
// Teleport(body) · ESC · 바깥(backdrop) 클릭 닫기 내장.
// 전역 .modal*(확인 다이얼로그 전용)과 충돌하지 않도록 bm- 접두 클래스를 쓴다.
// 폼 필드는 전역 .form-* 클래스(relay.css)를 본문 슬롯에서 사용한다.
import { onBeforeUnmount, onMounted } from 'vue'

withDefaults(
  defineProps<{
    title: string
    // 너비: md(기본 33.75rem) | sm(27.5rem)
    size?: 'md' | 'sm'
  }>(),
  { size: 'md' },
)
const emit = defineEmits<{ (e: 'close'): void }>()

function onKey(e: KeyboardEvent): void {
  if (e.key === 'Escape') emit('close')
}
onMounted(() => document.addEventListener('keydown', onKey))
onBeforeUnmount(() => document.removeEventListener('keydown', onKey))
</script>

<template>
  <Teleport to="body">
    <div
      class="bm-back"
      @mousedown.self="emit('close')"
    >
      <div
        class="bm"
        :class="{ 'bm-sm': size === 'sm' }"
        role="dialog"
        aria-modal="true"
      >
        <div class="bm-head">
          <div class="bm-head-text">
            <h3>{{ title }}</h3>
            <div
              v-if="$slots.subtitle"
              class="bm-sub"
            >
              <slot name="subtitle" />
            </div>
          </div>
          <button
            type="button"
            class="bm-x"
            aria-label="닫기"
            @click="emit('close')"
          >
            <svg
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2.2"
              stroke-linecap="round"
            ><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>
        <div class="bm-body">
          <slot />
        </div>
        <div
          v-if="$slots.foot"
          class="bm-foot"
        >
          <slot name="foot" />
        </div>
      </div>
    </div>
  </Teleport>
</template>

<style scoped>
.bm-back {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: rgba(20, 24, 33, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}
.bm {
  width: 100%;
  max-width: 33.75rem;
  max-height: 90vh;
  overflow-y: auto;
  background: #fff;
  border-radius: 0.875rem;
  box-shadow: 0 24px 64px rgba(20, 24, 33, 0.32);
  display: flex;
  flex-direction: column;
}
.bm.bm-sm {
  max-width: 27.5rem;
}
.bm-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 1.375rem 1.5rem 1rem;
  position: sticky;
  top: 0;
  background: #fff;
  border-radius: 0.875rem 0.875rem 0 0;
  z-index: 1;
}
.bm-head h3 {
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: -0.01875rem;
}
.bm-sub {
  font-size: 0.8125rem;
  color: var(--text-2);
  margin-top: 0.25rem;
}
.bm-sub :deep(b) {
  color: var(--text-2);
  font-weight: 600;
}
.bm-x {
  flex-shrink: 0;
}
.bm-x {
  width: 2rem;
  height: 2rem;
  border: none;
  background: transparent;
  color: var(--text-3);
  border-radius: var(--radius-sm);
  cursor: pointer;
  display: grid;
  place-items: center;
  margin-right: -0.3125rem;
}
.bm-x:hover {
  background: #f1f2f4;
  color: var(--text);
}
.bm-x svg {
  width: 1.125rem;
  height: 1.125rem;
}
.bm-body {
  padding: 0.5rem 1.5rem 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 1.125rem;
  text-align: left;
}
.bm-foot {
  display: flex;
  justify-content: flex-end;
  gap: 0.5625rem;
  padding: 1rem 1.5rem;
  border-top: 1px solid var(--border);
  background: #fafbfc;
  position: sticky;
  bottom: 0;
  border-radius: 0 0 0.875rem 0.875rem;
}
/* 푸터 버튼 — 전역 .mbtn(확인 다이얼로그용 flex:1) 대신 폼 모달용 우측정렬 컴팩트 */
.bm-foot :deep(.mbtn) {
  flex: 0 0 auto;
  height: 2.375rem;
  padding: 0 1rem;
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
}
.bm-foot :deep(.mbtn svg) {
  width: 0.9375rem;
  height: 0.9375rem;
}
.bm-foot :deep(.mbtn:disabled) {
  opacity: 0.45;
  cursor: not-allowed;
}
.bm-foot :deep(.mbtn.primary:disabled),
.bm-foot :deep(.mbtn.primary:disabled:hover) {
  background: var(--accent);
  border-color: var(--accent);
}
</style>
