<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { api, type DirectoryDto, type DriveDto, type FileRecordDto, type LibraryRootDto, type MediaType, type TextPreviewDto } from './api'

const isAdminPage = computed(() => window.location.pathname.toLowerCase().startsWith('/admin'))
const roots = ref<LibraryRootDto[]>([])
const drives = ref<DriveDto[]>([])
const directories = ref<DirectoryDto[]>([])
const files = ref<FileRecordDto[]>([])
const selectedFile = ref<FileRecordDto | null>(null)
const textPreview = ref<TextPreviewDto | null>(null)
const currentPath = ref('')
const manualPath = ref('')
const keyword = ref('')
const mediaType = ref<MediaType>('all')
const rootId = ref<number | undefined>()
const isBrowsingRoots = ref(true)
const page = ref(1)
const pageSize = 24
const total = ref(0)
const loading = ref(false)
const scanningId = ref<number | null>(null)
const errorMessage = ref('')
const showQrCode = ref(false)
const qrCodeData = ref<{ url: string; qrCodeBase64: string } | null>(null)

const totalPages = computed(() => Math.max(1, Math.ceil(total.value / pageSize)))
const availableRoots = computed(() => roots.value.filter((root) => root.isAvailable))
const activeRoots = computed(() => roots.value.filter((root) => root.isEnabled && root.isAvailable))
const selectedRoot = computed(() => roots.value.find((root) => root.id === selectedFile.value?.libraryRootId))
const totalRootFiles = computed(() => roots.value.reduce((sum, root) => sum + root.fileCount, 0))
const selectedMediaUrl = computed(() => selectedFile.value ? api.mediaUrl(selectedFile.value.streamUrl) : '')
const clientTitle = computed(() => {
  if (isBrowsingRoots.value) return '文件库'
  return rootId.value ? roots.value.find((root) => root.id === rootId.value)?.displayName ?? '文件' : '文件'
})

function formatSize(bytes: number) {
  if (bytes < 1024) return `${bytes} B`
  const units = ['KB', 'MB', 'GB', 'TB']
  let value = bytes / 1024
  let index = 0
  while (value >= 1024 && index < units.length - 1) {
    value /= 1024
    index += 1
  }
  return `${value.toFixed(value >= 10 ? 1 : 2)} ${units[index]}`
}

function formatDate(value: string | null) {
  if (!value) return '未扫描'
  return new Date(value).toLocaleString()
}

function setError(error: unknown) {
  errorMessage.value = error instanceof Error ? error.message : '操作失败'
}

async function loadRoots() {
  roots.value = await api.getRoots()
}

async function loadDrives() {
  drives.value = await api.getDrives()
}

async function openDirectory(path: string) {
  try {
    errorMessage.value = ''
    currentPath.value = path
    manualPath.value = path
    directories.value = await api.getDirectories(path)
  } catch (error) {
    setError(error)
  }
}

async function addRoot(path = manualPath.value) {
  try {
    errorMessage.value = ''
    loading.value = true
    await api.addRoot({ path, scanIntervalMinutes: 5 })
    await Promise.all([loadRoots(), loadFiles()])
  } catch (error) {
    setError(error)
  } finally {
    loading.value = false
  }
}

async function toggleRoot(root: LibraryRootDto) {
  try {
    errorMessage.value = ''
    await api.setRootEnabled(root.id, !root.isEnabled)
    await loadRoots()
  } catch (error) {
    setError(error)
  }
}

async function deleteRoot(root: LibraryRootDto) {
  try {
    errorMessage.value = ''
    await api.deleteRoot(root.id)
    if (rootId.value === root.id) rootId.value = undefined
    await Promise.all([loadRoots(), loadFiles()])
  } catch (error) {
    setError(error)
  }
}

async function scanRoot(root: LibraryRootDto) {
  try {
    errorMessage.value = ''
    scanningId.value = root.id
    await api.scanRoot(root.id)
    await Promise.all([loadRoots(), loadFiles()])
  } catch (error) {
    setError(error)
  } finally {
    scanningId.value = null
  }
}

async function loadFiles(resetPage = false) {
  try {
    errorMessage.value = ''
    if (resetPage) page.value = 1
    const result = await api.searchFiles({
      page: page.value,
      pageSize,
      mediaType: mediaType.value,
      keyword: keyword.value,
      rootId: rootId.value,
    })
    files.value = result.items
    total.value = result.total
    if (!selectedFile.value || !files.value.some((file) => file.id === selectedFile.value?.id)) {
      selectedFile.value = null
      textPreview.value = null
    }
  } catch (error) {
    setError(error)
  }
}

async function openClientRoot(id: number) {
  rootId.value = id
  isBrowsingRoots.value = false
  await loadFiles(true)
}

function backToRoots() {
  isBrowsingRoots.value = true
  rootId.value = undefined
  selectedFile.value = null
  textPreview.value = null
}

async function selectFile(file: FileRecordDto | null) {
  selectedFile.value = file
  textPreview.value = null
  if (!file || file.mediaType !== 'text') return

  try {
    textPreview.value = await api.getTextPreview(file.id)
  } catch (error) {
    setError(error)
  }
}

