import React, { useCallback, useEffect, useMemo, useState } from "react";
import Filter from "../components/Filter";
import { Axiosinstance } from "../services/auth/Axiosinstance";
import { useToast } from "../components/ToastProvider";

import { IoGrid, IoList } from "react-icons/io5";

import { TYPE_EXTENSION_MAP, flattenFolderTree, getFileExtension, getFileId, joinUrl } from "../utils/storage";

import { useStorageColors } from "../hooks/useStorageColors";
import { useStorageDashboardItems } from "../hooks/useStorageDashboardItems";

import SearchCategoryBar from "../components/storage/SearchCategoryBar";
import RenameModal from "../components/storage/RenameModal";
import MoveModal from "../components/storage/MoveModal";
import FilesList from "../components/storage/FilesList";
import FilesGrid from "../components/storage/FilesGrid";
import ColorPickerModal from "../components/storage/ColorPickerModal";

import ShareModal from "../components/storage/ShareModal";
import DetailsModal from "../components/storage/DetailsModal";
import ZipModal from "../components/storage/ZipModal";

import { FileMenu } from "../components/storage/ItemMenus";
import PaginationControls from "../components/storage/PaginationControls";

/* ---------------- session helpers ---------------- */
const SESSION_PAGE_SIZE_KEY = "storage.pageSize";
const readSessionInt = (key, fallback) => {
  try {
    const raw = sessionStorage.getItem(key);
    const n = Number.parseInt(raw, 10);
    return Number.isFinite(n) ? n : fallback;
  } catch {
    return fallback;
  }
};
const clampInt = (v, min, max) => {
  const n = Number.parseInt(String(v || ""), 10);
  if (!Number.isFinite(n)) return min;
  return Math.max(min, Math.min(max, n));
};

// پیام خطا از DRF/Backend
const getErrMsg = (err, fallback = "خطا. لطفاً دوباره تلاش کنید.") => {
  const d = err?.response?.data;
  if (!d) return err?.message || fallback;
  if (typeof d === "string") return d;
  if (d.detail) return d.detail;
  if (d.message) return d.message;
  try {
    return JSON.stringify(d);
  } catch {
    return fallback;
  }
};

