<script>
  import { createEventDispatcher } from 'svelte'
  import FileBreadcrumbs from '../../FileBreadcrumbs.svelte'
  import FileTreeRow from '../../../FileTreeRow.svelte'
  import FilePreviewModal from '../../FilePreviewModal.svelte'
  import ConfirmModal from '../../ConfirmModal.svelte'
  import { canPreviewFile, needsBase64Preview, isTextFile, isMarkdownFile } from '../../fileUtils.js'
  import { t } from '../../i18n'
  import MarkdownEditor from '../notes/MarkdownEditor.svelte'
  import MarkdownPreview from '../notes/MarkdownPreview.svelte'

  // ===== Props =====
  export let selectedNode = null
  export let wailsCall = async () => {}

  // ===== Debug helper =====
  function _fdl(msg) {
    try { wailsCall('WriteDebugLog', '[FilesTab] ' + msg) } catch(e) {}
  }

  // ===== Events =====
  const dispatch = createEventDispatcher()

  // ===== Internal state (owned by FilesTab) =====
  let loadingFiles = false
  let currentFolderId = null
  let folderStack = []
  let fileItems = []
  // Preview modal state (images, PDF, binary)
  let previewItem = null
  let previewContent = ''
  let previewLoading = false
  let previewError = ''
  // Text file editor state (text, markdown, code)
  let textEditorFile = null
  let textEditorContent = ''
  let textEditorLoading = false
  let textEditorError = ''
  let textEditorIsMarkdown = false
  let textEditorMode = 'view' // 'view' | 'edit' | 'split'
  let textEditorDirty = false
  let clipboard = { items: [], mode: 'copy' }
  let selectedIds = []
  let dragIds = []
  let importing = false
  let importSummary = null
  let showImportDialog = false
  let pendingImportPath = ''
  let pendingImportParent = ''
  let showRename = false
  let renameId = ''
  let renameValue = ''
  let renameError = ''
  let showConfirm = false
  let confirmTitle = ''
  let confirmMessage = ''
  let confirmDanger = false
  let confirmText = t('common.delete')
  let confirmAction = null
  let cancelAction = null

  // ===== Public API (called via bind:this) =====
  export function resetToNode(nodeId) {
    folderStack = []
    currentFolderId = null
    selectedIds = []
    dragIds = []
    previewItem = null
    previewContent = ''
    closeTextEditor()
    loadFolder(nodeId)
  }

  // ===== React to selectedNode changes =====
  let lastLoadedNodeId = null
  $: if (selectedNode && selectedNode.id && selectedNode.id !== lastLoadedNodeId) {
    _fdl('selectedNode changed: id=' + selectedNode.id + ' title=' + selectedNode.title + ' type=' + selectedNode.type)
    lastLoadedNodeId = selectedNode.id
    resetToNode(selectedNode.id)
  }

  export function addFile() {
    _addFile()
  }

  export function loadFolder(folderId) {
    _loadFolder(folderId)
  }

  export function openFileById(fileNodeId) {
    // Find the file in the current fileItems and open preview
    const fileItem = fileItems.find(f => f.id === fileNodeId)
    if (fileItem) {
      _openFile(fileItem)
    }
  }

  export function focusItem(nodeId) {
    selectedIds = [nodeId]
  }

  // ===== Folder navigation =====
  async function _loadFolder(folderId) {
    loadingFiles = true
    try {
      let items = await wailsCall('ListItems', folderId) || []
      _fdl('loadFolder nodeId=' + folderId + ' count=' + items.length + ' first=' + (items[0] ? JSON.stringify({id: items[0].id, name: items[0].name, type: items[0].type, fileId: items[0].fileId}) : 'none'))
      items.sort((a, b) => {
        if (a.type !== b.type) return a.type === 'folder' ? -1 : 1
        return (a.name || '').localeCompare(b.name || '')
      })
      fileItems = items
    } catch (e) {
      _fdl('loadFolder ERROR nodeId=' + folderId + ' err=' + String(e))
      fileItems = []
    }
    loadingFiles = false
  }

  async function navigateToFolder(folderId) {
    if (!selectedNode) return
    try {
      const node = await wailsCall('GetNodeDetail', folderId)
      if (node) {
        folderStack = [...folderStack, { id: folderId, name: node.title }]
      }
    } catch (e) {
      folderStack = [...folderStack, { id: folderId, name: '...' }]
    }
    currentFolderId = folderId
    await _loadFolder(folderId)
  }

  function navigateBack() {
    if (folderStack.length < 2) {
      folderStack = []
      currentFolderId = null
      if (selectedNode) _loadFolder(selectedNode.id)
    } else {
      const target = folderStack[folderStack.length - 2]
      folderStack = folderStack.slice(0, -1)
      currentFolderId = target.id
      _loadFolder(target.id)
    }
  }

  function navigateToBreadcrumb(index) {
    const target = folderStack[index]
    folderStack = folderStack.slice(0, index + 1)
    currentFolderId = target.id
    _loadFolder(target.id)
  }

  // ===== Open file: text editor or preview modal =====
  async function _openFile(item) {
    _fdl('openFile item=' + JSON.stringify({id: item.id, name: item.name, type: item.type, fileId: item.fileId}))

    // 1. Markdown: check if linked to a note
    if (item && item.fileId && isMarkdownFile(item)) {
      try {
        const action = await wailsCall('CheckFileAction', item.fileId)
        _fdl('CheckFileAction result=' + JSON.stringify(action))
        if (action && action.action === 'note') {
          // Linked note → open note editor
          dispatch('openNote', { id: action.noteId, title: action.noteTitle })
          return
        }
        // action === 'preview' → fall through to text editor below
      } catch (e) {
        _fdl('CheckFileAction ERROR: ' + String(e))
      }
    }

    // 2. Text/markdown files → TextFileEditor
    if (item && item.fileId && (isTextFile(item) || isMarkdownFile(item))) {
      _fdl('opening text editor for ' + item.name)
      openTextEditor(item, isMarkdownFile(item))
      return
    }

    // 3. Images / PDF / binary preview → FilePreviewModal
    if (item && item.fileId && canPreviewFile(item)) {
      _fdl('opening preview modal for ' + item.name)
      openPreviewModal(item)
      return
    }

    // 4. Fallback: unknown type, try as text
    if (item && item.fileId && item.type !== 'folder') {
      _fdl('fallback: trying text editor for unknown type ' + item.name)
      openTextEditor(item, false)
      return
    }

    _fdl('no suitable opener for ' + item.name)
  }

  async function openTextEditor(item, isMarkdown) {
    textEditorFile = item
    textEditorContent = ''
    textEditorError = ''
    textEditorLoading = true
    textEditorIsMarkdown = isMarkdown
    try {
      textEditorContent = await wailsCall('ReadFileText', item.fileId) || ''
    } catch (e) {
      textEditorError = String(e)
    }
    textEditorLoading = false
  }

  function closeTextEditor() {
    textEditorFile = null
    textEditorContent = ''
    textEditorError = ''
    textEditorIsMarkdown = false
    textEditorMode = 'view'
    textEditorDirty = false
  }

  function saveTextEditor() {
    if (!textEditorFile || !textEditorDirty) return
    wailsCall('SaveFileText', textEditorFile.fileId, textEditorContent)
    textEditorDirty = false
  }

  async function openPreviewModal(item) {
    previewItem = item
    previewContent = ''
    previewError = ''
    previewLoading = true
    try {
      if (needsBase64Preview(item)) {
        previewContent = await wailsCall('GetFileBase64', item.fileId) || ''
      }
    } catch (e) {
      previewError = String(e)
    }
    previewLoading = false
  }

  function closePreview() {
    previewItem = null
    previewContent = ''
    previewError = ''
  }

  // ===== File operations =====
  async function _addFile() {
    const path = await wailsCall('PickFile')
    if (!path) return
    const parentId = currentFolderId || selectedNode.id
    await _startImport(parentId, path)
  }

  async function _addFolder() {
    const path = await wailsCall('PickDirectory')
    if (!path) return
    const parentId = currentFolderId || selectedNode.id
    await _startImport(parentId, path)
  }

  async function createFile() {
    const name = prompt(t('file.namePrompt'))
    if (!name || !name.trim()) return
    try {
      const parentId = currentFolderId || selectedNode.id
      await wailsCall('CreateEmptyFile', parentId, name.trim())
      await _loadFolder(parentId)
      dispatch('refreshParent', { nodeId: parentId })
    } catch (e) {
      dispatch('error', { message: String(e) })
    }
  }

  async function duplicateItem(id) {
    try {
      await wailsCall('DuplicateNode', id)
      const parentId = currentFolderId || selectedNode.id
      await _loadFolder(parentId)
      dispatch('refreshParent', { nodeId: parentId })
    } catch (e) {
      dispatch('error', { message: String(e) })
    }
  }

  function renameItem(id) {
    const item = fileItems.find(x => x.id === id)
    if (item) _openRename(item.id, item.name)
  }

  function cutItem(id) {
    clipboard = { items: [id], mode: 'cut' }
  }

  function copyItem(id) {
    clipboard = { items: [id], mode: 'copy' }
  }

  async function pasteItem() {
    if (clipboard.items.length === 0) return
    const targetId = currentFolderId || selectedNode.id
    try {
      if (clipboard.mode === 'copy') {
        for (const id of clipboard.items) {
          await wailsCall('DuplicateNode', id)
        }
      } else {
        for (const id of clipboard.items) {
          await wailsCall('MoveNode', id, targetId)
        }
      }
      clipboard = { items: [], mode: 'copy' }
      await _loadFolder(targetId)
    } catch (e) {
      dispatch('error', { message: String(e) })
    }
  }

  // ===== Selection =====
  function toggleSelection(id) {
    if (selectedIds.includes(id)) {
      selectedIds = selectedIds.filter(x => x !== id)
    } else {
      selectedIds = [...selectedIds, id]
    }
  }

  function selectOne(id) {
    selectedIds = [id]
  }

  function selectAll() {
    selectedIds = fileItems.map(x => x.id)
  }

  function rangeSelect(id) {
    if (fileItems.length === 0) return
    const lastId = selectedIds.length > 0 ? selectedIds[selectedIds.length - 1] : fileItems[0].id
    const lastIdx = fileItems.findIndex(x => x.id === lastId)
    const curIdx = fileItems.findIndex(x => x.id === id)
    if (lastIdx === -1 || curIdx === -1) return
    const start = Math.min(lastIdx, curIdx)
    const end = Math.max(lastIdx, curIdx)
    const range = fileItems.slice(start, end + 1).map(x => x.id)
    const set = new Set(selectedIds)
    range.forEach(x => set.add(x))
    selectedIds = [...set]
  }

  function clearSelection() {
    selectedIds = []
  }

  function getTargetIds(ids) {
    return ids.length > 0 ? ids : fileItems.map(x => x.id)
  }

  async function deleteSelected() {
    const ids = getTargetIds(selectedIds)
    const item = fileItems.find(x => x.id === ids[0])
    let label
    if (ids.length === 1 && item?.type === 'folder') {
      label = t('delete.folder')
    } else if (ids.length === 1) {
      label = t('delete.file')
    } else {
      label = t('delete.files', { count: ids.length })
    }
    _openConfirm({
      title: t('delete.confirmTitle'),
      message: t('delete.confirmMessage') + ' ' + label + '?',
      confirmText: t('common.delete'),
      danger: true,
      onConfirm: async () => {
        for (const id of ids) {
          try {
            await wailsCall('DeleteFileOrFolder', id)
          } catch (e) {
            dispatch('error', { message: String(e) })
          }
        }
        selectedIds = []
        const reloadId = currentFolderId || selectedNode.id
        await _loadFolder(reloadId)
      }
    })
  }

  function cutSelected() {
    const ids = getTargetIds(selectedIds)
    clipboard = { items: ids, mode: 'cut' }
    selectedIds = []
  }

  function copySelected() {
    const ids = getTargetIds(selectedIds)
    clipboard = { items: ids, mode: 'copy' }
    selectedIds = []
  }

  // ===== Drag-and-drop =====
  function onDragStart(e, id) {
    e.stopPropagation()
    const ids = selectedIds.includes(id) ? selectedIds : [id]
    dragIds = ids
    e.dataTransfer.effectAllowed = 'move'
    e.dataTransfer.setData('text/plain', ids.join(','))
  }

  function onDragOver(e, folderId) {
    const item = fileItems.find(x => x.id === folderId)
    if (item && item.type === 'folder') {
      e.preventDefault()
      e.stopPropagation()
      e.dataTransfer.dropEffect = 'move'
    }
  }

  async function onDrop(e, folderId) {
    e.preventDefault()
    e.stopPropagation()
    if (dragIds.length === 0) return
    for (const id of dragIds) {
      try {
        await wailsCall('MoveNode', id, folderId)
      } catch (e) {
        dispatch('error', { message: String(e) })
      }
    }
    dragIds = []
    selectedIds = []
    await _loadFolder(currentFolderId || selectedNode.id)
  }

  // ===== Keyboard =====
  function openSelected() {
    if (selectedIds.length === 1) {
      const item = fileItems.find(x => x.id === selectedIds[0])
      if (item) {
        if (item.type === 'folder') {
          navigateToFolder(item.id)
        } else {
          _openFile(item)
        }
      }
    }
  }

  function openSelectedExternal() {
    if (selectedIds.length === 1) {
      const item = fileItems.find(x => x.id === selectedIds[0])
      if (item && item.fileId) {
        wailsCall('OpenFile', item.fileId)
      }
    }
  }

  function openRenameForSelection() {
    if (selectedIds.length === 1) {
      const item = fileItems.find(x => x.id === selectedIds[0])
      if (item) {
        _openRename(item.id, item.name)
      }
    }
  }

  // ===== Rename modal =====
  function _openRename(id, currentName) {
    renameId = id
    renameValue = currentName
    renameError = ''
    showRename = true
  }

  async function submitRename() {
    const name = renameValue.trim()
    if (!name) { renameError = t('rename.emptyError'); return }
    try {
      await wailsCall('ValidateName', name)
    } catch (e) {
      renameError = t('rename.invalidError')
      return
    }
    showRename = false
    const id = renameId
    renameId = ''
    try {
      await wailsCall('RenameNode', id, name)
      if (selectedNode && selectedNode.id === id) {
        selectedNode = { ...selectedNode, title: name }
      }
      dispatch('refreshParent', { nodeId: currentFolderId || selectedNode.id })
      if (currentFolderId) {
        await _loadFolder(currentFolderId)
      }
    } catch (e) {
      dispatch('error', { message: String(e) })
    }
  }

  function cancelRename() {
    showRename = false
    renameId = ''
    renameValue = ''
    renameError = ''
  }

  function onRenameKeydown(e) {
    if (e.key === 'Enter') submitRename()
    else renameError = ''
  }

  // ===== Confirm modal =====
  function _openConfirm(opts) {
    confirmTitle = opts.title || t('common.confirm')
    confirmMessage = opts.message || ''
    confirmDanger = opts.danger !== undefined ? opts.danger : true
    confirmText = opts.confirmText || t('common.delete')
    confirmAction = opts.onConfirm || null
    cancelAction = opts.onCancel || null
    showConfirm = true
  }

  function closeConfirm() {
    showConfirm = false
    confirmAction = null
    cancelAction = null
  }

  function handleConfirm() {
    if (confirmAction) confirmAction()
    closeConfirm()
  }

  function handleCancel() {
    if (cancelAction) cancelAction()
    closeConfirm()
  }

  // ===== Import =====
  async function _startImport(parentID, sourcePath) {
    importing = true
    try {
      const summary = await wailsCall('PreviewImport', sourcePath)
      importSummary = summary
      pendingImportPath = sourcePath
      pendingImportParent = parentID
      showImportDialog = true
    } catch (e) {
      dispatch('error', { message: String(e) })
    }
    importing = false
  }

  async function confirmImport(mode) {
    try {
      const parentId = pendingImportParent || selectedNode.id
      if (mode === 'copy') {
        await wailsCall('AddPathCopy', parentId, pendingImportPath)
      } else {
        await wailsCall('AddPathLink', parentId, pendingImportPath)
      }
      showImportDialog = false
      importSummary = null
      folderStack = []
      currentFolderId = null
      await _loadFolder(parentId)
      dispatch('refreshParent', { nodeId: parentId })
    } catch (e) {
      dispatch('error', { message: String(e) })
    }
  }

  function cancelImport() {
    showImportDialog = false
    importSummary = null
  }

  async function deleteFile({ id, type }) {
    const label = type === 'folder' ? t('delete.folder') : t('delete.file')
    _openConfirm({
      title: t('delete.confirmTitle'),
      message: t('delete.confirmMessage') + ' ' + label + '?',
      confirmText: t('common.delete'),
      danger: true,
      onConfirm: async () => {
        try {
          await wailsCall('DeleteFileOrFolder', id)
          const reloadId = currentFolderId || selectedNode.id
          await _loadFolder(reloadId)
        } catch (e) {
          dispatch('error', { message: String(e) })
        }
      }
    })
  }

  async function openSelectedFile(fileID) {
    try {
      await wailsCall('OpenFile', fileID)
    } catch (e) {
      dispatch('error', { message: String(e) })
    }
  }

  // ===== Keyboard handler (called from parent) =====
  export function handleFilesKeydown(e) {
    if (e.ctrlKey || e.metaKey) {
      if (e.key === 'c' || e.key === 'C') { e.preventDefault(); copySelected() }
      else if (e.key === 'x' || e.key === 'X') { e.preventDefault(); cutSelected() }
      else if (e.key === 'v' || e.key === 'V') { e.preventDefault(); pasteItem() }
      else if (e.key === 'a' || e.key === 'A') { e.preventDefault(); selectAll() }
      else if (e.key === 'o' || e.key === 'O') { e.preventDefault(); openSelectedExternal() }
      else if (e.key === 'Enter') { e.preventDefault(); openSelected() }
    } else if (e.key === 'Enter') {
      e.preventDefault()
      openSelected()
    } else if (e.key === 'Delete') {
      if (textEditorFile) { e.preventDefault(); closeTextEditor(); return }
      if (previewItem) { e.preventDefault(); closePreview(); return }
      if (selectedIds.length > 0) { e.preventDefault(); deleteSelected(); return }
    } else if (e.key === 'Escape') {
      if (textEditorFile) { closeTextEditor(); return }
      if (previewItem) { closePreview(); return }
      if (selectedIds.length > 0) { clearSelection(); return }
    } else if (e.key === 'F2') {
      e.preventDefault()
      openRenameForSelection()
    }
  }

  // ===== Reset on node change =====
  export function resetState() {
    folderStack = []
    currentFolderId = null
    fileItems = []
    selectedIds = []
    dragIds = []
    previewItem = null
    previewContent = ''
    previewError = ''
    clipboard = { items: [], mode: 'copy' }
    importing = false
    importSummary = null
    showImportDialog = false
    showRename = false
    showConfirm = false
  }
