<template>
  <div v-if="visible" class="modal-mask" @click.self="emit('close')">
    <div
      ref="dialogRef"
      class="modal hint-modal scale-in"
      role="dialog"
      aria-modal="true"
      aria-labelledby="task-hint-modal-title"
      tabindex="-1"
      @keydown="handleKeydown"
    >
      <div class="modal-head">
        <h3 id="task-hint-modal-title" class="modal-title">
          <svg
            width="14"
            height="14"
            viewBox="0 0 24 24"
            fill="none"
            stroke="#f97316"
            stroke-width="2"
            stroke-linecap="round"
            stroke-linejoin="round"
          >
            <path d="M9 18h6" />
            <path d="M10 22h4" />
            <path
              d="M15.09 14c.18-.98.65-1.74 1.41-2.5A4.65 4.65 0 0 0 18 8 6 6 0 0 0 6 8c0 1 .23 2.23 1.5 3.5A4.61 4.61 0 0 1 8.91 14"
            />
          </svg>
          <span class="modal-title-text">
            {{ aiName ? `${aiName} 的任务提示` : '任务提示' }}
          </span>
        </h3>
        <button class="close-btn" type="button" aria-label="关闭" @click="emit('close')">
          <svg
            width="14"
            height="14"
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
            stroke-linecap="round"
            stroke-linejoin="round"
          >
            <line x1="18" y1="6" x2="6" y2="18" />
            <line x1="6" y1="6" x2="18" y2="18" />
          </svg>
        </button>
      </div>

      <div v-if="loading" class="state-panel">
        <p class="state-text">正在生成任务提示...</p>
      </div>

      <div v-else-if="error" class="state-panel error-panel">
        <p class="error-text">{{ error }}</p>
        <button class="retry-btn" type="button" @click="emit('retry')">
          重试
        </button>
      </div>

      <template v-else-if="hint">
        <div class="hint-context">
          <p class="context-label">当前问题</p>
          <p class="context-body">{{ hint.current_question }}</p>
        </div>

        <div class="hint-section">
          <p class="section-label">参考句子</p>
          <div class="sentences">
            <div
              v-for="(sentence, index) in hint.example_sentences"
              :key="`${sentence.english}-${index}`"
              class="sentence-card"
            >
              <p class="sentence-en">{{ sentence.english }}</p>
              <p class="sentence-zh">{{ sentence.chinese }}</p>
            </div>
          </div>
        </div>

        <div class="hint-section">
          <p class="section-label">关键词汇</p>
          <div class="vocab-grid">
            <div
              v-for="(vocab, index) in hint.key_vocabulary"
              :key="`${vocab.word}-${index}`"
              class="vocab-item"
            >
              <p class="vocab-word">{{ vocab.word }}</p>
              <p class="vocab-meaning">{{ vocab.meaning }}</p>
            </div>
          </div>
        </div>

        <p class="hint-footer">用自己的话表达更棒哦</p>
      </template>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { nextTick, onBeforeUnmount, ref, watch } from 'vue'
import type { TaskHint } from '@/types/englishSpeaking'

const props = defineProps<{
  visible: boolean
  loading: boolean
  error?: string | null
  hint?: TaskHint | null
  aiName?: string
}>()

const emit = defineEmits<{
  close: []
  retry: []
}>()

const dialogRef = ref<HTMLElement | null>(null)
const previouslyFocusedElement = ref<HTMLElement | null>(null)

const focusableSelector = [
  'a[href]',
  'button:not([disabled])',
  'textarea:not([disabled])',
  'input:not([disabled])',
  'select:not([disabled])',
  '[tabindex]:not([tabindex="-1"])',
].join(',')

const getFocusableElements = () => {
  const dialog = dialogRef.value
  if (!dialog) return []

  return Array.from(dialog.querySelectorAll<HTMLElement>(focusableSelector)).filter((el) => {
    if (el.hasAttribute('disabled') || el.getAttribute('aria-hidden') === 'true') return false
    return el.offsetParent !== null || el === document.activeElement
  })
}

const restorePreviousFocus = () => {
  const element = previouslyFocusedElement.value
  previouslyFocusedElement.value = null

  if (element && document.contains(element)) {
    element.focus()
  }
}

const focusDialog = async () => {
  previouslyFocusedElement.value = document.activeElement instanceof HTMLElement
    ? document.activeElement
    : null

  await nextTick()
  dialogRef.value?.focus()
}

