<script setup lang="ts">
import { ref, computed, onMounted, watch, nextTick, defineAsyncComponent } from 'vue'
import { useDisplay } from 'vuetify'
import { useModuleStore, useIntegrationStore } from '@KTXC'
import { useFileManager, useFileSelection, useFileUpload, useFileEditor } from '@/composables'
import type { ViewMode, SortField, SortOrder, BreadcrumbItem } from '@/types'
import { CollectionObject } from '@DocumentsManager/models/collection'
import { EntityObject } from '@DocumentsManager/models/entity'
import { ServiceObject } from '@DocumentsManager/models/service'
import { useServicesStore } from '@DocumentsManager/stores/servicesStore'

// Components
import FilesToolbar from '@/components/FilesToolbar.vue'
import Sidebar from '@/components/Sidebar.vue'
import FilesBreadcrumbs from '@/components/FilesBreadcrumbs.vue'
import FilesEmptyState from '@/components/FilesEmptyState.vue'
import FilesDragOverlay from '@/components/FilesDragOverlay.vue'
import FilesInfoPanel from '@/components/FilesInfoPanel.vue'
import FilesGridView from '@/components/views/FilesGridView.vue'
import FilesListView from '@/components/views/FilesListView.vue'
import FilesDetailsView from '@/components/views/FilesDetailsView.vue'
import FileEditorDialog from '@/components/editor/FileEditorDialog.vue'
import NewFolderDialog from '@/components/dialogs/NewFolderDialog.vue'
import RenameDialog from '@/components/dialogs/RenameDialog.vue'
import DeleteConfirmDialog from '@/components/dialogs/DeleteConfirmDialog.vue'
import UploadDialog from '@/components/dialogs/UploadDialog.vue'

// Check if file manager is available
const display = useDisplay()
const isMobile = computed(() => display.mdAndDown.value)

const moduleStore = useModuleStore()
const integrationStore = useIntegrationStore()
const isFileManagerAvailable = computed(() => {
  return moduleStore.has('documents_manager') || moduleStore.has('DocumentsManager')
})

const servicesStore = useServicesStore()

// Active provider/service (will be selectable later)
const activeProviderId = ref('default')
const activeServiceId = ref('personal')

// File manager composable
const fileManager = useFileManager({
  providerId: activeProviderId,
  serviceId: activeServiceId,
})

// Selection composable
const selection = useFileSelection({ multiple: true })

// Upload composable
const upload = useFileUpload({
  providerId: activeProviderId,
  serviceId: activeServiceId,
})

// Keep upload collection in sync with current location
watch(() => fileManager.currentLocation.value, (newLocation) => {
  upload.setCollection(newLocation)
})

watch(() => fileManager.error.value, (message) => {
  if (message) {
    notify(message, 'error')
  }
})

// View state
const viewMode = ref<ViewMode>('grid')
const sortField = ref<SortField>('label')
const sortOrder = ref<SortOrder>('asc')
const sidebarVisible = ref(true)
const searchQuery = ref('')

// Dialogs
const showNewFolderDialog = ref(false)
const showRenameDialog = ref(false)
const showDeleteDialog = ref(false)
const showUploadDialog = ref(false)
const nodeToRename = ref<CollectionObject | EntityObject | null>(null)
const nodesToDelete = ref<(CollectionObject | EntityObject)[]>([])

// Drag and drop state
const isDragOver = ref(false)

// Notifications
const snackbarVisible = ref(false)
const snackbarMessage = ref('')
const snackbarColor = ref<'success' | 'info' | 'warning' | 'error'>('success')

// Upload preparation state
const isPreparingUploads = ref(false)
const uploadPreparationMessage = ref('Preparing uploads...')
const uploadPreparationProcessedCount = ref(0)
const uploadPreparationTotalCount = ref(0)

// Viewer state — the media viewer dialog is provided by the media_viewer module
// and resolved from the integration store so Documents does not import it.
interface ViewerItem {
  id: string
  title: string
  mime: string
  size?: number | null
  meta?: Record<string, unknown>
}

const showViewer = ref(false)
const viewerIndex = ref(0)

