import { useEffect, useMemo, useState } from "react";
import { useSearchParams } from "react-router-dom";
import { useQuery } from "@tanstack/react-query";
import { ArrowUpDown, Archive, Loader2 } from "lucide-react";
import { apiClient, detailFromApiError } from "@/shared/api/client";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import SearchableSelect, { type SearchableOption } from "@/components/admin/SearchableSelect";
import { ViewSubmittedApplicationButton } from "@/components/admin/ViewSubmittedApplicationButton";
import { DEPARTMENT_OPTIONS, GROUP_OPTIONS, STATUS_OPTIONS, ALL_OPTION_VALUE } from "@/components/admin/SelectOptions";
import type { ApplicationItem, ApplicationStatus } from "@/data/mockApplications";
import { useVisibilityAwareRefetchInterval } from "@/hooks/useVisibilityAwareRefetchInterval";
import { POLL_INTERVALS } from "@/shared/config/polling";
import { normalizeApplicationItem } from "@/lib/applicationReviewApi";
import { getApplicationMeritCategoryHint } from "@/components/admin/review/applicationMeritCategoryHint";
import type { ResearchEvidenceKind, InitiativeClassification, ApplicationFormState } from "@/components/applicant/initiativeFormTypes";
import { EvidenceFilesTableCell } from "@/components/evidence/EvidenceFilesTableCell";
import { ApplicationBackupDownloadButton } from "@/components/admin/ApplicationBackupDownloadButton";
import { toast } from "sonner";
import { formatIsoToDdMmYyyy, formatIsoToDdMmYyyyHhMm } from "@/lib/vnDateFormat";

type SortOrder = "asc" | "desc";

interface ApplicationResponse {
  data: ApplicationItem[];
  pagination: { page: number; pageSize: number; totalItems: number; totalPages: number };
  statusCounts?: { approved: number; rejected: number };
}

interface ApplicationReportFile {
  fileName: string;
  publicUrl: string;
  sizeBytes: number;
  updatedAt: string;
}

interface FilterState {
  /** API: `inbox` = chờ xử lý (loại đã/hủy); `decided` = chỉ đã duyệt hoặc từ chối */
  lifecycle: string;
  name: string;
  subjectId: string;
  conferenceId: string;
  status: string;
  dateFrom: string;
  dateTo: string;
  authorName: string;
  reviewerName: string;
  supervisorId: string;
  reviewStatus: string;
  topicTypeId: string;
  boardId: string;
  sortBy: string;
  sortOrder: SortOrder;
  page: number;
  pageSize: number;
}

const DEFAULT_FILTERS: FilterState = {
  lifecycle: "",
  name: "",
  subjectId: "",
  conferenceId: "",
  status: "",
  dateFrom: "",
  dateTo: "",
  authorName: "",
  reviewerName: "",
  supervisorId: "",
  reviewStatus: "",
  topicTypeId: "",
  boardId: "",
  sortBy: "submittedDate",
  sortOrder: "desc",
  page: 1,
  pageSize: 20,
};

export type AdminApplicationsLifecycle = "inbox" | "decided";

export interface AdminApplicationsListProps {
  lifecycle?: AdminApplicationsLifecycle;
  /** Tiêu đề khối lọc (CardTitle) */
  filterCardTitle?: string;
  /** Tiêu đề phần kết quả / bảng */
  resultsSectionTitle?: string;
  /** Hiện nút Duyệt / Từ chối (chỉ hợp lý khi chờ duyệt) */
  showReviewActionButtons?: boolean;
  /** `returnTo` cho nút Xem hồ sơ */
  viewSubmittedReturnPath?: string;
  /** Cột tải ZIP sao lưu (trang Dự án / Projects) */
  showBackupDownloadColumn?: boolean;
}

/** Filter stores YYYY-MM-DD (API); UI shows dd/MM/yyyy */
function isoDateToDdMmYyyy(iso: string) {
  if (!iso || !/^\d{4}-\d{2}-\d{2}$/.test(iso)) return "";
  const [y, m, d] = iso.split("-");
  return `${d}/${m}/${y}`;
}

