<script setup lang="ts">
import {
  ArrowLeft,
  CircleAlert,
  FileText,
  Folder,
  Loader2,
  RefreshCw,
  X,
} from '@lucide/vue'
import { computed, onMounted, ref } from 'vue'
import { apiFetch } from '../../services/api'

interface WorkspaceEntry {
  path: string
  name: string
  kind: string
  size: number | null
  updatedAt: string | null
}

interface WorkspaceCollection {
  agentId: string
  path: string
  parentPath: string | null
  entries: WorkspaceEntry[]
  totalEntries: number
  offset: number
  checkedAt: string
}

interface WorkspaceFile {
  agentId: string
  path: string
  name: string
  size: number
  updatedAt: string | null
  mimeType: string
  encoding: string
  content: string
  contentHash: string
  checkedAt: string
}

const props = defineProps<{ agentId: string }>()
const collection = ref<WorkspaceCollection | null>(null)
const selectedFile = ref<WorkspaceFile | null>(null)
const loading = ref(false)
const error = ref('')

const currentLabel = computed(() => collection.value?.path || 'Workspace root')

async function loadDirectory(path = '') {
  loading.value = true
  error.value = ''
  selectedFile.value = null
  try {
    const query = new URLSearchParams({ path, offset: '0', limit: '250' })
    const response = await apiFetch(
      `/api/v1/openclaw/agents/${encodeURIComponent(props.agentId)}/workspace?${query}`,
    )
    const payload = await response.json().catch(() => null) as
      | WorkspaceCollection
      | { message?: string }
      | null
    if (!response.ok) throw new Error((payload as { message?: string } | null)?.message || `HTTP ${response.status}`)
    collection.value = payload as WorkspaceCollection
  } catch (cause) {
    error.value = cause instanceof Error ? cause.message : 'Workspace konnte nicht geladen werden.'
  } finally {
    loading.value = false
  }
}

async function openEntry(entry: WorkspaceEntry) {
  if (entry.kind === 'directory' || entry.kind === 'folder') {
    await loadDirectory(entry.path)
    return
  }

  loading.value = true
  error.value = ''
  try {
    const query = new URLSearchParams({ path: entry.path })
    const response = await apiFetch(
      `/api/v1/openclaw/agents/${encodeURIComponent(props.agentId)}/workspace/file?${query}`,
    )
    const payload = await response.json().catch(() => null) as
      | WorkspaceFile
      | { message?: string }
      | null
    if (!response.ok) throw new Error((payload as { message?: string } | null)?.message || `HTTP ${response.status}`)
    selectedFile.value = payload as WorkspaceFile
  } catch (cause) {
    error.value = cause instanceof Error ? cause.message : 'Workspace-Datei konnte nicht geladen werden.'
  } finally {
    loading.value = false
  }
}

function formatSize(size: number | null) {
  if (size === null) return '—'
  if (size < 1024) return `${size} B`
  return `${(size / 1024).toFixed(1)} KB`
}

onMounted(() => loadDirectory())
</script>

<template>
  <section class="workspace-browser" aria-labelledby="workspace-browser-title">
    <header>
      <div>
        <span class="eyebrow">READ-ONLY WORKSPACE</span>
        <h3 id="workspace-browser-title">Zusätzliche Agent-Dateien</h3>
        <p>Custom-Dokumente werden sicher über OpenClaw gelesen und bleiben unverändert.</p>
      </div>
      <button
        type="button"
        class="nexus-button"
        :disabled="loading"
        @click="loadDirectory(collection?.path || '')"
      >
        <Loader2 v-if="loading" :size="14" class="spin" aria-hidden="true" />
        <RefreshCw v-else :size="14" aria-hidden="true" />
        Aktualisieren
      </button>
    </header>

    <div class="workspace-path">
      <button
        type="button"
        class="nexus-button"
        :disabled="!collection?.parentPath && collection?.path === ''"
        @click="loadDirectory(collection?.parentPath || '')"
      >
        <ArrowLeft :size="14" aria-hidden="true" />
        Eine Ebene hoch
      </button>
      <code>{{ currentLabel }}</code>
      <span>{{ collection?.totalEntries ?? 0 }} Einträge</span>
    </div>

    <div v-if="error" class="workspace-state workspace-state--error" role="alert">
      <CircleAlert :size="17" aria-hidden="true" />
      <p>{{ error }}</p>
      <button type="button" class="nexus-button" @click="loadDirectory(collection?.path || '')">Erneut laden</button>
    </div>
    <div v-else-if="loading && !collection" class="workspace-state" role="status">
      <Loader2 :size="17" class="spin" aria-hidden="true" />
      <p>Workspace wird geladen…</p>
    </div>
    <div v-else-if="collection?.entries.length" class="workspace-list">
      <button
        v-for="entry in collection.entries"
        :key="entry.path"
        type="button"
        class="workspace-entry"
        @click="openEntry(entry)"
      >
        <Folder v-if="entry.kind === 'directory' || entry.kind === 'folder'" :size="16" aria-hidden="true" />
        <FileText v-else :size="16" aria-hidden="true" />
        <span><strong>{{ entry.name }}</strong><code>{{ entry.path }}</code></span>
        <small>{{ formatSize(entry.size) }}</small>
      </button>
    </div>
    <div v-else class="workspace-state">
      <Folder :size="17" aria-hidden="true" />
      <p>OpenClaw meldet in diesem Ordner keine lesbaren Einträge.</p>
    </div>

    <div v-if="selectedFile" class="workspace-preview">
      <header>
        <div>
          <strong>{{ selectedFile.name }}</strong>
          <code>{{ selectedFile.path }} · sha256:{{ selectedFile.contentHash.slice(0, 12) }}</code>
        </div>
        <button type="button" aria-label="Dateivorschau schließen" @click="selectedFile = null">
          <X :size="16" aria-hidden="true" />
        </button>
      </header>
      <pre tabindex="0">{{ selectedFile.content }}</pre>
    </div>
  </section>