const mediaViewerDialog = computed(() => {
  // Integration ids are prefixed with the module handle (e.g. 'media_viewer.dialog').
  const entry = integrationStore.getItems('media_viewer').find(i => i.id.endsWith('.dialog'))
  return entry?.component ? defineAsyncComponent(entry.component as () => Promise<unknown>) : null
})

const viewerItems = computed<ViewerItem[]>(() =>
  sortedItems.value.entities.map(entityToViewerItem),
)

function entityToViewerItem(entity: EntityObject): ViewerItem {
  return {
    id: String(entity.identifier ?? ''),
    title: entity.properties.label ?? String(entity.identifier ?? ''),
    mime: entity.properties.mime ?? '',
    meta: { collection: entity.collection ? String(entity.collection) : null },
  }
}

function resolveViewerSource(item: ViewerItem): string {
  return fileManager.getEntityUrl(item.id, (item.meta?.collection as string | null) ?? null)
}

function downloadViewerItem(item: ViewerItem): void {
  fileManager.downloadEntity(item.id, (item.meta?.collection as string | null) ?? null)
}

// Editor state
const fileEditorComposable = useFileEditor()
const editorEntity = ref<EntityObject | null>(null)
const showEditor = ref(false)

function notify(message: string, color: 'success' | 'info' | 'warning' | 'error' = 'success') {
  snackbarMessage.value = message
  snackbarColor.value = color
  snackbarVisible.value = true
}

function getErrorMessage(error: unknown, fallback: string) {
  return error instanceof Error ? error.message : fallback
}

function beginUploadPreparation(message: string, totalCount: number = 0) {
  isPreparingUploads.value = true
  uploadPreparationMessage.value = message
  uploadPreparationProcessedCount.value = 0
  uploadPreparationTotalCount.value = totalCount
}

function updateUploadPreparation(processedCount: number, totalCount: number) {
  uploadPreparationProcessedCount.value = processedCount
  uploadPreparationTotalCount.value = totalCount
}

function finishUploadPreparation() {
  isPreparingUploads.value = false
  uploadPreparationProcessedCount.value = 0
  uploadPreparationTotalCount.value = 0
}

async function queueFolderUploads(
  filesOrList: FileList | { file: File; relativePath: string }[],
  message: string,
  successMessage: string
) {
  const totalCount = filesOrList.length

  showUploadDialog.value = true
  beginUploadPreparation(message, totalCount)
  await nextTick()

  try {
    await upload.addFilesWithPathsBatched(filesOrList, {
      batchSize: 250,
      onProgress: updateUploadPreparation,
    })

    notify(successMessage, 'info')
  } catch (error) {
    console.error('Failed to prepare uploads:', error)
    notify(getErrorMessage(error, 'Failed to prepare uploads'), 'error')
  } finally {
    finishUploadPreparation()
  }
}

function handleOpenItem(item: CollectionObject | EntityObject) {
  if (item instanceof EntityObject) {
    const id = String(item.identifier ?? '')
    const idx = viewerItems.value.findIndex(m => m.id === id)
    viewerIndex.value = idx >= 0 ? idx : 0
    showViewer.value = true
  } else {
    // Folders: navigate into them when opened via double-click / action
    selection.clear()
    handleFolderOpen(item as CollectionObject)
  }
}

function handleEditItem(item: CollectionObject | EntityObject) {
  if (item instanceof EntityObject && fileEditorComposable.canEdit(item)) {
    editorEntity.value = item
    showEditor.value = true
  }
}

// Hidden file inputs
const fileInputRef = ref<HTMLInputElement | null>(null)
const folderInputRef = ref<HTMLInputElement | null>(null)

function nodeId(node: CollectionObject | EntityObject): string {
  return String(node.identifier ?? '')
}

function nodeLabel(node: CollectionObject | EntityObject): string {
  if (node instanceof EntityObject) {
    return node.properties.label || nodeId(node)
  }
  return node.properties.label || nodeId(node)
}

function renameCurrentName(node: CollectionObject | EntityObject | null): string {
  if (!node) return ''
  if (node instanceof EntityObject) {
    return node.properties.label || nodeId(node)
  }
  return node.properties.label || nodeId(node)
}

