<!-- #region StorageIndexPage [C:3] [TYPE Page] [SEMANTICS sveltekit, storage, file, upload, management] -->
<!-- @ingroup Routes -->
<!-- @BRIEF Page component: routes/tools/storage/+page.svelte -->
<!-- @LAYER Page -->
<!--
@UX_STATE: Loading -> Default

@SEMANTICS: storage, file, upload, management
@PURPOSE:   Main page for unified file storage management.
@LAYER     UI
@RELATION  DEPENDS_ON -> [storageService]
@RELATION  CONTAINS -> [FileList]
@RELATION  CONTAINS -> [FileUpload]

@INVARIANT: Always displays a unified storage view without category tabs.
-->

<script lang="ts">
  // [SECTION: IMPORTS]
  import { onMount } from 'svelte';
  import { page } from '$app/state';
  import { listFiles, deleteFile } from '../../../services/storageService';
  import { addToast } from '$lib/toasts.svelte.js';
  import { t } from '$lib/i18n/index.svelte.js';
  import { ConfirmDialog } from "$lib/ui";
  import { log } from "$lib/cot-logger";
  import FileList from '$lib/components/storage/FileList.svelte';
  import FileUpload from '$lib/components/storage/FileUpload.svelte';
  // [/SECTION: IMPORTS]

  // #region loadFiles:Function [TYPE Function]
// @ingroup Routes
  /**
   * @purpose Fetches the list of files from the server.
   * @pre     currentPath is a valid storage path or empty for root.
   * @post    Updates the `files` array with the latest data.
   */
  let files = $state([]);
  let isLoading = $state(false);
  let currentPath = $state('');
  let showDeleteConfirm = $state(false);
  let deletePayload = $state(null);

  // #region resolveStorageQueryFromPath:Function [TYPE Function]
// @ingroup Routes
  /**
   * @purpose Splits UI path into storage API category and category-local subpath.
   * @pre     uiPath may be empty or start with backups/repositorys.
   * @post    Returns {category, subpath} compatible with /api/storage/files.
   */
  function resolveStorageQueryFromPath(uiPath: string): { category?: string; subpath?: string } {
    const segments = String(uiPath || '').split('/').filter(Boolean);
    if (segments.length === 0) return {};
    const topLevel = segments[0];
    if (topLevel !== 'backups' && topLevel !== 'repositorys') {
      return {};
    }
    const subpath = segments.slice(1).join('/');
    return {
      category: topLevel,
      subpath: subpath || undefined,
    };
  }
  // #endregion resolveStorageQueryFromPath:Function

  async function loadFiles() {
    log("StorageIndexPage", "REASON", "Loading files", { path: currentPath });
    isLoading = true;
    try {
      const query = resolveStorageQueryFromPath(currentPath);
      files = await listFiles(query.category, query.subpath);
      log("StorageIndexPage", "REFLECT", "Files loaded", { count: files.length });
    } catch (error) {
      log("StorageIndexPage", "EXPLORE", "Failed to load files", {}, String(error.message));
      addToast($t.storage.messages.load_failed.replace('{error}', error.message), 'error');
    } finally {
      isLoading = false;
    }
  }
  // #endregion loadFiles:Function

  // #region handleDelete:Function [TYPE Function]
// @ingroup Routes
  /**
   * @purpose Handles the file deletion process.
   * @pre     The event contains valid category and path.
   * @post    File is deleted and file list is refreshed.
   * @param   {CustomEvent} event - The delete event containing category and path.
   */
  async function handleDelete(payload) {
    const { category, path, name } = payload || {};
    if (!category || !path || !name) {
      log("StorageIndexPage", "EXPLORE", "Delete skipped — invalid payload", { payload });
      return;
    }
    deletePayload = payload;
    showDeleteConfirm = true;
  }

  // ── Bulk delete ─────────────────────────────────────────────────
  let bulkDeletePayloads = $state<Array<{category: string; path: string; name: string}>>([]);

  function handleBulkDelete(files: Array<{category: string; path: string; name: string}>) {
    bulkDeletePayloads = files;
    deletePayload = files[0]; // for confirm dialog message
    showDeleteConfirm = true;
  }

  async function onConfirmDelete() {
    const payloads = bulkDeletePayloads.length > 0 ? bulkDeletePayloads : (deletePayload ? [deletePayload] : []);
    deletePayload = null;
    bulkDeletePayloads = [];
    let errors = 0;
    for (const p of payloads) {
      try {
        await deleteFile(p.category, p.path);
      } catch (error) {
        errors++;
        log("StorageIndexPage", "EXPLORE", "Failed to delete file", {}, String(error.message));
      }
    }
    if (errors === 0) {
      addToast(payloads.length > 1
        ? $t.storage.messages.bulk_delete_success?.replace('{count}', String(payloads.length)) || `${payloads.length} files deleted`
        : $t.storage.messages.delete_success.replace('{name}', payloads[0].name), 'success');
    } else {
      addToast($t.storage.messages.delete_failed.replace('{error}', `${errors} failed`), 'error');
    }
    await loadFiles();
  }
  // #endregion handleDelete:Function

  // #region handleNavigate:Function [TYPE Function]