const containTabFocus = (event: KeyboardEvent) => {
  const dialog = dialogRef.value
  if (!dialog) return

  const focusableElements = getFocusableElements()
  if (!focusableElements.length) {
    event.preventDefault()
    dialog.focus()
    return
  }

  const firstElement = focusableElements[0]
  const lastElement = focusableElements[focusableElements.length - 1]
  const activeElement = document.activeElement

  if (event.shiftKey) {
    if (activeElement === dialog || activeElement === firstElement || !dialog.contains(activeElement)) {
      event.preventDefault()
      lastElement.focus()
    }
    return
  }

  if (activeElement === dialog) {
    event.preventDefault()
    firstElement.focus()
    return
  }

  if (activeElement === lastElement) {
    event.preventDefault()
    firstElement.focus()
  }
}

const handleKeydown = (event: KeyboardEvent) => {
  if (event.key === 'Escape') {
    event.preventDefault()
    emit('close')
    return
  }

  if (event.key === 'Tab') {
    containTabFocus(event)
  }
}

watch(
  () => props.visible,
  (visible) => {
    if (visible) {
      void focusDialog()
      return
    }

    restorePreviousFocus()
  },
  { flush: 'post', immediate: true },
)

onBeforeUnmount(() => {
  restorePreviousFocus()
})
</script>

<style lang="scss" scoped>
.modal-mask {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(0, 0, 0, 0.3);
  backdrop-filter: blur(2px);
}

.modal {
  width: 100%;
  max-height: 80vh;
  overflow-y: auto;
  background: #fff;
  border-radius: 16px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
}

.hint-modal {
  max-width: 440px;
  min-width: 280px;
  padding: 20px;
}

.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.modal-title {
  display: flex;
  min-width: 0;
  align-items: center;
  gap: 6px;
  margin: 0;
  color: #111827;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.4;
}

.modal-title svg {
  flex: 0 0 auto;
}

.modal-title-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.close-btn {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  color: #6b7280;
  cursor: pointer;
  background: #f3f4f6;
  border: none;
  border-radius: 8px;

  &:hover {
    background: #e5e7eb;
  }
}

.state-panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 128px;
  padding: 16px;
  text-align: center;
}

.state-text,
.error-text {
  margin: 0;
  font-size: 13px;
  line-height: 1.6;
}

.state-text {
  color: #6b7280;
}

.error-panel {
  gap: 12px;
}

.error-text {
  color: #ef4444;
  overflow-wrap: anywhere;
}

.retry-btn {
  min-width: 72px;
  height: 32px;
  padding: 0 14px;
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  background: #f97316;
  border: none;
  border-radius: 8px;

  &:hover {
    background: #ea580c;
  }
}

.hint-context {
  padding: 12px 14px;
  margin-bottom: 16px;
  background: #fff7ed;
  border: 1px solid #fed7aa;
  border-radius: 12px;
}

.context-label,
.section-label {
  margin: 0 0 8px;
  font-size: 10px;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.context-label {
  margin-bottom: 4px;
  color: #f97316;
}

.context-body {
  margin: 0;
  color: #374151;
  font-size: 13px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.hint-section {
  margin-bottom: 16px;
}

.section-label {
  color: #9ca3af;
}

.sentences {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.sentence-card {
  min-width: 0;
  padding: 10px 12px;
  background: #f9fafb;
  border: 1px solid #f3f4f6;
  border-radius: 12px;
  transition: border-color 0.2s;

  &:hover {
    border-color: #fed7aa;
  }
}

.sentence-en,
.sentence-zh,
.vocab-word,
.vocab-meaning {
  overflow-wrap: anywhere;
}

.sentence-en {
  margin: 0;
  color: #1f2937;
  font-size: 12px;
  line-height: 1.5;
}

.sentence-zh {
  margin: 2px 0 0;
  color: #9ca3af;
  font-size: 11px;
  line-height: 1.5;
}

.vocab-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

.vocab-item {
  min-width: 0;
  padding: 8px 10px;
  background: #f9fafb;
  border: 1px solid #f3f4f6;
  border-radius: 10px;
}

.vocab-word {
  margin: 0;
  color: #1f2937;
  font-size: 12px;
  font-weight: 500;
  line-height: 1.4;
}

.vocab-meaning {
  margin: 2px 0 0;
  color: #9ca3af;
  font-size: 10px;
  line-height: 1.5;
}

.hint-footer {
  margin: 16px 0 0;
  color: #d1d5db;
  font-size: 11px;
  line-height: 1.5;
  text-align: center;
}

.scale-in {
  animation: scale-in 0.18s ease-out;
}

@keyframes scale-in {
  from {
    opacity: 0;
    transform: scale(0.96);
  }

  to {
    opacity: 1;
    transform: scale(1);
  }
}

@media (max-width: 420px) {
  .hint-modal {
    padding: 16px;
  }

  .vocab-grid {
    grid-template-columns: 1fr;
  }
}
</style>