// Computed
const breadcrumbs = computed<BreadcrumbItem[]>(() => {
  const items: BreadcrumbItem[] = [
    { id: fileManager.ROOT_ID, label: 'Home', isRoot: true }
  ]
  
  for (const node of fileManager.breadcrumbs.value) {
    items.push({
      id: nodeId(node),
      label: nodeLabel(node),
      isRoot: false,
    })
  }
  
  return items
})

const sortedItems = computed(() => {
  const collections = [...fileManager.currentCollections.value]
  const entities = [...fileManager.currentEntities.value]
  
  // Sort collections
  collections.sort((a, b) => {
    const aVal = sortField.value === 'label'
      ? (a.properties.label || nodeId(a))
      : sortField.value === 'modifiedOn'
        ? (a.modified?.getTime() ?? 0)
        : sortField.value === 'createdOn'
          ? (a.created?.getTime() ?? 0)
          : ''
    const bVal = sortField.value === 'label'
      ? (b.properties.label || nodeId(b))
      : sortField.value === 'modifiedOn'
        ? (b.modified?.getTime() ?? 0)
        : sortField.value === 'createdOn'
          ? (b.created?.getTime() ?? 0)
          : ''
    const cmp = String(aVal).localeCompare(String(bVal))
    return sortOrder.value === 'asc' ? cmp : -cmp
  })
  
  // Sort entities
  entities.sort((a, b) => {
    const aVal = sortField.value === 'label'
      ? (a.properties.label || nodeId(a))
      : sortField.value === 'mime'
        ? (a.properties.mime || '')
        : sortField.value === 'size'
          ? a.properties.size
          : sortField.value === 'modifiedOn'
            ? (a.modified?.getTime() ?? 0)
            : sortField.value === 'createdOn'
              ? (a.created?.getTime() ?? 0)
              : ''
    const bVal = sortField.value === 'label'
      ? (b.properties.label || nodeId(b))
      : sortField.value === 'mime'
        ? (b.properties.mime || '')
        : sortField.value === 'size'
          ? b.properties.size
          : sortField.value === 'modifiedOn'
            ? (b.modified?.getTime() ?? 0)
            : sortField.value === 'createdOn'
              ? (b.created?.getTime() ?? 0)
              : ''
    const cmp = String(aVal).localeCompare(String(bVal))
    return sortOrder.value === 'asc' ? cmp : -cmp
  })
  
  // Filter by search
  const filterFn = (item: CollectionObject | EntityObject) => {
    if (!searchQuery.value) return true
    const label = item instanceof EntityObject
      ? (item.properties.label || nodeId(item))
      : (item.properties.label || nodeId(item))
    return label.toLowerCase().includes(searchQuery.value.toLowerCase())
  }
  
  return {
    collections: collections.filter(filterFn),
    entities: entities.filter(filterFn),
  }
})

const hasItems = computed(() => 
  sortedItems.value.collections.length > 0 || sortedItems.value.entities.length > 0
)

const hasSelection = computed(() => selection.hasSelection.value)

const selectedIds = computed(() => selection.selectedIds.value)

const availableServices = computed<ServiceObject[]>(() => {
  const services = servicesStore.services
  const enabledServices = services.filter(service => service.enabled)
  const source = enabledServices.length > 0 ? enabledServices : services

  return [...source].sort((left, right) => {
    const leftLabel = (left.label || String(left.identifier || '')).toLowerCase()
    const rightLabel = (right.label || String(right.identifier || '')).toLowerCase()
    return leftLabel.localeCompare(rightLabel)
  })
})

function syncActiveService(services: ServiceObject[]) {
  if (services.length === 0) {
    return
  }

  const currentService = services.find(service =>
    service.provider === activeProviderId.value &&
    String(service.identifier ?? '') === activeServiceId.value
  )

  if (currentService) {
    return
  }

  const [nextService] = services
  activeProviderId.value = nextService.provider
  activeServiceId.value = String(nextService.identifier ?? '')
}

watch(availableServices, (services) => {
  syncActiveService(services)
}, { immediate: true })

watch([activeProviderId, activeServiceId], async ([providerId, serviceId], [previousProviderId, previousServiceId]) => {
  if (!providerId || !serviceId) {
    return
  }

  if (providerId === previousProviderId && serviceId === previousServiceId) {
    return
  }

  selection.clear()
  upload.setCollection(fileManager.rootId.value)
  await fileManager.navigateToRoot()
}, { flush: 'post' })