</script>

<!-- Files tab template -->
<div class="files-tab">
  {#if textEditorFile}
    <!-- ===== Editor mode ===== -->
    <div class="file-editor-mode">
      <div class="fe-toolbar">
        <button class="btn btn-sm back-btn" on:click={closeTextEditor}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>
          {t('file.backToFiles')}
        </button>
        <span class="fe-filename" title={textEditorFile.name}>{textEditorFile.name}</span>
        {#if textEditorIsMarkdown}
          <span class="fe-badge">markdown</span>
        {/if}
        <div class="fe-spacer"></div>
        {#if textEditorIsMarkdown}
          <div class="fe-mode-switcher" role="tablist" aria-label="View mode">
            <button type="button" class="fe-mode-btn" class:active={textEditorMode === 'view'} on:click={() => textEditorMode = 'view'}>{t('note.mode.preview')}</button>
            <button type="button" class="fe-mode-btn" class:active={textEditorMode === 'edit'} on:click={() => textEditorMode = 'edit'}>{t('note.mode.edit')}</button>
            <button type="button" class="fe-mode-btn" class:active={textEditorMode === 'split'} on:click={() => textEditorMode = 'split'}>{t('note.mode.split')}</button>
          </div>
        {/if}
        <button class="btn btn-sm" on:click={() => wailsCall('OpenFile', textEditorFile.fileId)}>{t('file.openExternal')}</button>
      </div>
      <div class="fe-body">
        {#if textEditorLoading}
          <div class="fe-status"><p>{t('common.loading')}</p></div>
        {:else if textEditorError}
          <div class="fe-status fe-error">
            <p>{textEditorError}</p>
            <button class="btn btn-sm" on:click={() => wailsCall('OpenFile', textEditorFile.fileId)}>{t('file.openExternal')}</button>
          </div>
        {:else if textEditorIsMarkdown && textEditorMode === 'view'}
          <div class="fe-markdown-preview">
            <svelte:component this={MarkdownPreview} content={textEditorContent} />
          </div>
        {:else if textEditorIsMarkdown && textEditorMode === 'edit'}
          <svelte:component this={MarkdownEditor} content={textEditorContent} viewMode="edit" on:content-change={(e) => { textEditorContent = e.detail.content; textEditorDirty = true }} on:save={() => saveTextEditor()} />
        {:else if textEditorIsMarkdown && textEditorMode === 'split'}
          <div class="fe-split">
            <div class="fe-split-pane fe-split-editor">
              <svelte:component this={MarkdownEditor} content={textEditorContent} viewMode="split" on:content-change={(e) => { textEditorContent = e.detail.content; textEditorDirty = true }} on:save={() => saveTextEditor()} />
            </div>
            <div class="fe-split-pane fe-split-preview">
              <svelte:component this={MarkdownPreview} content={textEditorContent} />
            </div>
          </div>
        {:else}
          <pre class="fe-plain-text"><code>{textEditorContent}</code></pre>
        {/if}
      </div>
      {#if textEditorDirty}
        <div class="fe-footer">
          <button class="btn btn-primary btn-sm" on:click={saveTextEditor}>{t('common.save')}</button>
        </div>
      {/if}
    </div>
  {:else}
    <!-- ===== Browser mode ===== -->
    <div class="tab-toolbar">
      <button class="btn btn-primary" on:click={_addFile} disabled={importing}>{t('file.addFile')}</button>
      <button class="btn" on:click={_addFolder} disabled={importing}>{t('file.addFolder')}</button>
      <button class="btn" on:click={createFile}>{t('file.newFile')}</button>
      {#if clipboard.items.length > 0}
        <button class="btn" on:click={pasteItem}>{t('common.paste')} {clipboard.items.length}</button>
      {/if}
    </div>

    {#if loadingFiles}
      <div class="empty-state">
        <p>{t('common.loading')}</p>
      </div>
    {:else}
      {#if folderStack.length > 0}
        <FileBreadcrumbs crumbs={[{ name: t('file.root') }, ...folderStack]} on:navigate={(e) => {
          const i = e.detail
          if (i === 0) {
            folderStack = []
            currentFolderId = null
            if (selectedNode) _loadFolder(selectedNode.id)
          } else {
            navigateToBreadcrumb(i - 1)
          }
        }}/>
        <button class="btn btn-sm back-btn" on:click={navigateBack}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>
          {t('common.backLabel')}
        </button>
      {:else}
        <FileBreadcrumbs crumbs={[{ name: t('file.root') }]}/>
      {/if}

      {#if fileItems.length === 0}
        <div class="empty-state">
          <div class="empty-icon">
            <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">
              <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
              <polyline points="14 2 14 8 20 8"/>
            </svg>
          </div>
          <p>{folderStack.length > 0 ? t('file.noFiles') : t('file.noFilesCase')}</p>
          <p class="hint">{t('file.hint')}</p>
          <div class="empty-actions">
            <button class="btn btn-primary" on:click={_addFile}>{t('file.addFileSimple')}</button>
            <button class="btn" on:click={_addFolder}>{t('file.addFolderSimple')}</button>
          </div>
        </div>
      {:else}
        <div class="file-list">
          {#each fileItems as item (item.id)}
            <FileTreeRow
              {item}
              selected={selectedIds.includes(item.id)}
              {onDragStart}
              {onDragOver}
              {onDrop}
              on:navigate={(e) => navigateToFolder(e.detail)}
              on:preview={(e) => _openFile(e.detail)}
              on:openExternal={(e) => wailsCall('OpenFile', e.detail)}
              on:showInFolder={(e) => wailsCall('OpenFolder', e.detail)}
              on:delete={(e) => deleteFile(e.detail)}
              on:rename={(e) => renameItem(e.detail.id)}
              on:duplicate={(e) => duplicateItem(e.detail)}
              on:cut={(e) => cutItem(e.detail)}
              on:copy={(e) => copyItem(e.detail)}
              on:selectOne={(e) => selectOne(e.detail)}
              on:toggleSelect={(e) => toggleSelection(e.detail)}
              on:rangeSelect={(e) => rangeSelect(e.detail)}
            />
          {/each}
        </div>
      {/if}
    {/if}

    {#if importing && !showImportDialog}
      <div class="empty-state"><p>{t('file.scanning')}</p></div>
    {/if}
  {/if}
</div>

<!-- Rename modal -->
{#if showRename}
  <div class="modal-overlay" role="button" tabindex="0" on:click|self={cancelRename} on:keydown={(e) => e.key === 'Escape' && cancelRename()}>
    <div class="modal">
      <h3>{t('rename.title')}</h3>
      <div class="form-group">
        <label><span class="label-text">{t('common.newName')}</span>
        <input type="text" bind:value={renameValue}
               on:keydown={onRenameKeydown} />
        </label>
      </div>
      {#if renameError}
        <div class="rename-error">{renameError}</div>
      {/if}
      <div class="modal-actions">
        <button class="btn btn-primary" on:click={submitRename}>{t('common.rename')}</button>
        <button class="btn" on:click={cancelRename}>{t('common.cancel')}</button>
      </div>
    </div>
  </div>
{/if}

<!-- Confirm modal -->
{#if showConfirm}
  <ConfirmModal
    title={confirmTitle}
    message={confirmMessage}
    confirmText={confirmText}
    danger={confirmDanger}
    on:confirm={handleConfirm}
    on:cancel={handleCancel}
  />
{/if}

<!-- Import dialog -->
{#if showImportDialog && importSummary}
  <div class="modal-overlay" role="button" tabindex="0" on:click|self={cancelImport} on:keydown={(e) => e.key === 'Escape' && cancelImport()}>
    <div class="modal">
      <h3>{t('file.importTitle')} «{selectedNode ? selectedNode.title : ''}»</h3>
      <div class="import-summary">
        <div class="summary-row"><span>{t('file.importFiles')}</span><span>{importSummary.files}</span></div>
        <div class="summary-row"><span>{t('file.importFolders')}</span><span>{importSummary.folders}</span></div>
        <div class="summary-row"><span>{t('file.importSize')}</span><span>{(importSummary.totalBytes / 1024).toFixed(1)} KB</span></div>
        {#if importSummary.isDangerous}
          <div class="summary-warn">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
            {importSummary.dangerReason}
          </div>
        {/if}
      </div>
      <div class="modal-actions">
        <button class="btn btn-primary" on:click={() => confirmImport('copy')}>{t('file.importCopy')}</button>
        <button class="btn" on:click={() => confirmImport('link')}>{t('file.importLink')}</button>
        <button class="btn" on:click={cancelImport}>{t('common.cancel')}</button>
      </div>
    </div>
  </div>
{/if}

<!-- File preview modal (images, PDF, binary only) -->
{#if previewItem}
  <FilePreviewModal
    item={previewItem}
    content={previewContent}
    loading={previewLoading}
    error={previewError}
    on:close={closePreview}
    on:openExternal={(e) => wailsCall('OpenFile', e.detail)}
  />
{/if}

<style>
  .files-tab { padding: 20px; }
  .files-tab .tab-toolbar { display: flex; gap: 8px; align-items: center; margin-bottom: 16px; }
  .file-list { display: flex; flex-direction: column; }
  .back-btn { margin-bottom: 4px; display: inline-flex; align-items: center; gap: 4px; }

  .import-summary { margin-bottom: 16px; }
  .summary-row { display: flex; justify-content: space-between; padding: 6px 0; font-size: 14px; border-bottom: 1px solid #2a2a3c; }
  .summary-warn { margin-top: 8px; padding: 8px 12px; background: #3a2a22; border-radius: 6px; color: #ffaa66; font-size: 13px; }

  .rename-error { color: #ff6b6b; font-size: 12px; margin-top: 4px; }

  /* Button styles (mirroring global App.svelte .btn) */
  .btn { padding: 8px 16px; border: 1px solid #2a2a3c; background: #1a1a28; color: #ccc; border-radius: 6px; cursor: pointer; font-size: 13px; font-family: inherit; display: inline-flex; align-items: center; gap: 6px; }
  .btn:hover { background: #222233; }
  .btn-primary { background: #6366f1; border-color: #6366f1; color: #fff; }
  .btn-primary:hover { background: #4f46e5; }
  .btn:disabled { opacity: 0.4; cursor: not-allowed; }
  .btn-sm { padding: 4px 10px; font-size: 12px; }
  .btn-danger { color: #ff6b6b; border-color: #4a2222; }
  .btn-danger:hover { background: #3a2222; }

  /* ===== File editor mode ===== */
  .file-editor-mode {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
  }

  .fe-toolbar {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    border-bottom: 1px solid #2a2a3c;
    background: #16161f;
    flex-shrink: 0;
  }

  .fe-filename {
    font-size: 13px;
    font-weight: 500;
    color: #e4e4ef;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 300px;
  }

  .fe-badge {
    font-size: 10px;
    padding: 1px 6px;
    border-radius: 4px;
    background: #2a2a3c;
    color: #888;
    flex-shrink: 0;
  }

  .fe-spacer {
    flex: 1;
  }

  .fe-mode-switcher {
    display: flex;
    gap: 2px;
  }

  .fe-mode-btn {
    padding: 3px 10px;
    border: 1px solid transparent;
    border-radius: 4px;
    background: transparent;
    color: #888;
    font-size: 11px;
    font-family: inherit;
    cursor: pointer;
  }

  .fe-mode-btn:hover {
    color: #ccc;
    background: #1e1e30;
  }

  .fe-mode-btn.active {
    color: #e4e4ef;
    background: #22223a;
    border-color: #333350;
  }

  .fe-body {
    flex: 1;
    min-height: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
  }

  .fe-status {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 48px 24px;
    color: #888;
    font-size: 13px;
  }

  .fe-error {
    color: #ff8888;
  }

  .fe-markdown-preview {
    flex: 1;
    overflow-y: auto;
    padding: 16px 20px;
  }

  .fe-split {
    flex: 1;
    display: flex;
    min-height: 0;
    overflow: hidden;
  }

  .fe-split-pane {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
    overflow: hidden;
  }

  .fe-split-editor {
    border-right: 1px solid #2a2a3c;
  }

  .fe-split-preview {
    background: #11111c;
    overflow-y: auto;
    padding: 16px 20px;
  }

  .fe-plain-text {
    flex: 1;
    margin: 0;
    padding: 16px 20px;
    overflow: auto;
    font-family: 'SF Mono', 'Fira Code', 'Cascadia Code', 'Consolas', monospace;
    font-size: 13px;
    line-height: 1.6;
    color: #ccc;
    white-space: pre-wrap;
    word-break: break-word;
    background: #13131f;
  }

  .fe-plain-text code {
    font-family: inherit;
    background: none;
    padding: 0;
  }

  .fe-footer {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    padding: 8px 12px;
    border-top: 1px solid #2a2a3c;
    flex-shrink: 0;
  }
</style>
