<script setup lang="ts">
import { computed, onBeforeUnmount, ref, watch } from 'vue'
import { fetchAdminFileBlob, fetchFileBlobByURL } from '@/shared/api/files'

const props = withDefaults(
  defineProps<{
    source: string
    alt?: string
    admin?: boolean
    imageClass?: string
    fallbackClass?: string
    loading?: 'eager' | 'lazy'
    decoding?: 'async' | 'sync' | 'auto'
  }>(),
  {
    alt: '',
    admin: false,
    imageClass: '',
    fallbackClass: '',
    loading: 'lazy',
    decoding: 'async',
  }
)

const imageURL = ref('')
const failed = ref(false)
let createdObjectURL = ''

const fallbackText = computed(() => (failed.value ? '图片加载失败' : '图片加载中'))

function extractObjectKey(value: string) {
  try {
    const parsed = new URL(value, window.location.origin)
    return parsed.searchParams.get('key') || ''
  } catch {
    return ''
  }
}

function shouldFetchWithAuth(value: string) {
  return value.includes('/api/files/object') || value.includes('/api/admin/files/object')
}

function revokeCurrentURL() {
  if (!createdObjectURL) return
  URL.revokeObjectURL(createdObjectURL)
  createdObjectURL = ''
}

async function loadImage() {
  revokeCurrentURL()
  imageURL.value = ''
  failed.value = false

  if (!props.source) {
    failed.value = true
    return
  }

  if (!shouldFetchWithAuth(props.source)) {
    imageURL.value = props.source
    return
  }

  try {
    const key = extractObjectKey(props.source)
    const blob =
      props.admin && key ? await fetchAdminFileBlob(key) : await fetchFileBlobByURL(props.source)
    createdObjectURL = URL.createObjectURL(blob)
    imageURL.value = createdObjectURL
  } catch {
    failed.value = true
  }
}

watch(() => [props.source, props.admin] as const, loadImage, { immediate: true })

onBeforeUnmount(revokeCurrentURL)
</script>

<template>
  <img
    v-if="imageURL"
    :class="imageClass"
    :src="imageURL"
    :alt="alt"
    :loading="loading"
    :decoding="decoding"
  />
  <span v-else :class="['auth-image-fallback', fallbackClass]">{{ fallbackText }}</span>
</template>

<style scoped>
.auth-image-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 120px;
  border: 1px dashed #d8dee8;
  border-radius: 12px;
  background: #f8fafc;
  color: #94a3b8;
  font-size: 13px;
  font-weight: 700;
}
</style>