async function handleServiceSelect(service: ServiceObject) {
  const providerId = service.provider
  const serviceId = String(service.identifier ?? '')

  if (providerId === activeProviderId.value && serviceId === activeServiceId.value) {
    return
  }

  activeProviderId.value = providerId
  activeServiceId.value = serviceId
  if (isMobile.value) {
    sidebarVisible.value = false
  }
  notify(`Switched to ${service.label || serviceId}`, 'info')
}

// Navigation methods
async function handleBreadcrumbNavigate(item: BreadcrumbItem) {
  selection.clear()
  await fileManager.navigateTo(item.isRoot ? null : item.id)
}

async function handleFolderOpen(folder: CollectionObject) {
  selection.clear()
  await fileManager.navigateTo(nodeId(folder))
}

// Item interaction methods
function handleItemClick(item: CollectionObject | EntityObject, event: MouseEvent | KeyboardEvent) {
  const hasCtrl = event.ctrlKey || event.metaKey
  const hasShift = event.shiftKey
  
  if (hasCtrl) {
    // Ctrl+click: toggle selection
    selection.toggle(item)
  } else if (hasShift && selection.hasSelection.value) {
    // Shift+click: extend selection
    selection.select(item)
  } else {
    // Single click behavior depends on item type
    if (item instanceof CollectionObject) {
      // Folders: navigate into them
      selection.clear()
      handleFolderOpen(item as CollectionObject)
    } else {
      // Files: show info panel
      selection.clear()
      selection.select(item)
    }
  }
}

// Show details panel for an item
function handleShowDetails(item: CollectionObject | EntityObject) {
  selection.clear()
  selection.select(item)
}

// Folder operations
async function handleCreateFolder(name: string) {
  try {
    await fileManager.createFolder(name)
    showNewFolderDialog.value = false
    notify(`Folder "${name}" created`, 'success')
  } catch (error) {
    console.error('Failed to create folder:', error)
    notify(getErrorMessage(error, 'Failed to create folder'), 'error')
  }
}

// Rename operations - for specific item
function handleRenameItem(item: CollectionObject | EntityObject) {
  nodeToRename.value = item
  showRenameDialog.value = true
}

async function handleRename(newName: string) {
  if (!nodeToRename.value) return
  const currentName = renameCurrentName(nodeToRename.value)
  
  try {
    await fileManager.renameNode(nodeId(nodeToRename.value), newName)
    showRenameDialog.value = false
    nodeToRename.value = null
    notify(`Renamed "${currentName}" to "${newName}"`, 'success')
  } catch (error) {
    console.error('Failed to rename:', error)
    notify(getErrorMessage(error, 'Failed to rename item'), 'error')
  }
}

// Delete operations - for specific item
function handleDeleteItem(item: CollectionObject | EntityObject) {
  nodesToDelete.value = [item]
  showDeleteDialog.value = true
}

async function handleDelete() {
  const deletedCount = nodesToDelete.value.length

  try {
    for (const node of nodesToDelete.value) {
      await fileManager.deleteNode(nodeId(node))
    }
    selection.clear()
    showDeleteDialog.value = false
    nodesToDelete.value = []
    notify(
      deletedCount === 1 ? 'Item deleted' : `${deletedCount} items deleted`,
      'success'
    )
  } catch (error) {
    console.error('Failed to delete:', error)
    notify(getErrorMessage(error, 'Failed to delete selected items'), 'error')
  }
}

// Download operation
function handleDownloadItem(item: CollectionObject | EntityObject) {
  if (item instanceof EntityObject) {
    // Download single file
    fileManager.downloadEntity(nodeId(item), String(item.collection ?? fileManager.ROOT_ID))
    notify(`Download started for "${nodeLabel(item)}"`, 'info')
  } else if (item instanceof CollectionObject) {
    // Download folder as ZIP
    fileManager.downloadCollection(nodeId(item))
    notify(`Archive download started for "${nodeLabel(item)}"`, 'info')
  }
}

// File picker methods
function openFilePicker() {
  fileInputRef.value?.click()
}

function openFolderPicker() {
  folderInputRef.value?.click()
}

