<script setup lang="ts">
defineProps<{
  title?: string
  confirmText?: string
  cancelText?: string
  loading?: boolean
}>()

const emit = defineEmits<{
  confirm: []
  cancel: []
}>()
</script>

<template>
  <Teleport to="body">
    <Transition name="modal">
      <div class="modal-overlay" @click.self="emit('cancel')">
        <div class="modal">
          <div class="modal__header">
            <h3 class="modal__title">{{ title }}</h3>
            <button class="modal__close" @click="emit('cancel')">
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
              </svg>
            </button>
          </div>

          <div class="modal__body">
            <slot />
          </div>

          <div v-if="$slots.footer || confirmText !== undefined" class="modal__footer">
            <slot name="footer">
              <button class="modal-btn modal-btn--cancel" @click="emit('cancel')">
                {{ cancelText ?? '取消' }}
              </button>
              <button class="modal-btn modal-btn--confirm" :disabled="loading" @click="emit('confirm')">
                <span v-if="loading" class="spinner" />
                {{ confirmText ?? '确认' }}
              </button>
            </slot>
          </div>
        </div>
      </div>
    </Transition>
  </Teleport>
</template>

<style scoped>
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
}

.modal {
  background: #1a1a1a;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  width: 100%;
  max-width: 440px;
  box-shadow: var(--shadow-card);
}

.modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-6) var(--space-6) var(--space-4);
  border-bottom: 1px solid var(--color-border);
}
.modal__title {
  font-size: var(--text-h3);
  font-weight: var(--fw-semibold);
  color: var(--color-text-primary);
}
.modal__close {
  color: var(--color-text-muted);
  display: flex;
  align-items: center;
  transition: color var(--transition);
}
.modal__close:hover { color: var(--color-text-secondary); }

.modal__body { padding: var(--space-6); }

.modal__footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-6) var(--space-6);
}

.modal-btn {
  padding: 10px 24px;
  border-radius: var(--radius-md);
  font-size: var(--text-small);
  font-weight: var(--fw-semibold);
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}
.modal-btn--cancel {
  background: transparent;
  border: 1px solid var(--color-border);
  color: var(--color-text-secondary);
}
.modal-btn--cancel:hover { border-color: var(--color-text-secondary); color: var(--color-text-primary); }
.modal-btn--confirm {
  background: var(--color-primary);
  border: 1px solid transparent;
  color: #000;
}
.modal-btn--confirm:hover:not(:disabled) { background: var(--color-primary-hover); }
.modal-btn--confirm:disabled { opacity: 0.5; cursor: not-allowed; }

.spinner {
  width: 14px; height: 14px;
  border: 2px solid rgba(0,0,0,0.3);
  border-top-color: #000;
  border-radius: 50%;
  animation: spin 0.6s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Transition */
.modal-enter-active, .modal-leave-active { transition: all 0.2s ease; }
.modal-enter-from, .modal-leave-to { opacity: 0; }
.modal-enter-from .modal, .modal-leave-to .modal { transform: scale(0.96); }
</style>
