<template>
  <div
    role="dialog"
    aria-modal="true"
    :aria-labelledby="`wiz-heading-${currentStep?.step ?? 1}`"
    class="fixed inset-0 z-50 bg-surface overflow-y-auto"
    :ref="(el) => { dialogRef = el as HTMLElement | null }"
  >
    <div class="max-w-lg mx-auto py-12 px-6">
      <!-- Progress heading -->
      <h2
        :id="`wiz-heading-${currentStep?.step ?? 1}`"
        ref="headingRef"
        tabindex="-1"
        class="text-lg font-semibold text-text-primary mb-1 focus:outline-none"
      >
        Step {{ currentStep?.step ?? 1 }} of {{ totalSteps }}: {{ currentStep?.title ?? '…' }}
      </h2>
      <p v-if="currentStep?.help" class="text-sm text-text-dim mb-6">{{ currentStep.help }}</p>

      <!-- Step input -->
      <div class="mb-8">
        <!-- Select -->
        <div v-if="currentStep?.type === 'select'" class="space-y-2">
          <label :for="`wiz-input-${currentStep.id}`" class="sr-only">{{ currentStep.title }}</label>
          <select
            :id="`wiz-input-${currentStep.id}`"
            v-model="answer"
            class="w-full bg-surface border border-surface-border rounded px-4 py-2.5 text-sm text-text-primary focus:outline-none focus:border-accent"
          >
            <option value="" disabled>Choose one…</option>
            <option v-for="opt in currentStep.options" :key="opt" :value="opt">{{ opt }}</option>
          </select>
        </div>

        <!-- Text -->
        <div v-else-if="currentStep?.type === 'text'">
          <label :for="`wiz-input-${currentStep.id}`" class="sr-only">{{ currentStep.title }}</label>
          <input
            :id="`wiz-input-${currentStep.id}`"
            v-model="answer"
            type="text"
            :placeholder="currentStep.placeholder || ''"
            class="w-full bg-surface border border-surface-border rounded px-4 py-2.5 text-sm text-text-primary placeholder-text-dim focus:outline-none focus:border-accent"
          />
        </div>
      </div>

      <!-- Button row: Back | Next/Skip -->
      <div class="flex items-center gap-3">
        <button
          v-if="session.current_step > 1"
          @click="goBack"
          class="px-4 py-2 border border-surface-border rounded text-sm text-text-dim hover:text-text-primary transition-colors"
        >Back</button>
        <button
          @click="goNext()"
          :disabled="!canAdvance"
          class="px-4 py-2 bg-accent text-surface text-sm rounded font-medium hover:opacity-90 disabled:opacity-40 transition-opacity"
        >
          {{ isLastStep ? 'Review' : 'Next' }}
        </button>
        <button
          v-if="currentStep?.optional"
          @click="goNext(true)"
          class="px-4 py-2 text-sm text-text-dim hover:text-text-primary transition-colors"
        >Skip this step (add later)</button>
      </div>

      <!-- Escape hatch -->
      <p class="mt-8 pt-4 border-t border-surface-border">
        <RouterLink to="/settings" @click="$emit('close')" class="text-xs text-text-dim hover:text-text-primary underline underline-offset-2">
          Skip wizard — edit sources directly in config
        </RouterLink>
      </p>
    </div>

    <!-- Summary / Apply screen -->
    <div v-if="showSummary" class="max-w-lg mx-auto pb-12 px-6">
      <h2 ref="summaryRef" tabindex="-1" class="text-lg font-semibold text-text-primary mb-4 focus:outline-none">
        Review and apply
      </h2>
      <div class="rounded border border-surface-border bg-surface-raised p-4 mb-4 space-y-1">
        <p class="text-xs text-text-dim font-medium uppercase tracking-wide mb-2">Facts that will be saved</p>
        <div v-for="(val, key) in session.answers" :key="String(key)" class="flex gap-2 text-sm">
          <span class="font-mono text-text-dim w-28 shrink-0">{{ key }}</span>
          <span class="text-text-primary">{{ val || '(skipped)' }}</span>
        </div>
      </div>
      <div class="flex gap-3">
        <button
          @click="applyWizard"
          :disabled="applying"
          class="px-4 py-2 bg-accent text-surface text-sm rounded font-medium hover:opacity-90 disabled:opacity-40"
        >
          {{ applying ? 'Saving…' : `Save ${factCount} facts and apply source config` }}
        </button>
        <button @click="showSummary = false; session = { ...session, current_step: schema.length }" class="text-sm text-text-dim hover:text-text-primary">
          Go back and edit
        </button>
      </div>
      <div v-if="applyError" role="alert" class="mt-3 text-sm text-sev-error">{{ applyError }}</div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'