async function changePage(next: number) {
  page.value = Math.min(Math.max(1, next), totalPages.value)
  await loadFiles()
}

async function refreshAll() {
  await Promise.all([loadRoots(), loadFiles()])
}

async function loadQrCode() {
  try {
    qrCodeData.value = await api.qrCode()
    showQrCode.value = true
  } catch (error) {
    setError(error)
  }
}

onMounted(async () => {
  loading.value = true
  try {
    await loadRoots()
    if (isAdminPage.value) {
      await loadDrives()
    } else {
      total.value = activeRoots.value.reduce((sum, root) => sum + root.fileCount, 0)
    }
  } catch (error) {
    setError(error)
  } finally {
    loading.value = false
  }
})
</script>

<template>
  <main v-if="isAdminPage" class="admin-shell">
    <header class="admin-hero">
      <div>
        <p class="eyebrow">FileShare Admin</p>
        <h1>文件库管理</h1>
        <p>添加服务器本机磁盘或目录，系统按状态定时扫描，异常目录会自动下线并停止自动扫描。</p>
      </div>
      <div class="admin-metrics">
        <div>
          <strong>{{ roots.length }}</strong>
          <span>目录</span>
        </div>
        <div>
          <strong>{{ activeRoots.length }}</strong>
          <span>正常启用</span>
        </div>
        <div>
          <strong>{{ totalRootFiles }}</strong>
          <span>入库文件</span>
        </div>
      </div>
    </header>

    <p v-if="errorMessage" class="error-banner">{{ errorMessage }}</p>

    <section class="admin-layout">
      <section class="admin-card path-card">
        <div class="card-heading">
          <div>
            <h2>添加扫描目录</h2>
            <p>选择服务器路径，或直接输入绝对路径。</p>
          </div>
          <a href="/" class="client-link">客户端</a>
        </div>

        <label class="field">
          <span>服务器路径</span>
          <div class="inline-form">
            <input v-model="manualPath" type="text" placeholder="例如 D:\Media 或 E:\" />
            <button class="primary-button" type="button" :disabled="loading || !manualPath" @click="addRoot()">添加并扫描</button>
          </div>
        </label>

        <div class="admin-browser">
          <div class="drive-list">
            <h3>磁盘</h3>
            <button
              v-for="drive in drives"
              :key="drive.name"
              class="drive-row"
              type="button"
              :disabled="!drive.isReady"
              @click="openDirectory(drive.rootDirectory)"
            >
              <span>{{ drive.displayName }}</span>
              <small>{{ drive.driveType }} · {{ drive.availableFreeSpace !== null ? formatSize(drive.availableFreeSpace) : '不可用' }}</small>
            </button>
          </div>

          <div class="directory-list">
            <div class="browser-header">
              <h3>目录</h3>
              <button type="button" class="text-button" :disabled="!currentPath" @click="addRoot(currentPath)">添加当前目录</button>
            </div>
            <p class="current-path">{{ currentPath || '请选择一个磁盘' }}</p>
            <button
              v-for="directory in directories"
              :key="directory.fullPath"
              class="directory-row"
              type="button"
              @click="openDirectory(directory.fullPath)"
            >
              {{ directory.name }}
            </button>
          </div>
        </div>
      </section>

      <section class="admin-card roots-card">
        <div class="card-heading">
          <div>
            <h2>目录状态</h2>
            <p>异常目录不会自动扫描，客户端也无法访问其中的文件；手动扫描成功后恢复正常。</p>
          </div>
          <button class="secondary-button" type="button" :disabled="loading" @click="refreshAll">刷新</button>
        </div>

        <div class="root-table">
          <article v-for="root in roots" :key="root.id" class="root-item">
            <div class="root-main">
              <span :class="['status-pill', root.isAvailable ? 'ok' : 'bad']">{{ root.isAvailable ? '正常' : '异常' }}</span>
              <div>
                <strong>{{ root.displayName }}</strong>
                <p>{{ root.path }}</p>
              </div>
            </div>
            <div class="root-meta">
              <span>{{ root.fileCount }} 个文件</span>
              <span>{{ formatDate(root.lastScanCompletedAt) }}</span>
              <span>{{ root.isEnabled ? '启用' : '停用' }}</span>
            </div>
            <p v-if="root.lastScanError" class="root-error">{{ root.lastScanError }}</p>
            <div class="root-actions">
              <button type="button" class="secondary-button" @click="scanRoot(root)">
                {{ scanningId === root.id ? '扫描中' : root.isAvailable ? '立即扫描' : '手动扫描恢复' }}
              </button>
              <button type="button" class="secondary-button" :disabled="!root.isAvailable" @click="toggleRoot(root)">
                {{ root.isEnabled ? '停用' : '启用' }}
              </button>
              <button type="button" class="danger-button" @click="deleteRoot(root)">删除</button>
            </div>
          </article>
          <p v-if="roots.length === 0" class="empty-state">还没有添加扫描目录</p>
        </div>
      </section>
    </section>
  </main>

  <main v-else class="client-shell">
    <header class="mobile-header">
      <div>
        <h1>{{ clientTitle }}</h1>
        <p>{{ isBrowsingRoots ? `${activeRoots.length} 个目录` : `${total} 个文件` }}</p>
      </div>
      <div class="mobile-header-actions">
        <button v-if="!isBrowsingRoots" type="button" class="back-button" @click="backToRoots">返回</button>
        <button type="button" class="qr-button" title="生成二维码" @click="loadQrCode">二维码</button>
        <a href="/admin" class="admin-link">管理</a>
      </div>
    </header>

    <p v-if="errorMessage" class="error-banner">{{ errorMessage }}</p>

    <section v-if="isBrowsingRoots" class="root-picker">
      <button
        v-for="root in activeRoots"
        :key="root.id"
        class="root-tile"
        type="button"
        @click="openClientRoot(root.id)"
      >
        <span>{{ root.displayName }}</span>
        <strong>{{ root.fileCount }}</strong>
        <small>{{ root.path }}</small>
      </button>

      <p v-if="activeRoots.length === 0" class="empty-state">暂无可访问目录</p>
    </section>

    <section v-else class="mobile-filters">
      <input v-model="keyword" type="search" placeholder="搜索文件" @keyup.enter="loadFiles(true)" />
      <div class="filter-row">
        <select v-model="mediaType" @change="loadFiles(true)">
          <option value="all">全部</option>
          <option value="video">视频</option>
          <option value="audio">音频</option>
          <option value="text">文本</option>
        </select>
        <select v-model="rootId" @change="loadFiles(true)">
          <option v-for="root in availableRoots" :key="root.id" :value="root.id">{{ root.displayName }}</option>
        </select>
        <button class="primary-button" type="button" @click="loadFiles(true)">查询</button>
      </div>
    </section>

    <section v-if="!isBrowsingRoots" class="player-panel">
      <p v-if="!selectedFile" class="empty-state">请选择一个文件</p>

      <template v-else>
      <div class="player-title">
        <div>
          <h2>{{ selectedFile.fileName }}</h2>
          <p>{{ selectedRoot?.displayName ?? '文件库' }} · {{ selectedFile.relativePath }}</p>
        </div>
        <span>{{ selectedFile.extension }}</span>
      </div>

      <video
        v-if="selectedFile.mediaType === 'video' && selectedFile.browserPlayable"
        :key="selectedFile.id"
        controls
        playsinline
        webkit-playsinline
        preload="metadata"
      >
        <source :src="selectedMediaUrl" :type="selectedFile.contentType" />
      </video>
      <audio
        v-else-if="selectedFile.mediaType === 'audio' && selectedFile.browserPlayable"
        :key="selectedFile.id"
        controls
        preload="metadata"
      >
        <source :src="selectedMediaUrl" :type="selectedFile.contentType" />
      </audio>
      <pre v-else-if="selectedFile.mediaType === 'text'">{{ textPreview?.content ?? '加载中...' }}</pre>
      <p v-else class="unsupported">浏览器不支持在线播放此格式。</p>
      <a
        v-if="selectedFile.mediaType !== 'text'"
        class="open-media-link"
        :href="selectedMediaUrl"
        target="_blank"
        rel="noreferrer"
      >
        新窗口打开原视频/音频
      </a>
      <p v-if="textPreview?.truncated" class="hint">文本超过 1 MB，已截断显示。</p>
      </template>
    </section>

    <section v-if="!isBrowsingRoots" class="mobile-list">
      <button
        v-for="file in files"
        :key="file.id"
        class="mobile-file"
        :class="{ active: selectedFile?.id === file.id }"
        type="button"
        @click="selectFile(file)"
      >
        <span class="type-badge">{{ file.mediaType }}</span>
        <span>
          <strong>{{ file.fileName }}</strong>
          <small>{{ file.relativePath }}</small>
          <small>
            {{ formatSize(file.sizeBytes) }} · {{ formatDate(file.lastWriteTimeUtc) }}
            <template v-if="file.mediaType !== 'text' && !file.browserPlayable"> · 手机可能不支持</template>
          </small>
        </span>
      </button>

      <p v-if="files.length === 0" class="empty-state">暂无可查看文件</p>
    </section>

    <nav v-if="!isBrowsingRoots" class="mobile-pager">
      <button type="button" :disabled="page <= 1" @click="changePage(page - 1)">上一页</button>
      <span>{{ page }} / {{ totalPages }}</span>
      <button type="button" :disabled="page >= totalPages" @click="changePage(page + 1)">下一页</button>
    </nav>

    <Teleport to="body">
      <div v-if="showQrCode" class="qr-overlay" @click.self="showQrCode = false">
        <div class="qr-modal">
          <h2>扫码访问</h2>
          <img v-if="qrCodeData" :src="qrCodeData.qrCodeBase64" alt="QR Code" class="qr-image" />
          <p v-else class="qr-hint">加载中...</p>
          <p class="qr-hint">使用手机扫描二维码，即可在局域网中打开此网站</p>
          <button type="button" class="primary-button qr-close" @click="showQrCode = false">关闭</button>
        </div>
      </div>
    </Teleport>
  </main>
</template>