function handleFileSelect(event: Event) {
  const input = event.target as HTMLInputElement
  if (input.files && input.files.length > 0) {
    upload.addFiles(input.files)
    showUploadDialog.value = true
    notify(
      input.files.length === 1 ? '1 file added to uploads' : `${input.files.length} files added to uploads`,
      'info'
    )
    input.value = ''
  }
}

async function handleFolderSelect(event: Event) {
  const input = event.target as HTMLInputElement
  if (input.files && input.files.length > 0) {
    await queueFolderUploads(
      input.files,
      'Preparing folder upload...',
      input.files.length === 1
        ? '1 file added from folder upload'
        : `${input.files.length} files added from folder upload`
    )
    input.value = ''
  }
}

// Drag and drop methods
function handleDragOver(event: DragEvent) {
  event.preventDefault()
  isDragOver.value = true
}

function handleDragLeave(event: DragEvent) {
  event.preventDefault()
  isDragOver.value = false
}

async function handleDrop(event: DragEvent) {
  event.preventDefault()
  isDragOver.value = false
  
  if (!event.dataTransfer) return
  
  const items = event.dataTransfer.items
  if (items && items.length > 0) {
    const entries: FileSystemEntry[] = []
    for (let i = 0; i < items.length; i++) {
      const item = items[i]
      if (!item) continue

      const entry = item.webkitGetAsEntry?.()
      if (entry) {
        entries.push(entry)
      }
    }
    
    if (entries.length > 0) {
      showUploadDialog.value = true
      beginUploadPreparation('Scanning dropped folder...')
      await nextTick()

      try {
        const filesWithPaths = await readEntriesRecursively(entries)
        if (filesWithPaths.length > 0) {
          await queueFolderUploads(
            filesWithPaths,
            'Preparing dropped folder upload...',
            filesWithPaths.length === 1 ? '1 file added to uploads' : `${filesWithPaths.length} files added to uploads`
          )
        } else {
          notify('No files found in dropped folder', 'warning')
          finishUploadPreparation()
        }
      } catch (error) {
        finishUploadPreparation()
        console.error('Failed to read dropped folder:', error)
        notify(getErrorMessage(error, 'Failed to read dropped folder'), 'error')
      }

      return
    }
  }
  
  if (event.dataTransfer.files && event.dataTransfer.files.length > 0) {
    upload.addFiles(event.dataTransfer.files)
    showUploadDialog.value = true
    notify(
      event.dataTransfer.files.length === 1 ? '1 file added to uploads' : `${event.dataTransfer.files.length} files added to uploads`,
      'info'
    )
  }
}

async function readEntriesRecursively(
  entries: FileSystemEntry[],
  basePath: string = ''
): Promise<{ file: File; relativePath: string }[]> {
  const results: { file: File; relativePath: string }[] = []
  
  for (const entry of entries) {
    if (entry.isFile) {
      const fileEntry = entry as FileSystemFileEntry
      const file = await new Promise<File>((resolve, reject) => {
        fileEntry.file(resolve, reject)
      })
      const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name
      results.push({ file, relativePath })
    } else if (entry.isDirectory) {
      const dirEntry = entry as FileSystemDirectoryEntry
      const dirReader = dirEntry.createReader()
      const subEntries = await new Promise<FileSystemEntry[]>((resolve, reject) => {
        const allEntries: FileSystemEntry[] = []
        const readBatch = () => {
          dirReader.readEntries((batch) => {
            if (batch.length === 0) {
              resolve(allEntries)
            } else {
              allEntries.push(...batch)
              readBatch()
            }
          }, reject)
        }
        readBatch()
      })
      const subPath = basePath ? `${basePath}/${entry.name}` : entry.name
      const subResults = await readEntriesRecursively(subEntries, subPath)
      results.push(...subResults)
    }
  }
  
  return results
}

// Upload methods
async function handleUploadAll() {
  try {
    await upload.uploadAll()
    await fileManager.refresh()
    notify('Uploads completed', 'success')
  } catch (error) {
    console.error('Failed to upload files:', error)
    notify(getErrorMessage(error, 'Failed to upload files'), 'error')
  }
}

function handleUploadDialogClose() {
  showUploadDialog.value = false
  finishUploadPreparation()
  upload.clearAll()
}

