<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useInstancesStore } from '@/stores/instances'
import { useFilesStore } from '@/stores/files'
import { useToastStore } from '@/stores/toast'
import { safeDate, safeFileSize } from '@/utils/formatters'
import Panel from '@/components/ds/data/Panel.vue'
import Button from '@/components/ds/core/Button.vue'
import Icon from '@/components/ds/core/Icon.vue'
import Alert from '@/components/ds/feedback/Alert.vue'
import EmptyState from '@/components/ds/feedback/EmptyState.vue'

const router = useRouter()
const instancesStore = useInstancesStore()
const files = useFilesStore()
const toast = useToastStore()

// ---- Editor state ----
const editorPath = ref<string | null>(null)
const editorContent = ref('')
const editorLoading = ref(false)
const editorSaving = ref(false)

// ---- Inline confirm-delete ----
const pendingDelete = ref<string | null>(null)

// ---- Sorted entries: dirs first, then alpha ----
const sortedEntries = computed(() => {
  return [...files.entries].sort((a, b) => {
    if (a.is_dir !== b.is_dir) return a.is_dir ? -1 : 1
    return a.name.localeCompare(b.name)
  })
})

// ---- Breadcrumbs from cwd ----
const breadcrumbs = computed<{ label: string; path: string }[]>(() => {
  const crumbs: { label: string; path: string }[] = [{ label: 'Root', path: '' }]
  if (!files.cwd) return crumbs
  const parts = files.cwd.split('/').filter(Boolean)
  let acc = ''
  for (const p of parts) {
    acc = acc ? `${acc}/${p}` : p
    crumbs.push({ label: p, path: acc })
  }
  return crumbs
})

// ---- Parent path for "Up" button ----
const parentPath = computed<string | null>(() => {
  if (!files.cwd) return null
  const idx = files.cwd.lastIndexOf('/')
  return idx < 0 ? '' : files.cwd.slice(0, idx)
})

// ---- Lifecycle ----
onMounted(async () => {
  await instancesStore.fetchInstances()
  await files.list('')
})

// ---- Instance switch ----
async function onInstanceChange(e: Event) {
  const id = (e.target as HTMLSelectElement).value
  instancesStore.select(id)
  editorPath.value = null
  await files.list('')
}

// ---- Navigation ----
async function navigate(path: string) {
  editorPath.value = null
  pendingDelete.value = null
  await files.list(path)
}

// ---- Open a file in the editor ----
async function openFile(path: string) {
  editorLoading.value = true
  try {
    const content = await files.readFile(path)
    editorPath.value = path
    editorContent.value = content
  } catch (e) {
    toast.error(e instanceof Error ? e.message : 'Cannot open file (binary or too large)')
  } finally {
    editorLoading.value = false
  }
}

function closeEditor() {
  editorPath.value = null
  editorContent.value = ''
}

async function saveFile() {
  if (!editorPath.value) return
  editorSaving.value = true
  try {
    await files.writeFile(editorPath.value, editorContent.value)
    toast.success('File saved')
  } catch (e) {
    toast.error(e instanceof Error ? e.message : 'Failed to save file')
  } finally {
    editorSaving.value = false
  }
}

// ---- Toolbar: New folder ----
async function newFolder() {
  const name = window.prompt('Folder name:')
  if (!name || !name.trim()) return
  if (name.includes('/') || name.includes('\\')) {
    toast.error('Folder name cannot contain path separators')
    return
  }
  try {
    await files.mkdir(files.joinPath(files.cwd, name.trim()))
    toast.success('Folder created')
    await files.list(files.cwd)
  } catch (e) {
    toast.error(e instanceof Error ? e.message : 'Failed to create folder')
  }
}

// ---- Toolbar: New file ----
async function newFile() {
  const name = window.prompt('File name:')
  if (!name || !name.trim()) return
  if (name.includes('/') || name.includes('\\')) {
    toast.error('File name cannot contain path separators')
    return
  }
  try {
    await files.mkfile(files.joinPath(files.cwd, name.trim()))
    toast.success('File created')
    await files.list(files.cwd)
  } catch (e) {
    toast.error(e instanceof Error ? e.message : 'Failed to create file')
  }
}