// @ingroup Routes
  /**
   * @purpose Updates the current path and reloads files when navigating into a directory.
   * @pre     The event contains a valid path string.
   * @post    currentPath is updated and files are reloaded.
   * @param   {CustomEvent} event - The navigation event containing the new path.
   */
  function handleNavigate(path) {
    if (!path || typeof path !== 'string') {
      log("StorageIndexPage", "EXPLORE", "Navigate skipped — invalid path", { path });
      return;
    }
    log("StorageIndexPage", "REASON", "Navigating to path", { path });
    currentPath = path;
    loadFiles();
  }
  // #endregion handleNavigate:Function

  // #region navigateUp:Function [TYPE Function]
// @ingroup Routes
  /**
   * @purpose Navigates one level up in the directory structure.
   * @pre     currentPath is not root.
   * @post    currentPath is moved up one directory level.
   */
  function navigateUp() {
    if (!currentPath) return;
    const parts = currentPath.split('/');
    parts.pop();
    currentPath = parts.join('/') || '';
    loadFiles();
  }
  // #endregion navigateUp:Function

  // #region updateUploadCategory:Function [TYPE Function]
// @ingroup Routes
  /**
   * @purpose Keeps upload category aligned with the currently viewed top-level folder.
   * @pre     currentPath can be empty or a slash-delimited path.
   * @post    uploadCategory is either backups or repositorys.
   */
  let uploadCategory = $derived(
    currentPath.split('/').filter(Boolean)[0] === 'repositorys'
      ? 'repositorys'
      : 'backups',
  );
  let uploadSubpath = $derived.by(() => {
    const [topLevel, ...rest] = currentPath.split('/').filter(Boolean);
    return topLevel === 'repositorys' || topLevel === 'backups'
      ? rest.join('/')
      : '';
  });
  // #endregion updateUploadCategory:Function

  onMount(() => {
    const pathParam = page.url.searchParams.get('path');
    if (pathParam) {
      currentPath = pathParam;
    }
    loadFiles();
  });
</script>

  <!-- [SECTION: TEMPLATE] -->
<div class="container mx-auto w-full p-4 min-[1280px]:max-w-[1400px] min-[1536px]:max-w-[1680px]">
  <div class="mb-6">
    <h1 class="text-2xl font-bold text-text">{$t.storage.management}</h1>
  </div>

  <div class="flex justify-end mb-4">
    <button
      onclick={loadFiles}
      class="inline-flex items-center px-4 py-2 border border-border-strong rounded-md shadow-sm text-sm font-medium text-text bg-surface-card hover:bg-surface-muted"
      disabled={isLoading}
    >
      {isLoading ? $t.storage.refreshing : $t.storage.refresh}
    </button>
  </div>

  <div class="grid grid-cols-1 xl:grid-cols-[minmax(0,1fr)_360px] 2xl:grid-cols-[minmax(0,1fr)_420px] gap-6">
    <!-- Main Content: File List -->
    <div class="space-y-4 min-w-0">
      <FileList
        {files}
        {currentPath}
        loading={isLoading}
        ondelete={handleDelete}
        onnavigate={handleNavigate}
        onnavigateup={navigateUp}
        onbulkdelete={handleBulkDelete}
      />
    </div>

    <!-- Sidebar: Upload -->
    <div class="lg:col-span-1">
      <FileUpload
        category={uploadCategory}
        path={uploadSubpath}
        onuploaded={loadFiles}
      />
    </div>
  </div>
</div>

<ConfirmDialog
  bind:show={showDeleteConfirm}
  title="Delete file?"
  message={bulkDeletePayloads.length > 1
    ? `Delete ${bulkDeletePayloads.length} files?`
    : (deletePayload ? $t.storage.messages.delete_confirm.replace('{name}', deletePayload.name) : "")}
  variant="destructive"
  confirmLabel="Delete"
  cancelLabel="Cancel"
  onConfirm={onConfirmDelete}
  onCancel={() => { deletePayload = null; bulkDeletePayloads = []; }}
/>
<!-- [/SECTION: TEMPLATE] -->


<!-- #endregion StorageIndexPage -->
