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

import { ArrowLeft, Download } from '@vben/icons';
import { $t } from '@vben/locales';

import { ElButton, ElMessage } from 'element-plus';

import { getFileTypeIcon } from '#/assets/file-icons';
import { getFileUrl } from '#/composables/useFileUrl';

const FILE_PREVIEW_TITLE = '文件预览';
const FILE_DOWNLOAD_TEXT = '下载';
const FILE_DOWNLOAD_FAILED = '下载文件失败';
const FILE_PREVIEW_FAILED = '预览失败';
const FILE_PREVIEW_NOT_SUPPORTED = '该文件类型暂不支持预览';

const route = useRoute();

const fileId = computed(() => route.params.id as string);
const fileName = computed(() => (route.query.name as string) || '');
const fileExt = computed(() => (route.query.ext as string) || '');
const fileUrl = ref('');
const textContent = ref('');
const errorMsg = ref('');
const loading = ref(false);

const normalizedExt = computed(() =>
  fileExt.value.toLowerCase().replace('.', ''),
);
const textExts = new Set([
  'bash',
  'conf',
  'css',
  'csv',
  'env',
  'html',
  'ini',
  'js',
  'json',
  'less',
  'log',
  'md',
  'py',
  'sql',
  'ts',
  'txt',
  'vue',
  'xml',
  'yaml',
  'yml',
]);
const imageExts = new Set(['gif', 'jpeg', 'jpg', 'png', 'svg', 'webp']);

const previewType = computed<'image' | 'none' | 'pdf' | 'text'>(() => {
  const ext = normalizedExt.value;
  if (ext === 'pdf') return 'pdf';
  if (imageExts.has(ext)) return 'image';
  if (textExts.has(ext)) return 'text';
  return 'none';
});

async function loadFile() {
  if (!fileId.value) return;
  loading.value = true;
  errorMsg.value = '';
  textContent.value = '';
  try {
    const url = await getFileUrl(fileId.value);
    fileUrl.value = url;
    if (previewType.value === 'text') {
      const resp = await fetch(url);
      if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
      textContent.value = await resp.text();
    }
  } catch (error: any) {
    errorMsg.value = error?.message || String(error);
  } finally {
    loading.value = false;
  }
}

async function handleDownload() {
  if (!fileUrl.value) return;
  try {
    const resp = await fetch(fileUrl.value);
    const blob = await resp.blob();
    const blobUrl = window.URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = blobUrl;
    link.download = fileName.value || 'download';
    document.body.append(link);
    link.click();
    link.remove();
    window.URL.revokeObjectURL(blobUrl);
  } catch {
    ElMessage.error(FILE_DOWNLOAD_FAILED);
  }
}

function handleBack() {
  window.close();
}

onMounted(() => {
  document.title = fileName.value || FILE_PREVIEW_TITLE;
  loadFile();
});
</script>

<template>
  <div class="flex h-screen w-screen flex-col bg-[var(--el-bg-color)]">
    <div
      class="flex h-12 flex-shrink-0 items-center justify-between border-b border-[var(--el-border-color)] px-4"
    >
      <div class="flex min-w-0 items-center gap-3">
        <ElButton text circle size="small" @click="handleBack">
          <ArrowLeft class="size-4" />
        </ElButton>
        <img :src="getFileTypeIcon(fileExt)" class="size-5" />
        <span
          class="truncate text-sm font-medium text-[var(--el-text-color-primary)]"
        >
          {{ fileName }}
        </span>
      </div>
      <ElButton v-if="fileUrl" size="small" @click="handleDownload">
        <Download class="mr-1 size-4" />
        {{ FILE_DOWNLOAD_TEXT }}
      </ElButton>
    </div>

    <div class="flex flex-1 items-center justify-center overflow-hidden">
      <div v-if="loading" class="text-[var(--el-text-color-secondary)]">
        {{ $t('common.loading') }}...
      </div>

      <div v-else-if="errorMsg" class="max-w-md text-center">
        <p class="mb-2 text-lg text-[var(--el-color-danger)]">
          {{ FILE_PREVIEW_FAILED }}
        </p>
        <p class="text-sm text-[var(--el-text-color-secondary)]">
          {{ errorMsg }}
        </p>
      </div>

      <iframe
        v-else-if="previewType === 'pdf' && fileUrl"
        :src="fileUrl"
        class="h-full w-full border-0"
      />

      <img
        v-else-if="previewType === 'image' && fileUrl"
        :src="fileUrl"
        class="max-h-full max-w-full object-contain"
      />

      <pre
        v-else-if="previewType === 'text'"
        class="h-full w-full overflow-auto bg-[var(--el-fill-color-light)] p-4 text-sm leading-6"
        >{{ textContent }}</pre
      >

      <div v-else class="text-center">
        <img :src="getFileTypeIcon(fileExt)" class="mx-auto mb-4 size-20" />
        <p class="mb-4 text-lg text-[var(--el-text-color-secondary)]">
          {{ FILE_PREVIEW_NOT_SUPPORTED }}
        </p>
        <ElButton v-if="fileUrl" type="primary" @click="handleDownload">
          <Download class="mr-1 size-4" />
          {{ FILE_DOWNLOAD_TEXT }}
        </ElButton>
      </div>
    </div>
  </div>
</template>