function parseDdMmYyyyToIso(s: string): string {
  const trimmed = s.trim();
  if (!trimmed) return "";
  const match = trimmed.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
  if (!match) return "";
  const dd = Number(match[1]);
  const mm = Number(match[2]);
  const yyyy = Number(match[3]);
  if (mm < 1 || mm > 12 || dd < 1 || dd > 31) return "";
  const dt = new Date(yyyy, mm - 1, dd);
  if (dt.getFullYear() !== yyyy || dt.getMonth() !== mm - 1 || dt.getDate() !== dd) return "";
  return `${yyyy}-${String(mm).padStart(2, "0")}-${String(dd).padStart(2, "0")}`;
}

function formatDate(iso: string | null | undefined, withTime = false) {
  if (!iso) return "";
  if (withTime) return formatIsoToDdMmYyyyHhMm(iso);
  return formatIsoToDdMmYyyy(iso);
}

function optionLabel(options: ReadonlyArray<{ value: string; label: string }>, value?: string | null) {
  if (value == null || value === "") return "";
  return options.find((o) => o.value === value)?.label ?? "";
}

/** Đã duyệt: nhãn theo gợi ý nhóm Đơn (2.1.4 → Trung bình). */
function approvedMeritBadgeLabel(item: ApplicationItem): "Xuất sắc" | "Khá" | "Trung bình" {
  const hint = getApplicationMeritCategoryHint({
    initiativeClassification: (item.initiativeClassification ?? null) as InitiativeClassification,
    researchEvidenceKind: (item.researchEvidenceKind ?? "") as ResearchEvidenceKind,
    textbookEvidenceKind: (item.textbookEvidenceKind ?? "") as ApplicationFormState["textbookEvidenceKind"],
  });
  if (hint.meritLevel === "xuất sắc") return "Xuất sắc";
  if (hint.meritLevel === "trung bình") return "Trung bình";
  if (hint.meritLevel === "khá") return "Khá";
  if (hint.subgroupCode === "2.1.1" || hint.subgroupCode === "2.1.2" || hint.subgroupCode === "2.2.1") return "Xuất sắc";
  return "Khá";
}

function statusBadge(status: ApplicationStatus, item?: ApplicationItem) {
  const label = optionLabel(STATUS_OPTIONS, status) || String(status);
  switch (status) {
    case "pending":
      return <Badge className="bg-amber-500 hover:bg-amber-500/90">{label}</Badge>;
    case "approved":
      return (
        <Badge className="bg-green-600 hover:bg-green-600/90">
          {item ? approvedMeritBadgeLabel(item) : label}
        </Badge>
      );
    case "rejected":
      return <Badge variant="destructive">{label}</Badge>;
    case "transferred":
      return <Badge className="bg-blue-600 hover:bg-blue-600/90">{label}</Badge>;
    case "under_review":
      return <Badge variant="secondary">{label}</Badge>;
    case "reviewed":
      return <Badge variant="outline" className="border-green-500 text-green-700">{label}</Badge>;
    default:
      return <Badge variant="secondary">-</Badge>;
  }
}

function toSearchParams(filters: FilterState) {
  const params = new URLSearchParams();
  Object.entries(filters).forEach(([key, value]) => {
    const normalized = String(value ?? "");
    const defaultValue = String((DEFAULT_FILTERS as any)[key] ?? "");
    if (normalized && normalized !== defaultValue) {
      params.set(key, normalized);
    }
  });
  return params;
}

function toOptionList(input: unknown): SearchableOption[] {
  if (!Array.isArray(input)) return [];
  return input
    .map((item: any) => {
      const value = String(item?.id ?? item?.value ?? "");
      const label = String(item?.name ?? item?.fullName ?? item?.label ?? "");
      if (!value || !label) return null;
      return { value, label };
    })
    .filter(Boolean) as SearchableOption[];
}

function getNestedData<T = unknown>(raw: any): T {
  if (Array.isArray(raw)) return raw as T;
  if (raw?.data) return raw.data as T;
  return raw as T;
}

function useLookupQuery(path: string) {
  return useQuery({
    queryKey: ["dashboard-lookup", path],
    queryFn: async () => {
      const data = await apiClient.get(path);
      return toOptionList(getNestedData(data));
    },
    staleTime: 5 * 60 * 1000,
  });
}