export default function MyFile() {
  const toastApi = useToast();

  // ✅ wrapper برای سازگاری ToastProvider‌های مختلف
  const toast = useMemo(() => {
    if (toastApi?.success && toastApi?.error) return toastApi;
    if (toastApi?.show) {
      return {
        success: (m) => toastApi.show({ type: "success", message: m }),
        error: (m) => toastApi.show({ type: "error", message: m }),
        info: (m) => toastApi.show({ type: "info", message: m }),
      };
    }
    if (toastApi?.addToast) {
      return {
        success: (m) => toastApi.addToast("success", m),
        error: (m) => toastApi.addToast("error", m),
        info: (m) => toastApi.addToast("info", m),
      };
    }
    return { success: () => {}, error: () => {}, info: () => {} };
  }, [toastApi]);

  const baseURL = Axiosinstance.defaults.baseURL;

  // ✅ دیتا مثل داشبورد
  const { foldersTreeRaw, files, loading, loadError, ownerEmails, requestRefresh } = useStorageDashboardItems({ Axiosinstance, toast });

  // ✅ رنگ‌ها
  const { colorsCfg, colorOptions, colorsLoading } = useStorageColors({
    Axiosinstance,
    toast,
  });

  // filters ui states
  const [filterChanges, setFilterChanges] = useState(null);
  const [filterSpace, setFilterSpace] = useState(null);
  const [filterOwner, setFilterOwner] = useState(null);

  const [viewMode, setViewMode] = useState("grid");
  const [searchTerm, setSearchTerm] = useState("");
  const [selectedType, setSelectedType] = useState(null);

  // portal menu state
  const [fileMenu, setFileMenu] = useState({ id: null, rect: null });
  const closeFileMenu = () => setFileMenu({ id: null, rect: null });

  const toggleFileMenu = (id, e) => {
    e.preventDefault();
    e.stopPropagation();
    const rect = e.currentTarget.getBoundingClientRect();
    setFileMenu((prev) => (String(prev.id) === String(id) ? { id: null, rect: null } : { id, rect }));
  };

  // modals
  const [detailsModal, setDetailsModal] = useState({ open: false, type: null, item: null });
  const [renameModal, setRenameModal] = useState({ open: false, type: null, item: null, value: "" });

  const [shareModal, setShareModal] = useState({
    open: false,
    file: null,
    data: null,
    downloadLink: "",
    copying: false,
    revoking: false,
    creating: false,
  });

  const [colorModal, setColorModal] = useState({ open: false, type: null, item: null });

  // ✅ Move modal
  const [moveModal, setMoveModal] = useState({
    open: false,
    item: null,
    target: "root",
    createName: "",
    creating: false,
    moving: false,
  });

  // ✅ Zip modal
  const [zipModal, setZipModal] = useState({
    open: false,
    items: [],
    name: "",
    folder_id: "root",
    picking: false,
    pickValue: "",
    zipping: false,
  });

  const allFoldersFlat = useMemo(() => flattenFolderTree(foldersTreeRaw), [foldersTreeRaw]);

  const openDetails = (type, item) => {
    closeFileMenu();
    setDetailsModal({ open: true, type, item });
  };

  const openRename = (file) => {
    closeFileMenu();
    setRenameModal({ open: true, type: "file", item: file, value: file?.name || "" });
  };

  const openMove = (file) => {
    closeFileMenu();
    setMoveModal({ open: true, item: file, target: "root", createName: "", creating: false, moving: false });
  };

  // clipboard (برای ShareModal)
  const copyToClipboard = async (text) => {
    try {
      if (navigator?.clipboard?.writeText) {
        await navigator.clipboard.writeText(text);
        return true;
      }
    } catch {}
    try {
      const ta = document.createElement("textarea");
      ta.value = text;
      ta.style.position = "fixed";
      ta.style.left = "-9999px";
      document.body.appendChild(ta);
      ta.focus();
      ta.select();
      const ok = document.execCommand("copy");
      document.body.removeChild(ta);
      return ok;
    } catch {
      return false;
    }
  };

  /* -------------------- filtering (همون منطق داشبورد) -------------------- */
  const filteredFiles = useMemo(() => {
    return (files || []).filter((file) => {
      const name = file.name || "";
      const lowerName = name.toLowerCase();
      const search = searchTerm.toLowerCase();

      if (search && !lowerName.includes(search)) return false;

      if (selectedType && selectedType !== "پوشه‌ها") {
        const allowedExts = TYPE_EXTENSION_MAP[selectedType];
        if (allowedExts && allowedExts.length > 0) {
          const ext = getFileExtension(name);
          if (!allowedExts.includes(ext)) return false;
        }
      }

      if (filterChanges && file.updated_at) {
        const updated = new Date(file.updated_at);
        const now = new Date();
        let fromDate = null;

        switch (filterChanges) {
          case "today":
            fromDate = new Date(now.getFullYear(), now.getMonth(), now.getDate());
            break;
          case "7days":
            fromDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
            break;
          case "30days":
            fromDate = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
            break;
          case "thisYear":
            fromDate = new Date(now.getFullYear(), 0, 1);
            break;
          case "lastYear":
            fromDate = new Date(now.getFullYear() - 1, 0, 1);
            break;
          default:
            break;
        }

        if (fromDate && updated < fromDate) return false;
      }

      if (filterSpace) {
        if (filterSpace === "starred" && !file.is_starred) return false;
        if (filterSpace === "trash" && !file.in_trash) return false;
      }

      if (filterOwner && file.owner_email && file.owner_email !== filterOwner) return false;

      return true;
    });
  }, [files, searchTerm, selectedType, filterChanges, filterSpace, filterOwner]);

  /* -------------------- ✅ Pagination -------------------- */
  const [pageSize, setPageSize] = useState(() => clampInt(readSessionInt(SESSION_PAGE_SIZE_KEY, 8), 1, 200));
  const [filesPage, setFilesPage] = useState(1);

  useEffect(() => {
    setFilesPage(1);
  }, [searchTerm, selectedType, filterChanges, filterSpace, filterOwner, viewMode, pageSize]);

  const paginate = (arr, page, size) => {
    const total = Array.isArray(arr) ? arr.length : 0;
    const totalPages = Math.max(1, Math.ceil(total / size));
    const p = clampInt(page, 1, totalPages);
    const start = (p - 1) * size;
    const end = start + size;
    return { total, totalPages, page: p, items: (arr || []).slice(start, end) };
  };

  const pagedFiles = useMemo(() => paginate(filteredFiles, filesPage, pageSize), [filteredFiles, filesPage, pageSize]);

  /* -------------------- actions -------------------- */
  const handleRenameFile = async (file, name) => {
    try {
      const id = getFileId(file);
      await Axiosinstance.patch(`storage/files/${id}/rename/`, { name });
      toast.success("نام فایل تغییر کرد ✅");
      requestRefresh({ silent: true });
    } catch (err) {
      toast.error(getErrMsg(err, "تغییر نام فایل ناموفق بود."));
    }
  };

  const handleDownloadFile = async (file) => {
    try {
      const id = getFileId(file);
      const response = await Axiosinstance.get(`storage/files/${id}/download/`, { responseType: "blob" });
      const blobUrl = window.URL.createObjectURL(new Blob([response.data]));
      const link = document.createElement("a");
      link.href = blobUrl;
      link.download = file.name || "file";
      document.body.appendChild(link);
      link.click();
      link.remove();
      window.URL.revokeObjectURL(blobUrl);
      toast.success("دانلود شروع شد ✅");
    } catch (err) {
      toast.error(getErrMsg(err, "دانلود فایل ناموفق بود."));
    }
  };

  const handleTrashFile = async (file) => {
    try {
      const id = getFileId(file);
      await Axiosinstance.post(`storage/files/${id}/trash/`);
      toast.success("به سطل زباله منتقل شد ✅");
      requestRefresh({ silent: true });
    } catch (err) {
      toast.error(getErrMsg(err, "انتقال به سطل زباله ناموفق بود."));
    }
  };

  const handleRestoreFile = async (file) => {
    try {
      const id = getFileId(file);
      await Axiosinstance.post(`storage/files/${id}/restore/`);
      toast.success("فایل بازیابی شد ✅");
      requestRefresh({ silent: true });
    } catch (err) {
      toast.error(getErrMsg(err, "بازگردانی فایل ناموفق بود."));
    }
  };

  const handleHardDeleteFile = async (file) => {
    if (!window.confirm("حذف دائمی این فایل قابل بازگشت نیست. آیا مطمئن هستید؟")) return;
    try {
      const id = getFileId(file);
      await Axiosinstance.delete(`storage/files/${id}/hard-delete/`);
      toast.success("حذف دائمی انجام شد ✅");
      requestRefresh({ silent: true });
    } catch (err) {
      toast.error(getErrMsg(err, "حذف دائمی فایل ناموفق بود."));
    }
  };

  const handleStarFile = async (file) => {
    try {
      const id = getFileId(file);
      const res = await Axiosinstance.post(`storage/files/${id}/star/`);
      const is_starred = typeof res.data?.is_starred === "boolean" ? res.data.is_starred : !file.is_starred;
      toast.success(is_starred ? "به ستاره‌دارها اضافه شد ⭐" : "از ستاره‌دارها حذف شد ✅");
      requestRefresh({ silent: true });
    } catch (err) {
      toast.error(getErrMsg(err, "عملیات ستاره‌دار کردن ناموفق بود."));
    }
  };

  // Share (مودال)
  const handleShareFile = async (file) => {
    closeFileMenu();
    setShareModal({
      open: true,
      file,
      data: null,
      downloadLink: "",
      copying: false,
      revoking: false,
      creating: false,
    });
  };

  const handleCreateShare = async ({ permission, duration, file }) => {
    if (!file) return toast.error("فایل انتخاب نشده.");
    try {
      setShareModal((p) => ({ ...p, creating: true }));

      const id = getFileId(file);
      const res = await Axiosinstance.post(`storage/files/${id}/share/`, {
        permission,
        duration,
      });

      const downloadLink = res.data?.download_url || res.data?.share_url || "";

      setShareModal((p) => ({
        ...p,
        data: res.data,
        downloadLink,
        creating: false,
      }));

      toast.success("لینک اشتراک ساخته شد ✅");
    } catch (err) {
      toast.error(getErrMsg(err, "ساخت لینک اشتراک ناموفق بود."));
      setShareModal((p) => ({ ...p, creating: false }));
    }
  };

  const handleRevokeShare = async () => {
    const token = shareModal?.data?.token;
    const file = shareModal?.file;
    if (!token || !file) return toast.error("توکن اشتراک پیدا نشد.");

    try {
      setShareModal((p) => ({ ...p, revoking: true }));
      const id = getFileId(file);
      await Axiosinstance.post(`storage/files/${id}/share/revoke/`, { token });

      toast.success("اشتراک‌گذاری لغو شد ✅");
      setShareModal({
        open: false,
        file: null,
        data: null,
        downloadLink: "",
        copying: false,
        revoking: false,
        creating: false,
      });
    } catch (err) {
      toast.error(getErrMsg(err, "لغو اشتراک ناموفق بود."));
      setShareModal((p) => ({ ...p, revoking: false }));
    }
  };

  const handleSetFileColor = async (file, color_id) => {
    const id = getFileId(file);
    if (!id) return toast.error("شناسه فایل پیدا نشد.");
    try {
      await Axiosinstance.patch(`storage/files/${id}/color/`, { color_id: color_id ?? null });
      toast.success("رنگ فایل تغییر کرد ✅");
    } catch (err) {
      toast.error(getErrMsg(err, "تغییر رنگ فایل ناموفق بود."));
    }
  };

  /* -------------------- ✅ Zip / Unzip -------------------- */
  const openZipModalWith = (seed) => {
    closeFileMenu();
    setZipModal((p) => {
      const exists = (p.items || []).some((it) => it.type === seed.type && String(it.id) === String(seed.id));
      const items = exists ? p.items : [seed];
      const suggestedName = seed?.type === "file" ? `${String(seed?.name || "archive").replaceAll("/", "-")}.zip` : `${String(seed?.name || "archive").replaceAll("/", "-")}.zip`;
      return {
        open: true,
        items,
        name: p.open ? p.name : suggestedName,
        folder_id: p.folder_id || "root",
        picking: false,
        pickValue: "",
        zipping: false,
      };
    });
  };

  const handleCreateArchive = async () => {
    const name = String(zipModal.name || "").trim();
    if (!name) return toast.error("نام فایل زیپ را وارد کنید.");

    const items = Array.isArray(zipModal.items) ? zipModal.items : [];
    const file_ids = items
      .filter((x) => x.type === "file")
      .map((x) => x.id)
      .filter(Boolean);
    const folder_ids = items
      .filter((x) => x.type === "folder")
      .map((x) => x.id)
      .filter(Boolean);

    if (file_ids.length === 0 && folder_ids.length === 0) return toast.error("حداقل یک فایل یا پوشه انتخاب کنید.");

    const folder_id = zipModal.folder_id && zipModal.folder_id !== "root" ? zipModal.folder_id : null;

    try {
      setZipModal((p) => ({ ...p, zipping: true }));
      toast.info("در حال ساخت آرشیو...");

      await Axiosinstance.post("storage/archive/create/", {
        name,
        folder_id,
        file_ids,
        folder_ids,
      });

      toast.success("زیپ ساخته شد ✅");
      setZipModal({ open: false, items: [], name: "", folder_id: "root", picking: false, pickValue: "", zipping: false });
      requestRefresh({ silent: true });
    } catch (err) {
      toast.error(getErrMsg(err, "زیپ کردن ناموفق بود."));
      setZipModal((p) => ({ ...p, zipping: false }));
    }
  };

  const handleExtractZip = async (file, opts = {}) => {
    const id = getFileId(file);
    if (!id) return toast.error("شناسه فایل پیدا نشد.");

    const payload = {
      zip_file_id: id,
      target_folder_id: opts?.target_folder_id ?? null,
      create_subfolder: opts?.create_subfolder ?? true,
      overwrite: opts?.overwrite ?? false,
    };

    try {
      toast.info("در حال Extract ...");
      await Axiosinstance.post("storage/archive/extract/", payload);
      toast.success("انزیپ انجام شد ✅");
      requestRefresh({ silent: true });
    } catch (err) {
      toast.error(getErrMsg(err, "انزیپ ناموفق بود."));
    }
  };

  /* -------------------- ✅ Move with duplicate-name check -------------------- */
  const fetchFilesInFolder = async (folderIdOrNull) => {
    const params = {};
    if (folderIdOrNull) params.folder = folderIdOrNull;
    const res = await Axiosinstance.get("storage/items/", { params });
    const list = Array.isArray(res?.data?.files) ? res.data.files : [];
    return list;
  };

  const handleMoveFile = async (file, destination_folder_id) => {
    const fileName = String(file?.name || "").trim();
    if (!fileName) return toast.error("نام فایل نامعتبر است.");

    try {
      // ✅ چک همنام داخل مقصد
      const destFiles = await fetchFilesInFolder(destination_folder_id || null);
      const exists = destFiles.some(
        (f) =>
          String(f?.name || "")
            .trim()
            .toLowerCase() === fileName.toLowerCase()
      );

      if (exists) {
        toast.error("داخل پوشه مقصد فایل همنام وجود دارد. ابتدا نام یکی را تغییر دهید.");
        return;
      }

      const id = getFileId(file);
      await Axiosinstance.post(`storage/files/${id}/move/`, { destination_folder_id });

      toast.success("فایل منتقل شد ✅");
      requestRefresh({ silent: true });
    } catch (err) {
      toast.error(getErrMsg(err, "انتقال فایل ناموفق بود."));
    }
  };

  const handleCreateFolder = async (name, parent) => {
    try {
      const payload = parent === "root" ? { name } : { name, parent };
      await Axiosinstance.post(`storage/folders/`, payload);
      toast.success("پوشه ساخته شد ✅");
      requestRefresh({ silent: true });
    } catch (err) {
      toast.error(getErrMsg(err, "ساخت پوشه ناموفق بود."));
    }
  };

  /* -------------------- render file menu -------------------- */
  const renderFileMenu = useCallback(
    (file) => (
      <FileMenu
        file={file}
        colorsCfg={colorsCfg}
        colorOptions={colorOptions}
        colorsLoading={colorsLoading}
        onDetails={(t, it) => {
          openDetails(t, it);
          closeFileMenu();
        }}
        onRename={(f) => openRename(f)}
        onZip={(seed) => {
          openZipModalWith(seed);
          closeFileMenu();
        }}
        onUnzip={async (f) => {
          await handleExtractZip(f);
          closeFileMenu();
        }}
        onShare={async (f) => {
          await handleShareFile(f);
          closeFileMenu();
        }}
        onDownload={async (f) => {
          await handleDownloadFile(f);
          closeFileMenu();
        }}
        onMove={(f) => openMove(f)}
        onOpenColorModal={(f) => {
          closeFileMenu();
          setColorModal({ open: true, type: "file", item: f });
        }}
        onToggleStar={async (f) => {
          await handleStarFile(f);
          closeFileMenu();
        }}
        onTrashOrRestore={async (f, mode) => {
          mode === "trash" ? await handleTrashFile(f) : await handleRestoreFile(f);
          closeFileMenu();
        }}
        onHardDelete={async (f) => {
          await handleHardDeleteFile(f);
          closeFileMenu();
        }}
      />
    ),
    [colorsCfg, colorOptions, colorsLoading] // ok
  );

  return (
    <div className="w-full min-w-0 dark:text-white text-black" onClick={() => closeFileMenu()}>
      {/* Zip */}
      <ZipModal state={zipModal} setState={setZipModal} files={(files || []).map((f) => ({ ...f, id: String(getFileId(f)) }))} allFoldersFlat={allFoldersFlat} onCreateArchive={handleCreateArchive} />

      {/* Details */}
      <DetailsModal state={detailsModal} onClose={() => setDetailsModal({ open: false, type: null, item: null })} />

      {/* Rename */}
      <RenameModal
        state={renameModal}
        setState={setRenameModal}
        onSave={async () => {
          const item = renameModal.item;
          const name = String(renameModal.value || "").trim();
          if (!item || !name) return toast.error("نام جدید را وارد کنید.");
          await handleRenameFile(item, name);
          setRenameModal({ open: false, type: null, item: null, value: "" });
        }}
      />

      {/* Move */}
      <MoveModal state={moveModal} setState={setMoveModal} foldersFlat={allFoldersFlat} onMove={handleMoveFile} onCreateFolder={handleCreateFolder} />

      {/* Share */}
      <ShareModal
        state={shareModal}
        onClose={() =>
          setShareModal({
            open: false,
            file: null,
            data: null,
            downloadLink: "",
            copying: false,
            revoking: false,
            creating: false,
          })
        }
        onCopy={async (link) => {
          const text = link || shareModal?.data?.download_url || shareModal?.data?.share_url || shareModal?.downloadLink || "";
          if (!text) return toast.error("لینکی برای کپی وجود ندارد.");

          setShareModal((p) => ({ ...p, copying: true }));
          const ok = await copyToClipboard(text);
          setShareModal((p) => ({ ...p, copying: false }));
          ok ? toast.success("لینک کپی شد ✅") : toast.error("کپی انجام نشد.");
        }}
        onRevoke={handleRevokeShare}
        onCreate={handleCreateShare}
      />

      {/* Color Picker */}
      <ColorPickerModal
        open={colorModal.open}
        onClose={() => setColorModal({ open: false, type: null, item: null })}
        title="تغییر رنگ"
        itemName={colorModal?.item?.name || ""}
        colorsCfg={colorsCfg}
        colorOptions={colorOptions}
        colorsLoading={colorsLoading}
        onPick={async (colorIdOrNull) => {
          const it = colorModal.item;
          if (!it) return;
          await handleSetFileColor(it, colorIdOrNull);
          requestRefresh({ silent: true });
          setColorModal({ open: false, type: null, item: null });
        }}
      />

      {/* ===== Top bar ===== */}
      <div className="mb-5 rounded-2xl border border-black/10 dark:border-white/10 bg-[#A1E3F910] shadow dark:bg-[#A1E3F910] p-3 sm:p-4">
        <div className="flex flex-col lg:flex-row gap-3 lg:items-center lg:justify-between min-w-0">
          <div className="min-w-0">
            <h1 className="text-lg sm:text-xl font-extrabold">فایل‌های من</h1>
            <p className="text-xs sm:text-sm text-black/60 dark:text-white/70 truncate">جستجو کن، فیلتر بزن، و فایل‌ها رو مدیریت کن</p>
          </div>

          <div className="flex items-center gap-2 w-full lg:w-auto">
            <button
              onClick={() => setViewMode("grid")}
              className={`flex-1 lg:flex-none border rounded-xl px-3 py-2 inline-flex items-center justify-center gap-2 transition
                ${
                  viewMode === "grid"
                    ? "dark:bg-[#A1E3F919] bg-[#A1E3F980] dark:text-[#43BEFF] shadow text-black border-[#A1E3F919]"
                    : "border-[#A1E3F919] hover:bg-black/5 dark:text-white text-[#43BEFF] dark:hover:bg-white/10"
                }`}
              title="نمای گرید"
            >
              <IoGrid className="h-5 w-5" />
              <span className="text-sm">گرید</span>
            </button>

            <button
              onClick={() => setViewMode("list")}
              className={`flex-1 lg:flex-none border rounded-xl px-3 py-2 inline-flex items-center justify-center gap-2 transition
                ${
                  viewMode === "list"
                    ? "dark:bg-[#A1E3F919] bg-[#A1E3F980] dark:text-[#43BEFF] shadow text-black border-[#A1E3F919]"
                    : "border-[#A1E3F919] hover:bg-black/5 dark:text-white text-[#43BEFF] dark:hover:bg-white/10"
                }`}
              title="نمای لیست"
            >
              <IoList className="h-5 w-5" />
              <span className="text-sm">لیست</span>
            </button>
          </div>
        </div>
      </div>

      {/* Filters */}
      <div className="flex justify-evenly">
        <Filter
          selectedType={selectedType}
          onTypeChange={(label) => setSelectedType(label)}
          selectedChanges={filterChanges}
          onChangesChange={(val) => setFilterChanges(val)}
          selectedSpace={filterSpace}
          onSpaceChange={(val) => setFilterSpace(val)}
          selectedOwnerEmail={filterOwner}
          onOwnerChange={(email) => setFilterOwner(email)}
          owners={ownerEmails}
        />
      </div>

      {/* Search + Categories */}
      <SearchCategoryBar searchTerm={searchTerm} onSearchTermChange={setSearchTerm} selectedType={selectedType} onSelectedTypeChange={setSelectedType} />

      {/* header */}
      <div className="flex items-center justify-between mb-3">
        <button className="dark:text-white text-black font-extrabold text-base sm:text-lg">فایل‌ها</button>
        <div className="text-xs flex items-center gap-2">
          {loading && <span className="dark:text-white/70">در حال دریافت...</span>}
          {loadError && <span className="text-red-400">{loadError}</span>}
        </div>
      </div>

      {!loading && pagedFiles.total === 0 && (
        <div className="p-4 rounded-2xl bg-white/60 dark:bg-[#16325b] border border-black/10 dark:border-white/10 text-sm text-black/60 dark:text-white/70">فایلی برای نمایش وجود ندارد.</div>
      )}

      {/* LIST */}
      {viewMode === "list" && <FilesList files={pagedFiles.items} fileMenu={fileMenu} onToggleFileMenu={toggleFileMenu} onCloseFileMenu={closeFileMenu} renderFileMenu={renderFileMenu} />}

      {/* GRID */}
      {viewMode === "grid" && (
        <FilesGrid
          files={pagedFiles.items}
          baseURL={baseURL}
          Axiosinstance={Axiosinstance}
          fileMenu={fileMenu}
          onToggleFileMenu={toggleFileMenu}
          onCloseFileMenu={closeFileMenu}
          renderFileMenu={renderFileMenu}
        />
      )}

      {/* ✅ Pagination controls */}
      <div className="mt-3">
        <PaginationControls
          total={pagedFiles.total}
          page={pagedFiles.page}
          onPageChange={setFilesPage}
          pageSize={pageSize}
          onPageSizeChange={setPageSize}
          sessionKey={SESSION_PAGE_SIZE_KEY}
          defaultPageSize={8}
          label="فایل‌ها"
        />
      </div>
    </div>
  );
}