// ---- Row: Rename ----
async function renameEntry(path: string, isDir: boolean) {
  const current = path.split('/').pop() ?? path
  const name = window.prompt('New name:', current)
  if (!name || !name.trim() || name.trim() === current) return
  if (name.includes('/') || name.includes('\\')) {
    toast.error('Name cannot contain path separators')
    return
  }
  try {
    await files.rename(path, name.trim())
    toast.success(`${isDir ? 'Folder' : 'File'} renamed`)
    await files.list(files.cwd)
    // If currently editing the renamed file, close editor
    if (editorPath.value === path) closeEditor()
  } catch (e) {
    toast.error(e instanceof Error ? e.message : 'Failed to rename')
  }
}

// ---- Row: Delete ----
async function confirmDelete(path: string) {
  try {
    await files.del(path)
    toast.success('Deleted')
    pendingDelete.value = null
    await files.list(files.cwd)
    if (editorPath.value === path) closeEditor()
  } catch (e) {
    toast.error(e instanceof Error ? e.message : 'Failed to delete')
  }
}
</script>

<template>
  <div class="fm">
    <!-- Page head -->
    <div class="fm__head">
      <div class="fm__head-id">
        <div class="fm__head-chip">
          <Icon name="folder-open" :size="20" :stroke-width="2" />
        </div>
        <div>
          <div class="t-eyebrow">Server management</div>
          <h1 class="fm__title">File manager</h1>
        </div>
      </div>
    </div>

    <!-- No instances at all -->
    <Panel v-if="!instancesStore.loading && instancesStore.instances.length === 0">
      <EmptyState
        icon="server"
        title="No re-Agent connected"
        description="Install re-Agent from the Server page to manage files on your game server."
      >
        <template #action>
          <Button variant="secondary" size="sm" icon="server" @click="router.push('/server')">
            Go to Server page
          </Button>
        </template>
      </EmptyState>
    </Panel>

    <template v-else>
      <!-- Instance selector -->
      <div v-if="instancesStore.instances.length > 1" class="fm__instance-pick">
        <span class="fm__field-label">Instance</span>
        <select
          class="fm__select"
          :value="instancesStore.currentId ?? ''"
          @change="onInstanceChange"
        >
          <option v-for="inst in instancesStore.instances" :key="inst.id" :value="inst.id">
            {{ inst.label || inst.agent_instance_id }} ({{ inst.game }}) · {{ inst.host_hostname }}
          </option>
        </select>
      </div>

      <!-- File browser panel -->
      <Panel :flush-body="true">
        <template #title>
          <!-- Breadcrumb -->
          <div class="fm__breadcrumb">
            <button
              v-for="(crumb, i) in breadcrumbs"
              :key="crumb.path"
              class="fm__crumb"
              :class="{ 'fm__crumb--active': i === breadcrumbs.length - 1 }"
              :disabled="i === breadcrumbs.length - 1"
              @click="navigate(crumb.path)"
            >{{ crumb.label }}</button>
          </div>
        </template>

        <template #actions>
          <!-- Up button -->
          <Button
            v-if="parentPath !== null"
            variant="ghost"
            size="sm"
            icon="chevron-left"
            :disabled="files.loading"
            @click="navigate(parentPath!)"
          >
            Up
          </Button>
          <Button
            variant="ghost"
            size="sm"
            icon="folder-open"
            :disabled="files.loading"
            @click="newFolder"
          >
            New folder
          </Button>
          <Button
            variant="ghost"
            size="sm"
            icon="file-text"
            :disabled="files.loading"
            @click="newFile"
          >
            New file
          </Button>
          <Button
            variant="ghost"
            size="sm"
            icon="refresh-cw"
            :disabled="files.loading"
            :loading="files.loading"
            @click="files.list(files.cwd)"
          />
        </template>

        <!-- Error state -->
        <div v-if="files.error && !files.loading" class="fm__padded">
          <Alert tone="danger" :title="files.error">
            <template #actions>
              <Button variant="danger-soft" size="sm" icon="refresh-cw" @click="files.list(files.cwd)">
                Retry
              </Button>
            </template>
          </Alert>
        </div>

        <!-- Loading skeleton -->
        <div v-else-if="files.loading" class="fm__padded fm__loading">
          <Icon name="loader" :size="18" :stroke-width="2" class="fm__spinner" />
          <span class="fm__loading-text">Loading…</span>
        </div>

        <!-- Empty directory -->
        <EmptyState
          v-else-if="sortedEntries.length === 0"
          icon="folder-open"
          title="Empty directory"
          description="This directory contains no files or folders."
        />

        <!-- Entry table -->
        <table v-else class="fm__table">
          <thead>
            <tr>
              <th class="fm__th fm__th--name">Name</th>
              <th class="fm__th fm__th--size">Size</th>
              <th class="fm__th fm__th--date">Modified</th>
              <th class="fm__th fm__th--actions"></th>
            </tr>
          </thead>
          <tbody>
            <tr
              v-for="entry in sortedEntries"
              :key="entry.path"
              class="fm__row"
              :class="{ 'fm__row--active': editorPath === entry.path }"
            >
              <!-- Name -->
              <td class="fm__td fm__td--name">
                <button
                  class="fm__entry-btn"
                  @click="entry.is_dir ? navigate(entry.path) : openFile(entry.path)"
                >
                  <Icon
                    :name="entry.is_dir ? 'folder-open' : 'file-text'"
                    :size="15"
                    :stroke-width="1.75"
                    class="fm__entry-icon"
                    :class="entry.is_dir ? 'fm__entry-icon--dir' : 'fm__entry-icon--file'"
                  />
                  <span class="fm__entry-name">{{ entry.name }}</span>
                  <Icon v-if="entry.is_dir" name="chevron-right" :size="13" :stroke-width="2" class="fm__entry-chevron" />
                </button>
              </td>

              <!-- Size -->
              <td class="fm__td fm__td--size">
                {{ entry.is_dir ? '—' : safeFileSize(entry.size, '0 B') }}
              </td>

              <!-- Modified -->
              <td class="fm__td fm__td--date">{{ safeDate(entry.modified) }}</td>

              <!-- Row actions -->
              <td class="fm__td fm__td--actions">
                <!-- Pending delete confirm -->
                <template v-if="pendingDelete === entry.path">
                  <span class="fm__del-confirm-label">Delete?</span>
                  <Button
                    variant="danger"
                    size="sm"
                    @click="confirmDelete(entry.path)"
                  >
                    Yes
                  </Button>
                  <Button
                    variant="ghost"
                    size="sm"
                    @click="pendingDelete = null"
                  >
                    Cancel
                  </Button>
                </template>
                <template v-else>
                  <Button
                    variant="ghost"
                    size="sm"
                    icon="pencil"
                    :title="`Rename ${entry.name}`"
                    @click="renameEntry(entry.path, entry.is_dir)"
                  />
                  <Button
                    variant="ghost"
                    size="sm"
                    icon="trash-2"
                    :title="`Delete ${entry.name}`"
                    @click="pendingDelete = entry.path"
                  />
                </template>
              </td>
            </tr>
          </tbody>
        </table>
      </Panel>

      <!-- File editor panel -->
      <Panel v-if="editorPath !== null" :title="editorPath">
        <template #actions>
          <Button
            variant="primary"
            size="sm"
            icon="save"
            :loading="editorSaving"
            @click="saveFile"
          >
            Save
          </Button>
          <Button variant="ghost" size="sm" icon="x" @click="closeEditor">Close</Button>
        </template>

        <div v-if="editorLoading" class="fm__padded fm__loading">
          <Icon name="loader" :size="18" :stroke-width="2" class="fm__spinner" />
          <span class="fm__loading-text">Loading file…</span>
        </div>
        <textarea
          v-else
          v-model="editorContent"
          class="fm__editor"
          spellcheck="false"
          autocomplete="off"
          autocorrect="off"
          autocapitalize="off"
        />
      </Panel>
    </template>
  </div>