</template>

<style scoped>
.workspace-browser { display: grid; gap: 12px; margin-top: 16px; padding: 15px; border: 1px solid var(--line); border-radius: var(--r); background: var(--glass); }
.workspace-browser > header, .workspace-path, .workspace-entry, .workspace-preview > header { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.workspace-browser h3 { margin: 3px 0 0; font-family: var(--font-display); font-size: 15px; }
.workspace-browser header p { margin: 4px 0 0; color: var(--tx-3); line-height: 1.5; }
.workspace-path { min-width: 0; padding: 9px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--accent-wash); }
.workspace-path code { min-width: 0; overflow: hidden; color: var(--tx-2); font-family: var(--font-mono-v2); font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
.workspace-path > span { flex: 0 0 auto; color: var(--tx-3); font-size: 11px; }
.workspace-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px; }
.workspace-entry { min-width: 0; padding: 10px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--accent-wash); color: var(--tx-2); text-align: left; cursor: pointer; }
.workspace-entry:hover { border-color: var(--line-3); }
.workspace-entry > svg { flex: 0 0 auto; color: var(--a-mid); }
.workspace-entry > span { display: grid; flex: 1; gap: 3px; min-width: 0; }
.workspace-entry strong, .workspace-entry code { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.workspace-entry code, .workspace-entry small { color: var(--tx-3); font-family: var(--font-mono-v2); font-size: 10px; }
.workspace-state { display: flex; align-items: center; gap: 9px; min-height: 58px; padding: 12px; border: 1px dashed var(--line-2); border-radius: var(--r-sm); color: var(--tx-3); }
.workspace-state p { flex: 1; margin: 0; }
.workspace-state--error { border-style: solid; border-color: var(--status-block-line); background: var(--status-block-bg); color: var(--st-block); }
.workspace-preview { overflow: hidden; border: 1px solid var(--line-2); border-radius: var(--r-sm); }
.workspace-preview > header { padding: 11px 13px; border-bottom: 1px solid var(--line); background: var(--accent-wash); }
.workspace-preview header div { display: grid; gap: 3px; min-width: 0; }
.workspace-preview header code { overflow-wrap: anywhere; color: var(--tx-3); font-family: var(--font-mono-v2); font-size: 10px; }
.workspace-preview header button { width: 34px; height: 34px; display: grid; place-items: center; flex: 0 0 auto; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--glass); color: var(--tx-2); cursor: pointer; }
.workspace-preview pre { max-height: 420px; margin: 0; overflow: auto; padding: 14px; background: var(--field-surface); color: var(--tx-2); font-family: var(--font-mono-v2); font-size: 11px; line-height: 1.6; white-space: pre-wrap; overflow-wrap: anywhere; }
.spin { animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

@media (max-width: 680px) {
  .workspace-browser > header, .workspace-path { align-items: flex-start; flex-direction: column; }
  .workspace-list { grid-template-columns: 1fr; }
  .workspace-path code { white-space: normal; overflow-wrap: anywhere; }
}
</style>