// Refresh
async function handleRefresh() {
  try {
    await fileManager.refresh()
  } catch (error) {
    console.error('Failed to refresh files:', error)
    notify(getErrorMessage(error, 'Failed to refresh files'), 'error')
  }
}

// Initialize
onMounted(async () => {
  try {
    await fileManager.initialize()
    await servicesStore.list()
    syncActiveService(availableServices.value)
    await fileManager.refresh()
    console.log('[Files] - Initialized with:', {
      provider: activeProviderId.value,
      service: activeServiceId.value,
    })
  } catch (error) {
    console.error('[Files] - Failed to initialize:', error)
    notify(getErrorMessage(error, 'Failed to initialize file manager'), 'error')
  }
})
</script>

<template>
  <div v-if="!isFileManagerAvailable" class="files-unavailable">
    <v-alert
      type="warning"
      variant="outlined"
      class="files-unavailable-alert"
    >
      <v-icon size="64" color="warning" class="mb-6">mdi-folder-off-outline</v-icon>
      <h2 class="text-h5 font-weight-bold mb-4">File Manager Not Available</h2>
      <p>
        The File Manager module is not installed or enabled.
        This page requires the <strong>documents_manager</strong> module to function properly.
      </p>
      <p class="mb-0 mt-2">
        Please contact your system administrator to install and enable the
        <code>documents_manager</code> module.
      </p>
    </v-alert>
  </div>

  <div v-else class="files-container">
    <!-- Top Toolbar -->
    <FilesToolbar
      v-model:search-query="searchQuery"
      v-model:view-mode="viewMode"
      :is-loading="fileManager.isLoading.value"
      @toggle-sidebar="sidebarVisible = !sidebarVisible"
      @refresh="handleRefresh"
      @open-file-picker="openFilePicker"
      @open-folder-picker="openFolderPicker"
      @new-folder="showNewFolderDialog = true"
    />

    <!-- Main Content -->
    <div 
      class="files-content"
      @dragover="handleDragOver"
      @dragleave="handleDragLeave"
      @drop="handleDrop"
    >
      <!-- Drag overlay -->
      <FilesDragOverlay :visible="isDragOver" />

      <!-- Sidebar -->
      <Sidebar
        v-model="sidebarVisible"
        :active-provider-id="activeProviderId"
        :active-service-id="activeServiceId"
        :services="availableServices"
        @navigate-home="fileManager.navigateToRoot()"
        @select-service="handleServiceSelect"
        @new-folder="showNewFolderDialog = true"
        @open-file-picker="openFilePicker"
        @open-folder-picker="openFolderPicker"
      />

      <!-- Main Area -->
      <div class="files-main">
        <div class="files-workspace">
          <div class="files-browser-panel">
            <!-- Breadcrumbs -->
            <FilesBreadcrumbs
              :items="breadcrumbs"
              @navigate="handleBreadcrumbNavigate"
            />

            <!-- Loading -->
            <v-progress-linear
              v-if="fileManager.isLoading.value"
              indeterminate
              color="primary"
              class="mx-4"
            />

            <div class="files-view-panel">
              <!-- Empty state -->
              <FilesEmptyState v-if="!hasItems && !fileManager.isLoading.value" />

              <!-- Grid View -->
              <FilesGridView
                v-else-if="viewMode === 'grid'"
                :collections="sortedItems.collections"
                :entities="sortedItems.entities"
                :selected-ids="selectedIds"
                :preview-source="resolveViewerSource"
                @item-click="handleItemClick"
                @open="handleOpenItem"
                @edit="handleEditItem"
                @rename="handleRenameItem"
                @delete="handleDeleteItem"
                @download="handleDownloadItem"
                @show-details="handleShowDetails"
              />

              <!-- List View -->
              <FilesListView
                v-else-if="viewMode === 'list'"
                :collections="sortedItems.collections"
                :entities="sortedItems.entities"
                :selected-ids="selectedIds"
                :preview-source="resolveViewerSource"
                @item-click="handleItemClick"
                @open="handleOpenItem"
                @edit="handleEditItem"
                @rename="handleRenameItem"
                @delete="handleDeleteItem"
                @download="handleDownloadItem"
                @show-details="handleShowDetails"
              />

              <!-- Details View -->
              <FilesDetailsView
                v-else-if="viewMode === 'details'"
                :collections="sortedItems.collections"
                :entities="sortedItems.entities"
                :selected-ids="selectedIds"
                :preview-source="resolveViewerSource"
                @item-click="handleItemClick"
                @open="handleOpenItem"
                @edit="handleEditItem"
                @rename="handleRenameItem"
                @delete="handleDeleteItem"
                @download="handleDownloadItem"
                @show-details="handleShowDetails"
              />
            </div>
          </div>

          <FilesInfoPanel
            v-if="hasSelection && !isMobile"
            embedded
            :selected-items="selection.selectedNodeArray.value"
            @close="selection.clear()"
          />
        </div>
      </div>

      <FilesInfoPanel
        v-if="isMobile"
        :selected-items="selection.selectedNodeArray.value"
        @close="selection.clear()"
      />
    </div>

    <!-- Hidden file inputs -->
    <input
      ref="fileInputRef"
      type="file"
      multiple
      style="display: none;"
      @change="handleFileSelect"
    />
    <input
      ref="folderInputRef"
      type="file"
      webkitdirectory
      style="display: none;"
      @change="handleFolderSelect"
    />

    <!-- Dialogs -->
    <NewFolderDialog
      v-model="showNewFolderDialog"
      @create="handleCreateFolder"
    />

    <RenameDialog
      v-model="showRenameDialog"
      :current-name="renameCurrentName(nodeToRename)"
      @rename="handleRename"
    />

    <DeleteConfirmDialog
      v-model="showDeleteDialog"
      :item-count="nodesToDelete.length"
      @confirm="handleDelete"
    />

    <UploadDialog
      v-model="showUploadDialog"
      :uploads="upload.uploads.value"
      :total-progress="upload.totalProgress.value"
      :is-uploading="upload.isUploading.value"
      :is-preparing="isPreparingUploads"
      :preparing-message="uploadPreparationMessage"
      :preparing-processed-count="uploadPreparationProcessedCount"
      :preparing-total-count="uploadPreparationTotalCount"
      :pending-count="upload.pendingUploads.value.length"
      :completed-count="upload.completedUploads.value.length"
      @upload-all="handleUploadAll"
      @remove-upload="upload.removeUpload"
      @retry-upload="upload.retryUpload"
      @add-files="openFilePicker"
      @close="handleUploadDialogClose"
    />

    <!-- File Viewer (provided by the media_viewer module) -->
    <component
      :is="mediaViewerDialog"
      v-if="mediaViewerDialog"
      v-model="showViewer"
      :items="viewerItems"
      :index="viewerIndex"
      :source="resolveViewerSource"
      :download="downloadViewerItem"
      :navigation="true"
      @update:index="viewerIndex = $event"
    />

    <!-- File Editor -->
    <FileEditorDialog
      v-model="showEditor"
      :entity="editorEntity"
      :read-file="fileManager.readFile"
      :write-file="fileManager.writeFile"
    />

    <v-snackbar
      v-model="snackbarVisible"
      :color="snackbarColor"
      :timeout="3000"
      location="bottom right"
    >
      {{ snackbarMessage }}
      <template #actions>
        <v-btn variant="text" @click="snackbarVisible = false">Close</v-btn>
      </template>
    </v-snackbar>
  </div>
</template>

<style scoped>
.files-unavailable {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  min-height: 0;
  padding: 48px;
  text-align: center;
  width: 100%;
}

.files-unavailable-alert {
  width: 100%;
  text-align: left;
}

.files-container {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
  isolation: isolate;
}

.files-content {
  display: flex;
  flex: 1;
  min-height: 0;
  overflow: hidden;
  position: relative;
}

.files-main {
  flex: 1;
  min-height: 0;
  display: flex;
  overflow: hidden;
  min-width: 0;
}

.files-workspace {
  flex: 1;
  min-height: 0;
  display: flex;
  overflow: hidden;
  min-width: 0;
}

.files-browser-panel {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-width: 0;
}

.files-view-panel {
  flex: 1;
  min-height: 0;
  overflow: auto;
}

@media (max-width: 960px) {
  .files-workspace {
    flex-direction: column;
  }
}
</style>
