<script setup lang="ts">
/**
 * Error boundary component.
 *
 * Catches errors in child components and displays a fallback UI
 * instead of crashing the entire application. Provides a retry
 * button to attempt recovery.
 */
import { ref, computed, onErrorCaptured } from 'vue'

const props = withDefaults(defineProps<{
  /** Custom fallback message */
  fallbackMessage?: string
}>(), {
  fallbackMessage: 'Something went wrong. Please try again.',
})

const emit = defineEmits<{
  error: [error: Error, info: string]
}>()

const hasError = ref(false)
const errorMessage = ref<string | null>(null)
const isDev = computed(() => import.meta.env.DEV)

onErrorCaptured((error: Error, _instance, info: string) => {
  hasError.value = true
  errorMessage.value = error.message

  // Emit error for parent handling/logging
  emit('error', error, info)

  // Log in development
  if (import.meta.env.DEV) {
    console.error('ErrorBoundary caught:', error)
    console.error('Component info:', info)
  }

  // Prevent error from propagating
  return false
})

function handleRetry(): void {
  hasError.value = false
  errorMessage.value = null
}
</script>

<template>
  <div
    v-if="hasError"
    class="flex flex-col items-center justify-center p-8 text-center"
  >
    <div class="text-4xl mb-4">
      &#x26A0;
    </div>
    <h2 class="text-xl font-semibold text-gray-200 mb-2">
      Oops!
    </h2>
    <p class="text-gray-400 mb-4 max-w-md">
      {{ props.fallbackMessage }}
    </p>
    <p
      v-if="errorMessage && isDev"
      class="text-error text-sm mb-4 font-mono bg-error/10 px-3 py-2 rounded"
    >
      {{ errorMessage }}
    </p>
    <button
      class="btn btn-primary"
      @click="handleRetry"
    >
      Try Again
    </button>
  </div>
  <slot v-else />
</template>