import { RouterLink } from 'vue-router'

const BASE = import.meta.env.BASE_URL.replace(/\/$/, '')
const emit = defineEmits<{ (e: 'close'): void; (e: 'complete'): void }>()

interface WizardStep {
  step: number
  id: string
  title: string
  type: string
  options?: string[]
  placeholder?: string
  optional?: boolean
  help?: string
  condition?: { step_id: string; value: string }
}

const schema = ref<WizardStep[]>([])
const session = ref<{ current_step: number; answers: Record<string, string> }>({
  current_step: 1,
  answers: {},
})
const answer = ref('')
const showSummary = ref(false)
const applying = ref(false)
const applyError = ref<string | null>(null)
const headingRef = ref<HTMLElement | null>(null)
const summaryRef = ref<HTMLElement | null>(null)
const dialogRef  = ref<HTMLElement | null>(null)

const totalSteps = computed(() => schema.value.length)
const currentStep = computed(() =>
  schema.value.find(s => s.step === session.value.current_step) ?? schema.value[0]
)
const isLastStep = computed(() => session.value.current_step === totalSteps.value)
const canAdvance = computed(() => currentStep.value?.optional || !!answer.value.trim())
const factCount = computed(() => Object.values(session.value.answers).filter(v => v).length)

async function loadSchema() {
  try {
    const r = await fetch(`${BASE}/api/context/wizard/schema`)
    if (r.ok) schema.value = await r.json()
  } catch { /* non-critical — wizard shows loading state */ }
  const saved = sessionStorage.getItem('turnstone-wizard')
  if (saved) {
    try { session.value = JSON.parse(saved) } catch {}
  }
  // Pre-populate answer for the current step (handles sessionStorage restore)
  answer.value = session.value.answers[currentStep.value?.id ?? ''] ?? ''
}

async function goNext(skip = false) {
  applyError.value = null
  const stepId = currentStep.value?.id
  if (!stepId) return
  try {
    const r = await fetch(`${BASE}/api/context/wizard/step`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ session: session.value, step_id: stepId, answer: skip ? '' : answer.value }),
    })
    if (!r.ok) { applyError.value = `Step failed (${r.status})`; return }
    const data = await r.json()
    session.value = data.session
    sessionStorage.setItem('turnstone-wizard', JSON.stringify(session.value))
    answer.value = session.value.answers[currentStep.value?.id ?? ''] ?? ''
    if (data.complete) {
      showSummary.value = true
      nextTick(() => summaryRef.value?.focus())
    } else {
      nextTick(() => headingRef.value?.focus())
    }
  } catch {
    applyError.value = 'Could not reach server'
  }
}

function goBack() {
  session.value = { ...session.value, current_step: session.value.current_step - 1 }
  answer.value = session.value.answers[currentStep.value?.id ?? ''] ?? ''
  nextTick(() => headingRef.value?.focus())
}

async function applyWizard() {
  applying.value = true
  applyError.value = null
  try {
    const r = await fetch(`${BASE}/api/context/wizard/apply`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ session: session.value }),
    })
    if (!r.ok) throw new Error(await r.text())
    sessionStorage.removeItem('turnstone-wizard')
    emit('complete')
  } catch (e) {
    applyError.value = e instanceof Error ? e.message : 'Apply failed'
  } finally {
    applying.value = false
  }
}

function onKeydown(e: KeyboardEvent) {
  if (e.key === 'Tab') {
    const focusable = dialogRef.value?.querySelectorAll<HTMLElement>(
      'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
    )
    if (!focusable || focusable.length === 0) return
    const first = focusable[0]!
    const last = focusable[focusable.length - 1]!
    if (e.shiftKey) {
      if (document.activeElement === first) { e.preventDefault(); last.focus() }
    } else {
      if (document.activeElement === last) { e.preventDefault(); first.focus() }
    }
  }
  if (e.key === 'Escape') emit('close')
}

onMounted(() => {
  loadSchema()
  document.addEventListener('keydown', onKeydown)
  nextTick(() => headingRef.value?.focus())
})

onUnmounted(() => document.removeEventListener('keydown', onKeydown))
</script>