</template>

<style scoped>
.fm {
  max-width: 1480px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* Page head */
.fm__head { display: flex; align-items: center; gap: 12px; }
.fm__head-id { display: flex; align-items: center; gap: 12px; }
.fm__head-chip {
  width: 40px; height: 40px; flex: none; border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center;
  color: var(--accent); background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px var(--accent-border);
}
.fm__title {
  font-size: var(--text-2xl); font-weight: 700; letter-spacing: -0.02em;
  color: var(--text-primary); margin-top: 3px;
}

/* Instance selector */
.fm__instance-pick { display: flex; align-items: center; gap: 12px; }
.fm__field-label { font-size: var(--text-sm); font-weight: 500; color: var(--text-tertiary); }
.fm__select {
  background: var(--surface-base);
  color: var(--text-primary);
  border: none;
  box-shadow: var(--ring-subtle);
  border-radius: var(--radius-md);
  padding: 8px 12px;
  font-size: var(--text-sm);
  font-family: var(--font-mono);
  min-width: 280px;
}

/* Breadcrumb */
.fm__breadcrumb { display: flex; align-items: center; gap: 2px; flex-wrap: wrap; }
.fm__crumb {
  background: none; border: none; cursor: pointer; padding: 0 4px;
  font-size: var(--text-sm); font-weight: 500; color: var(--text-secondary);
  border-radius: var(--radius-sm); transition: var(--transition-colors);
}
.fm__crumb:hover:not(:disabled) { color: var(--text-primary); background: var(--surface-hover); }
.fm__crumb:disabled { cursor: default; }
.fm__crumb--active { color: var(--text-primary); font-weight: 600; }
.fm__crumb:not(:last-child)::after { content: '/'; margin-left: 4px; color: var(--text-muted); }

/* Loading */
.fm__padded { padding: 24px 16px; }
.fm__loading { display: flex; align-items: center; gap: 10px; }
.fm__spinner { animation: fm-spin 0.75s linear infinite; color: var(--text-tertiary); }
@keyframes fm-spin { to { transform: rotate(360deg); } }
.fm__loading-text { font-size: var(--text-sm); color: var(--text-tertiary); }

/* Table */
.fm__table {
  width: 100%; border-collapse: collapse;
  font-size: var(--text-sm); table-layout: fixed;
}
.fm__th {
  padding: 9px 14px; font-size: var(--text-xs); font-weight: 600;
  color: var(--text-tertiary); text-align: left;
  border-bottom: 1px solid var(--border-subtle);
  text-transform: uppercase; letter-spacing: var(--tracking-wider);
}
.fm__th--name { width: auto; }
.fm__th--size { width: 90px; }
.fm__th--date { width: 180px; }
.fm__th--actions { width: 130px; }

.fm__row { transition: background var(--dur-fast) var(--ease-standard); }
.fm__row:hover { background: var(--surface-hover); }
.fm__row--active { background: var(--accent-soft); }
.fm__row + .fm__row { border-top: 1px solid var(--border-subtle); }

.fm__td {
  padding: 8px 14px; color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fm__td--name { width: auto; }
.fm__td--size { text-align: right; font-family: var(--font-mono); font-size: var(--text-xs); }
.fm__td--date { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-muted); }
.fm__td--actions {
  text-align: right;
  display: flex; align-items: center; justify-content: flex-end; gap: 2px;
  padding-top: 6px; padding-bottom: 6px;
}

/* Entry button */
.fm__entry-btn {
  display: inline-flex; align-items: center; gap: 8px;
  background: none; border: none; cursor: pointer; padding: 0;
  color: var(--text-primary); font-size: var(--text-sm); font-weight: 500;
  max-width: 100%; text-align: left;
}
.fm__entry-btn:hover .fm__entry-name { text-decoration: underline; text-decoration-color: var(--border-subtle); }
.fm__entry-icon--dir { color: var(--accent); }
.fm__entry-icon--file { color: var(--text-tertiary); }
.fm__entry-name {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-family: var(--font-mono); font-size: var(--text-xs);
}
.fm__entry-chevron { color: var(--text-muted); flex: none; }

/* Inline delete confirm */
.fm__del-confirm-label {
  font-size: var(--text-xs); font-weight: 600; color: var(--danger);
  margin-right: 6px;
}

/* File editor textarea */
.fm__editor {
  width: 100%;
  min-height: 400px;
  background: var(--surface-base);
  color: var(--text-primary);
  border: none;
  box-shadow: var(--ring-subtle);
  border-radius: var(--radius-md);
  padding: 14px 16px;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  line-height: 1.6;
  resize: vertical;
  outline: none;
  display: block;
}
.fm__editor:focus { box-shadow: var(--focus-ring); }
</style>