export default function ApprovedApplicationsList({
  lifecycle,
  filterCardTitle,
  resultsSectionTitle,
  showReviewActionButtons = true,
  viewSubmittedReturnPath = "/dashboard",
  showBackupDownloadColumn = false,
}: AdminApplicationsListProps = {}) {
  const [, setSearchParams] = useSearchParams();
  const lc = lifecycle ?? "";
  const [filters, setFilters] = useState<FilterState>(() => ({ ...DEFAULT_FILTERS, lifecycle: lc }));
  const [nameInput, setNameInput] = useState(filters.name);
  const [authorInput, setAuthorInput] = useState(filters.authorName);
  const [reviewerInput, setReviewerInput] = useState(filters.reviewerName);
  const [dateFromText, setDateFromText] = useState(() => isoDateToDdMmYyyy(filters.dateFrom));
  const [statusOverrides, setStatusOverrides] = useState<Record<string, ApplicationStatus>>({});
  const [isExportingExcel, setIsExportingExcel] = useState(false);
  const [isExportingBackups, setIsExportingBackups] = useState(false);

  useEffect(() => {
    const handle = setTimeout(() => {
      setFilters((prev) => ({ ...prev, name: nameInput, page: 1 }));
    }, 300);
    return () => clearTimeout(handle);
  }, [nameInput]);

  useEffect(() => {
    const handle = setTimeout(() => {
      setFilters((prev) => ({ ...prev, authorName: authorInput, page: 1 }));
    }, 300);
    return () => clearTimeout(handle);
  }, [authorInput]);

  useEffect(() => {
    const handle = setTimeout(() => {
      setFilters((prev) => ({ ...prev, reviewerName: reviewerInput, page: 1 }));
    }, 300);
    return () => clearTimeout(handle);
  }, [reviewerInput]);

  useEffect(() => {
    setDateFromText(isoDateToDdMmYyyy(filters.dateFrom));
  }, [filters.dateFrom]);

  useEffect(() => {
    setSearchParams(toSearchParams(filters), { replace: true });
  }, [filters, setSearchParams]);

  const conferencesQuery = useLookupQuery("/api/conferences");
  const supervisorsQuery = useLookupQuery("/api/supervisors");
  const applicationsRefetchInterval = useVisibilityAwareRefetchInterval(
    POLL_INTERVALS.adminApplicationsList,
  );

  const reportFilesQuery = useQuery({
    queryKey: ["application-report-files"],
    queryFn: async () => {
      try {
        return await apiClient.get<{ files: ApplicationReportFile[] }>("/api/v1/application-reports");
      } catch {
        const response = await fetch("/application-report-index.json", { cache: "no-store" });
        if (!response.ok) return { files: [] };
        const files = (await response.json()) as ApplicationReportFile[];
        return { files: Array.isArray(files) ? files : [] };
      }
    },
    staleTime: 30 * 1000,
  });

  const applicationsQuery = useQuery({
    queryKey: ["applications", filters],
    queryFn: async (): Promise<ApplicationResponse> => {
      const res = await apiClient.get<ApplicationResponse>("/api/applications", { params: filters });
      return {
        ...res,
        data: (res.data ?? []).map((row) =>
          normalizeApplicationItem(
            row as ApplicationItem & {
              draft_case_id?: string;
              du_va_dung?: string | null;
              nhan_xet?: string | null;
              initiative_classification?: ApplicationItem["initiativeClassification"];
              research_evidence_kind?: ApplicationItem["researchEvidenceKind"];
            },
          ),
        ),
      };
    },
    placeholderData: (previous) => previous,
    staleTime: 30_000,
    refetchInterval: applicationsRefetchInterval,
    refetchOnWindowFocus: true,
    refetchOnReconnect: true,
  });

  const data = applicationsQuery.data?.data ?? [];
  const pagination = applicationsQuery.data?.pagination ?? { page: 1, pageSize: filters.pageSize, totalItems: 0, totalPages: 1 };
  const statusCounts = applicationsQuery.data?.statusCounts;
  const showStatusBreakdown =
    statusCounts != null &&
    (lifecycle === "decided" || statusCounts.approved + statusCounts.rejected > 0);

  const setFilter = (key: keyof FilterState, value: string | number) => {
    setFilters((prev) => ({ ...prev, [key]: value, page: key === "page" || key === "pageSize" ? Number(value) : 1 }));
  };

  const handleReset = () => {
    setNameInput("");
    setAuthorInput("");
    setReviewerInput("");
    setDateFromText("");
    setFilters({ ...DEFAULT_FILTERS, lifecycle: lc });
  };

  const statusFilterOptions = useMemo(() => {
    if (lifecycle === "inbox") {
      return STATUS_OPTIONS.filter((o) => o.value !== "approved" && o.value !== "rejected");
    }
    if (lifecycle === "decided") {
      return STATUS_OPTIONS.filter((o) => o.value === "approved" || o.value === "rejected");
    }
    return STATUS_OPTIONS;
  }, [lifecycle]);

  const filterCardTitleResolved =
    filterCardTitle ??
    (lifecycle === "inbox"
      ? "Hồ sơ chờ duyệt"
      : lifecycle === "decided"
        ? "Kết quả đã duyệt / từ chối"
        : "Quản trị duyệt hồ sơ sáng kiến");

  const resultsSectionTitleResolved =
    resultsSectionTitle ??
    (lifecycle === "inbox"
      ? "Danh sách chờ duyệt"
      : lifecycle === "decided"
        ? "Danh sách đã có kết luận"
        : "Kết quả tìm");

  const toggleSort = (sortBy: string) => {
    setFilters((prev) => ({
      ...prev,
      sortBy,
      sortOrder: prev.sortBy === sortBy && prev.sortOrder === "desc" ? "asc" : "desc",
      page: 1,
    }));
  };

  const exportExcel = async () => {
    setIsExportingExcel(true);
    try {
      const blobData = await apiClient.get<Blob>("/api/applications/export", {
        params: filters,
        responseType: "blob",
      } as any);
      const blob = new Blob([blobData], {
        type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
      });
      const url = URL.createObjectURL(blob);
      const link = document.createElement("a");
      link.href = url;
      link.download = "applications-export.xlsx";
      link.click();
      URL.revokeObjectURL(url);
    } finally {
      setIsExportingExcel(false);
    }
  };

  const exportAllBackupsZip = async () => {
    if (isExportingBackups || isExportingExcel) return;
    setIsExportingBackups(true);
    try {
      const blobData = await apiClient.get<Blob>("/api/applications/export-backups", {
        params: filters,
        responseType: "blob",
        timeout: 480_000,
      } as any);
      const blob = new Blob([blobData], { type: "application/zip" });
      const url = URL.createObjectURL(blob);
      const link = document.createElement("a");
      link.href = url;
      link.download = `sang-kien-sao-luu-tong-hop-${new Date().toISOString().slice(0, 10)}.zip`;
      link.click();
      URL.revokeObjectURL(url);
      toast.success("Đã tải ZIP tổng hợp (mỗi hồ sơ một file ZIP bên trong).");
    } catch (e) {
      toast.error(detailFromApiError(e, "Không xuất được ZIP tổng hợp."));
    } finally {
      setIsExportingBackups(false);
    }
  };

  const getStatus = (item: ApplicationItem): ApplicationStatus => statusOverrides[item.id] ?? item.status;

  const handleReviewAction = (applicationId: string, nextStatus: ApplicationStatus) => {
    setStatusOverrides((prev) => ({ ...prev, [applicationId]: nextStatus }));
  };

  const tableColSpan = 10 + (showBackupDownloadColumn ? 1 : 0);

  return (
    <div className="mt-4 space-y-4">
      <Card>
        <CardHeader>
          <CardTitle>{filterCardTitleResolved}</CardTitle>
        </CardHeader>
        <CardContent className="space-y-4">
          <div className="grid grid-cols-1 gap-4 md:grid-cols-3 lg:grid-cols-3">
            <div className="space-y-2">
              <Label htmlFor="name">Tên sáng kiến</Label>
              <Input id="name" value={nameInput} onChange={(e) => setNameInput(e.target.value)} placeholder="Nhập tên sáng kiến" />
            </div>
            <div className="space-y-2">
              <Label>Đơn vị</Label>
              <Select
                value={filters.subjectId || ALL_OPTION_VALUE}
                onValueChange={(v) => setFilter("subjectId", v === ALL_OPTION_VALUE ? "" : v)}
              >
                <SelectTrigger><SelectValue placeholder="Chọn" /></SelectTrigger>
                <SelectContent>
                  <SelectItem value={ALL_OPTION_VALUE}>Tất cả</SelectItem>
                  {DEPARTMENT_OPTIONS.map((option) => (
                    <SelectItem key={option.value} value={option.value}>
                      {option.label}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
            <div className="space-y-2">
              <Label>Năm</Label>
              <Select value={filters.conferenceId || ALL_OPTION_VALUE} onValueChange={(v) => setFilter("conferenceId", v === ALL_OPTION_VALUE ? "" : v)}>
                <SelectTrigger><SelectValue placeholder="Chọn" /></SelectTrigger>
                <SelectContent>
                  <SelectItem value={ALL_OPTION_VALUE}>Tất cả</SelectItem>
                  {(conferencesQuery.data ?? []).map((option) => <SelectItem key={option.value} value={option.value}>{option.label}</SelectItem>)}
                </SelectContent>
              </Select>
            </div>
            <div className="space-y-2">
              <Label>Trạng thái</Label>
              <Select value={filters.status || ALL_OPTION_VALUE} onValueChange={(v) => setFilter("status", v === ALL_OPTION_VALUE ? "" : v)}>
                <SelectTrigger><SelectValue placeholder="Chọn" /></SelectTrigger>
                <SelectContent>
                  <SelectItem value={ALL_OPTION_VALUE}>Tất cả</SelectItem>
                  {statusFilterOptions.map((option) => <SelectItem key={option.value} value={option.value}>{option.label}</SelectItem>)}
                </SelectContent>
              </Select>
            </div>
            <div className="space-y-2">
              <Label htmlFor="date-from">Ngày gởi</Label>
              <Input
                id="date-from"
                inputMode="numeric"
                autoComplete="off"
                placeholder="dd/mm/yyyy"
                value={dateFromText}
                onChange={(e) => setDateFromText(e.target.value)}
                onBlur={() => {
                  const iso = parseDdMmYyyyToIso(dateFromText);
                  setFilter("dateFrom", iso);
                  setDateFromText(iso ? isoDateToDdMmYyyy(iso) : "");
                }}
              />
            </div>
            <div className="space-y-2">
              <Label htmlFor="author-name">Tác giả</Label>
              <Input
                id="author-name"
                value={authorInput}
                onChange={(e) => setAuthorInput(e.target.value)}
                placeholder="Nhập tên tác giả"
              />
            </div>
            <div className="space-y-2">
              <Label htmlFor="reviewer-name">Người đánh giá</Label>
              <Input
                id="reviewer-name"
                value={reviewerInput}
                onChange={(e) => setReviewerInput(e.target.value)}
                placeholder="Nhập tên người đánh giá"
              />
            </div>
            <div className="space-y-2">
              <Label>Người phụ trách</Label>
              <SearchableSelect value={filters.supervisorId} placeholder="Chọn người phụ trách" options={supervisorsQuery.data ?? []} onValueChange={(v) => setFilter("supervisorId", v)} />
            </div>
            <div className="space-y-2">
              <Label>Nhóm sáng kiến</Label>
              <Select value={filters.topicTypeId || ALL_OPTION_VALUE} onValueChange={(v) => setFilter("topicTypeId", v === ALL_OPTION_VALUE ? "" : v)}>
                <SelectTrigger><SelectValue placeholder="Chọn" /></SelectTrigger>
                <SelectContent>
                  <SelectItem value={ALL_OPTION_VALUE}>Tất cả</SelectItem>
                  {GROUP_OPTIONS.map((option) => (
                    <SelectItem key={option.value} value={option.value}>
                      {option.label}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
          </div>

          <div className="flex items-center gap-3">
            <Button onClick={() => setFilters((prev) => ({ ...prev, page: 1 }))}>Tìm</Button>
            <Button variant="ghost" onClick={handleReset}>Xóa bộ lọc</Button>
          </div>
        </CardContent>
      </Card>

      <div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
        <div>
          <h3 className="font-semibold">{resultsSectionTitleResolved} ({pagination.totalItems})</h3>
          {showStatusBreakdown ? (
            <p className="mt-1 text-sm text-muted-foreground">
              <span className="font-medium text-green-700 dark:text-green-500">Đã duyệt: {statusCounts.approved}</span>
              <span className="mx-2">·</span>
              <span className="font-medium text-destructive">Không duyệt: {statusCounts.rejected}</span>
            </p>
          ) : null}
        </div>
        <div className="flex flex-wrap items-center gap-2 shrink-0">
          <Button
            type="button"
            variant="outline"
            onClick={() => void exportAllBackupsZip()}
            className="shrink-0 gap-2"
            disabled={isExportingBackups || isExportingExcel || applicationsQuery.isLoading}
          >
            {isExportingBackups ? (
              <Loader2 className="h-4 w-4 animate-spin" aria-hidden />
            ) : (
              <Archive className="h-4 w-4" aria-hidden />
            )}
            ZIP sao lưu (tất cả)
          </Button>
          <Button
            onClick={exportExcel}
            className="shrink-0 gap-2 bg-green-600 hover:bg-green-700"
            disabled={isExportingExcel || isExportingBackups}
          >
            {isExportingExcel ? <Loader2 className="h-4 w-4 animate-spin" aria-hidden /> : null}
            Xuất Excel
          </Button>
        </div>
      </div>

      <Card>
        <CardHeader className="pb-3">
          <CardTitle className="text-base">File hồ sơ đã lưu trong public</CardTitle>
        </CardHeader>
        <CardContent>
          {reportFilesQuery.isLoading ? (
            <p className="text-sm text-muted-foreground">Đang tải danh sách file...</p>
          ) : (reportFilesQuery.data?.files?.length ?? 0) === 0 ? (
            <p className="text-sm text-muted-foreground">Chưa có file báo cáo nào.</p>
          ) : (
            <div className="space-y-2">
              {(reportFilesQuery.data?.files ?? []).slice(0, 10).map((file) => (
                <div key={file.fileName} className="flex items-center justify-between rounded border px-3 py-2">
                  <div>
                    <div className="text-sm font-medium">{file.fileName}</div>
                    <div className="text-xs text-muted-foreground">
                      Cập nhật: {formatIsoToDdMmYyyyHhMm(file.updatedAt)}
                    </div>
                  </div>
                  <Button size="sm" variant="outline" asChild>
                    <a href={file.publicUrl} target="_blank" rel="noreferrer">Xem file</a>
                  </Button>
                </div>
              ))}
            </div>
          )}
        </CardContent>
      </Card>

      <div className="overflow-x-auto rounded-md border">
        <Table>
          <TableHeader>
            <TableRow>
              <TableHead className="w-[50px]">STT</TableHead>
              <TableHead className="min-w-[250px]"><button type="button" onClick={() => toggleSort("name")} className="inline-flex items-center gap-1">Tên sáng kiến <ArrowUpDown className="h-3 w-3" /></button></TableHead>
              <TableHead className="min-w-[160px]"><button type="button" onClick={() => toggleSort("author")} className="inline-flex items-center gap-1">Tác giả <ArrowUpDown className="h-3 w-3" /></button></TableHead>
              <TableHead className="w-[120px]">Người đánh giá</TableHead>
              <TableHead className="w-[110px]">Nhóm sáng kiến</TableHead>
              <TableHead className="w-[110px]">Trạng thái</TableHead>
              <TableHead className="w-[60px] text-center">Minh chứng</TableHead>
              <TableHead className="min-w-[100px]">Đủ và Đúng</TableHead>
              <TableHead className="min-w-[160px]">Nhận xét</TableHead>
              {showBackupDownloadColumn ? (
                <TableHead className="w-[72px] text-center">Sao lưu</TableHead>
              ) : null}
              <TableHead className="w-[100px] text-center">Xem hồ sơ</TableHead>
            </TableRow>
          </TableHeader>
          <TableBody>
            {applicationsQuery.isLoading ? (
              <TableRow><TableCell colSpan={tableColSpan} className="py-10 text-center text-muted-foreground">Đang tải dữ liệu...</TableCell></TableRow>
            ) : applicationsQuery.isError ? (
              <TableRow>
                <TableCell colSpan={tableColSpan} className="py-10 text-center text-destructive">
                  Không thể tải hồ sơ đã nộp từ cơ sở dữ liệu. Vui lòng thử lại.
                </TableCell>
              </TableRow>
            ) : data.length === 0 ? (
              <TableRow><TableCell colSpan={tableColSpan} className="py-10 text-center text-muted-foreground">Chưa có hồ sơ nào được nộp thành công.</TableCell></TableRow>
            ) : (
              data.map((item, index) => {
                const stt = (pagination.page - 1) * pagination.pageSize + index + 1;
                return (
                  <TableRow key={item.id}>
                    <TableCell>{stt}</TableCell>
                    <TableCell className="max-w-[260px] truncate font-semibold" title={item.name}>{item.name}</TableCell>
                    <TableCell>
                      <div className="space-y-0.5">
                        <div className="font-semibold">{item.author.name}</div>
                        <div className="text-xs text-muted-foreground">{item.author.email ?? ""}</div>
                        <div className="text-xs text-muted-foreground">{item.author.phone ?? ""}</div>
                      </div>
                    </TableCell>
                    <TableCell>{item.reviewer?.name ?? "—"}</TableCell>
                    <TableCell className="max-w-[220px] align-top">
                      <span
                        className="line-clamp-4"
                        title={optionLabel(GROUP_OPTIONS, item.groupId) || item.topicType || undefined}
                      >
                        {optionLabel(GROUP_OPTIONS, item.groupId) || item.topicType || "—"}
                      </span>
                    </TableCell>
                    <TableCell>{statusBadge(getStatus(item), item)}</TableCell>
                    <TableCell className="text-center">
                      <EvidenceFilesTableCell
                        item={item}
                        caseId={item.draftCaseId || item.draft_case_id}
                      />
                    </TableCell>
                    <TableCell className="max-w-[140px] align-top text-sm">
                      {item.duVaDung?.trim() ? item.duVaDung : "—"}
                    </TableCell>
                    <TableCell className="max-w-[280px] align-top text-sm">
                      <span className="line-clamp-4 whitespace-pre-wrap" title={item.nhanXet?.trim() || undefined}>
                        {item.nhanXet?.trim() ? item.nhanXet : "—"}
                      </span>
                    </TableCell>
                    {showBackupDownloadColumn ? (
                      <TableCell className="text-center align-middle">
                        <div className="flex justify-center">
                          <ApplicationBackupDownloadButton
                            applicationId={item.id}
                            author={item.author}
                            variant="compact"
                          />
                        </div>
                      </TableCell>
                    ) : null}
                    <TableCell className="text-center">
                      <ViewSubmittedApplicationButton applicationId={item.id} returnTo={viewSubmittedReturnPath} />
                    </TableCell>
                  </TableRow>
                );
              })
            )}
          </TableBody>
        </Table>
      </div>

      <div className="flex flex-col justify-between gap-3 text-sm text-muted-foreground sm:flex-row sm:items-center">
        <div>Trang {pagination.page} / {Math.max(1, pagination.totalPages)} | Hiển thị {pagination.pageSize} / {pagination.totalItems} kết quả</div>
        <div className="flex items-center gap-2">
          <Select value={String(filters.pageSize)} onValueChange={(v) => setFilters((prev) => ({ ...prev, pageSize: Number(v), page: 1 }))}>
            <SelectTrigger className="w-[90px]"><SelectValue /></SelectTrigger>
            <SelectContent>
              {[10, 20, 50, 100].map((size) => <SelectItem key={size} value={String(size)}>{size}</SelectItem>)}
            </SelectContent>
          </Select>
          <Button variant="outline" size="sm" onClick={() => setFilter("page", Math.max(1, filters.page - 1))} disabled={filters.page <= 1}>Trước</Button>
          <Button variant="outline" size="sm" onClick={() => setFilter("page", Math.min(pagination.totalPages, filters.page + 1))} disabled={filters.page >= pagination.totalPages}>Sau</Button>
        </div>
      </div>
    </div>
  );
}
