import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { Link, useParams, useNavigate } from "react-router-dom";
import {
  ArrowLeft,
  Plus,
  LayoutGrid,
  PlayCircle,
  ClipboardCheck,
  Pencil,
  Trash2,
  ChevronRight,
  ArrowRight,
  X,
} from "lucide-react";
import { Button } from "../../components/ui/button";
import { Card } from "../../components/ui/card";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
  DialogClose,
} from "../../components/ui/dialog";
import { Input } from "../../components/ui/input";
import uploadIcon from "../../assets/icons/upload.png";
import { toast } from "sonner";
import { ResolvedImage } from "../../components/media/ResolvedImage";
import {
  createExamPrepCatalogUnit,
  getExamPrepCatalogCourses,
  setExamPrepCatalogCoursePublishStatus,
  setExamPrepCatalogUnitAccessTier,
  setExamPrepCatalogUnitPublishStatus,
  updateExamPrepCatalogUnit,
  deleteExamPrepCatalogUnit,
  getExamPrepCatalogUnits,
} from "../../api/courses.api";
import { uploadImageFile } from "../../api/files.api";
import { ContentPublishStatusChip } from "./components/ContentPublishStatusChip";
import { ContentAccessTierChip } from "./components/ContentAccessTierChip";
import { ContentListSearchFilterBar } from "./components/ContentListSearchFilterBar";
import { ContentPageDescription } from "./components/ContentPageDescription";
import type { ContentAccessTier, PracticePublishStatus } from "../../types/course.types";
import {
  filterBySearchAndPublishStatus,
  type PublishStatusFilter,
} from "../../lib/contentListFilters";

export function CourseManagementPage() {
  const navigate = useNavigate();
  const { programType, courseId } = useParams<{
    programType: string;
    courseId: string;
  }>();
  const catalogCourseId = Number(courseId);
  const [addUnitOpen, setAddUnitOpen] = useState(false);
  const [createName, setCreateName] = useState("");
  const [createSortOrder, setCreateSortOrder] = useState("");
  const [createThumbnail, setCreateThumbnail] = useState("");
  const [creating, setCreating] = useState(false);
  const [uploadingThumbnail, setUploadingThumbnail] = useState(false);
  const createThumbnailFileInputRef = useRef<HTMLInputElement>(null);
  const [units, setUnits] = useState<
    Array<{
      id: number;
      name: string;
      description: string;
      thumbnail: string;
      sortOrder: number;
      publishStatus: PracticePublishStatus | string | null;
      accessTier: ContentAccessTier | string | null;
      modules: number;
      lessons: number;
      practices: number;
      gradient: string;
    }>
  >([]);
  const [publishStatusUpdatingId, setPublishStatusUpdatingId] = useState<
    number | null
  >(null);
  const [accessTierUpdatingId, setAccessTierUpdatingId] = useState<
    number | null
  >(null);
  const [unitsLoading, setUnitsLoading] = useState(false);
  const [editingUnitId, setEditingUnitId] = useState<number | null>(null);
  const [editName, setEditName] = useState("");
  const [editThumbnail, setEditThumbnail] = useState("");
  const [editSortOrder, setEditSortOrder] = useState("1");
  const [savingEdit, setSavingEdit] = useState(false);
  const [uploadingEditThumbnail, setUploadingEditThumbnail] = useState(false);
  const editThumbnailFileInputRef = useRef<HTMLInputElement>(null);
  const [deletingUnitId, setDeletingUnitId] = useState<number | null>(null);
  const [deletingUnit, setDeletingUnit] = useState(false);
  const [listSearch, setListSearch] = useState("");
  const [publishStatusFilter, setPublishStatusFilter] =
    useState<PublishStatusFilter>("all");
  const [catalogCourseName, setCatalogCourseName] = useState("Course");
  const [catalogCourseDescription, setCatalogCourseDescription] = useState("");
  const [catalogCoursePublishStatus, setCatalogCoursePublishStatus] = useState<
    PracticePublishStatus | string | null
  >(null);
  const [catalogCoursePublishStatusUpdating, setCatalogCoursePublishStatusUpdating] =
    useState(false);

  const filteredUnits = useMemo(
    () =>
      filterBySearchAndPublishStatus(units, {
        search: listSearch,
        publishStatusFilter,
        getSearchFields: (u) => [u.name, u.description],
        getPublishStatus: (u) => u.publishStatus,
      }),
    [listSearch, publishStatusFilter, units],
  );

  const courseDisplayName = catalogCourseName;

  const loadCatalogCourse = useCallback(async () => {
    if (!Number.isFinite(catalogCourseId) || catalogCourseId < 1) return;
    try {
      const response = await getExamPrepCatalogCourses({ limit: 100, offset: 0 });
      const rows = response.data?.data?.catalog_courses;
      const list = Array.isArray(rows) ? rows : [];
      const row = list.find((c) => Number(c.id) === catalogCourseId);
      if (row) {
        setCatalogCourseName(row.name?.trim() || `Course ${catalogCourseId}`);
        setCatalogCourseDescription(row.description?.trim() || "");
        setCatalogCoursePublishStatus(row.publish_status ?? null);
      }
    } catch (error) {
      console.error(error);
    }
  }, [catalogCourseId]);

  const loadUnits = useCallback(async () => {
    if (!Number.isFinite(catalogCourseId) || catalogCourseId < 1) {
      setUnits([]);
      return;
    }
    setUnitsLoading(true);
    try {
      const response = await getExamPrepCatalogUnits(catalogCourseId, {
        limit: 20,
        offset: 0,
      });
      const rows = response.data?.data?.units;
      const list = Array.isArray(rows) ? rows : [];
      setUnits(
        list.map((row, index) => ({
          id: Number(row.id),
          name: row.name?.trim() || `Unit ${row.id}`,
          description: row.description?.trim() || "—",
          thumbnail: row.thumbnail?.trim() || "",
          sortOrder: Number(row.sort_order ?? 0),
          publishStatus: row.publish_status ?? null,
          accessTier: row.access_tier ?? null,
          modules: Number(row.modules_count ?? 0),
          lessons: Number(row.lessons_count ?? row.videos_count ?? 0),
          practices: Number(row.practices_count ?? 0),
          gradient:
            index % 3 === 1
              ? "linear-gradient(135deg, rgba(79, 70, 229, 0.5) 0%, rgba(79, 70, 229, 0.8) 100%)"
              : index % 3 === 2
                ? "linear-gradient(135deg, rgba(124, 58, 237, 0.5) 0%, rgba(124, 58, 237, 0.8) 100%)"
                : "linear-gradient(135deg, rgba(158, 40, 145, 0.5) 0%, rgba(158, 40, 145, 0.8) 100%)",
        })),
      );
    } catch (error) {
      console.error(error);
      toast.error("Failed to load units");
      setUnits([]);
    } finally {
      setUnitsLoading(false);
    }
  }, [catalogCourseId]);

  useEffect(() => {
    void loadCatalogCourse();
  }, [loadCatalogCourse]);

  useEffect(() => {
    void loadUnits();
  }, [loadUnits]);

  const handleCatalogCoursePublishStatus = async (
    nextStatus: PracticePublishStatus,
  ) => {
    if (!Number.isFinite(catalogCourseId) || catalogCourseId < 1) return;
    setCatalogCoursePublishStatusUpdating(true);
    try {
      await setExamPrepCatalogCoursePublishStatus(catalogCourseId, {
        publish_status: nextStatus,
      });
      setCatalogCoursePublishStatus(nextStatus);
      toast.success(
        nextStatus === "PUBLISHED" ? "Course published" : "Course saved as draft",
      );
    } catch (error: unknown) {
      const message =
        (error as { response?: { data?: { message?: string } } })?.response?.data
          ?.message ?? "Failed to update course status";
      toast.error(message);
    } finally {
      setCatalogCoursePublishStatusUpdating(false);
    }
  };

  const handleUnitPublishStatus = async (
    unitId: number,
    nextStatus: PracticePublishStatus,
  ) => {
    setPublishStatusUpdatingId(unitId);
    try {
      await setExamPrepCatalogUnitPublishStatus(unitId, {
        publish_status: nextStatus,
      });
      setUnits((prev) =>
        prev.map((u) =>
          u.id === unitId ? { ...u, publishStatus: nextStatus } : u,
        ),
      );
      toast.success(
        nextStatus === "PUBLISHED" ? "Unit published" : "Unit saved as draft",
      );
    } catch (error: unknown) {
      const message =
        (error as { response?: { data?: { message?: string } } })?.response?.data
          ?.message ?? "Failed to update unit status";
      toast.error(message);
    } finally {
      setPublishStatusUpdatingId(null);
    }
  };

  const handleUnitAccessTier = async (
    unitId: number,
    nextTier: ContentAccessTier,
  ) => {
    setAccessTierUpdatingId(unitId);
    try {
      await setExamPrepCatalogUnitAccessTier(unitId, { access_tier: nextTier });
      setUnits((prev) =>
        prev.map((u) =>
          u.id === unitId ? { ...u, accessTier: nextTier } : u,
        ),
      );
      toast.success(
        nextTier === "PREMIUM" ? "Unit set to Premium" : "Unit set to Free",
      );
    } catch (error: unknown) {
      const message =
        (error as { response?: { data?: { message?: string } } })?.response?.data
          ?.message ?? "Failed to update unit access tier";
      toast.error(message);
    } finally {
      setAccessTierUpdatingId(null);
    }
  };

  const isHttpUrl = (value: string) =>
    value.startsWith("http://") || value.startsWith("https://");

  const isMinioUrl = (value: string) => {
    try {
      const url = new URL(value);
      return url.host === "s3.yimaruacademy.com";
    } catch {
      return false;
    }
  };

  const resolveThumbnailToMinioUrl = async (rawValue: string) => {
    const trimmed = rawValue.trim();
    if (!trimmed) return "";
    if (!isHttpUrl(trimmed) || isMinioUrl(trimmed)) return trimmed;
    const uploaded = await uploadImageFile(trimmed);
    const uploadedUrl = uploaded.data?.data?.url?.trim();
    if (!uploadedUrl) throw new Error("Failed to upload thumbnail URL to MinIO");
    return uploadedUrl;
  };

  const clearCreateUnitForm = () => {
    setCreateName("");
    setCreateSortOrder("");
    setCreateThumbnail("");
    if (createThumbnailFileInputRef.current) {
      createThumbnailFileInputRef.current.value = "";
    }
  };

  const handleCreateUnitThumbnailFile = async (
    event: React.ChangeEvent<HTMLInputElement>,
  ) => {
    const file = event.target.files?.[0];
    event.target.value = "";
    if (!file) return;
    if (!file.type.startsWith("image/")) {
      toast.error("Please choose an image file");
      return;
    }
    const maxBytes = 5 * 1024 * 1024;
    if (file.size > maxBytes) {
      toast.error("Image is too large", { description: "Maximum size is 5 MB." });
      return;
    }
    setUploadingThumbnail(true);
    try {
      const res = await uploadImageFile(file);
      const url = res.data?.data?.url?.trim();
      if (!url) throw new Error("Upload did not return a file URL");
      setCreateThumbnail(url);
      toast.success("Thumbnail uploaded");
    } catch (error: unknown) {
      console.error(error);
      const message =
        (error as { response?: { data?: { message?: string } } })?.response?.data
          ?.message ?? "Failed to upload thumbnail";
      toast.error(message);
    } finally {
      setUploadingThumbnail(false);
    }
  };

  const handleCreateUnit = async () => {
    if (!Number.isFinite(catalogCourseId) || catalogCourseId < 1) {
      toast.error("Invalid catalog course");
      return;
    }
    const name = createName.trim();
    if (!name) {
      toast.error("Unit name is required");
      return;
    }
    const sortOrderRaw = createSortOrder.trim();
    if (!sortOrderRaw) {
      toast.error("Sort order is required");
      return;
    }
    const sort_order = Number(sortOrderRaw);
    if (!Number.isInteger(sort_order) || sort_order < 0) {
      toast.error("Sort order must be a whole number of 0 or greater");
      return;
    }
    setCreating(true);
    try {
      const minioThumbnail = await resolveThumbnailToMinioUrl(createThumbnail);
      const response = await createExamPrepCatalogUnit(catalogCourseId, {
        name,
        description: null,
        thumbnail: minioThumbnail || null,
        sort_order,
      });
      void response;
      await loadUnits();
      toast.success("Unit created");
      clearCreateUnitForm();
      setAddUnitOpen(false);
    } catch (error: unknown) {
      console.error(error);
      const message =
        (error as { response?: { data?: { message?: string } } })?.response?.data
          ?.message ?? "Failed to create unit";
      toast.error(message);
    } finally {
      setCreating(false);
    }
  };

  const autoUploadCreateThumbnailUrl = async (rawValue: string) => {
    const trimmed = rawValue.trim();
    if (!trimmed || !isHttpUrl(trimmed) || isMinioUrl(trimmed)) return;
    setUploadingThumbnail(true);
    try {
      const minioUrl = await resolveThumbnailToMinioUrl(trimmed);
      if (minioUrl && minioUrl !== trimmed) {
        setCreateThumbnail(minioUrl);
        toast.success("Thumbnail uploaded to MinIO");
      }
    } catch (error: unknown) {
      console.error(error);
      const message =
        (error as { response?: { data?: { message?: string } } })?.response?.data
          ?.message ?? "Failed to upload URL to MinIO";
      toast.error(message);
    } finally {
      setUploadingThumbnail(false);
    }
  };

  const autoUploadEditThumbnailUrl = async (rawValue: string) => {
    const trimmed = rawValue.trim();
    if (!trimmed || !isHttpUrl(trimmed) || isMinioUrl(trimmed)) return;
    setUploadingEditThumbnail(true);
    try {
      const minioUrl = await resolveThumbnailToMinioUrl(trimmed);
      if (minioUrl && minioUrl !== trimmed) {
        setEditThumbnail(minioUrl);
        toast.success("Thumbnail uploaded to MinIO");
      }
    } catch (error: unknown) {
      console.error(error);
      const message =
        (error as { response?: { data?: { message?: string } } })?.response?.data
          ?.message ?? "Failed to upload URL to MinIO";
      toast.error(message);
    } finally {
      setUploadingEditThumbnail(false);
    }
  };

  const openEditUnit = (unit: (typeof units)[number]) => {
    setEditingUnitId(unit.id);
    setEditName(unit.name ?? "");
    setEditThumbnail(unit.thumbnail ?? "");
    setEditSortOrder(String(unit.sortOrder ?? 0));
  };

  const closeEditUnit = () => {
    if (savingEdit || uploadingEditThumbnail) return;
    setEditingUnitId(null);
    setEditName("");
    setEditThumbnail("");
    setEditSortOrder("");
  };

  const handleEditUnitThumbnailFile = async (
    event: React.ChangeEvent<HTMLInputElement>,
  ) => {
    const file = event.target.files?.[0];
    event.target.value = "";
    if (!file) return;
    if (!file.type.startsWith("image/")) {
      toast.error("Please choose an image file");
      return;
    }
    setUploadingEditThumbnail(true);
    try {
      const res = await uploadImageFile(file);
      const url = res.data?.data?.url?.trim();
      if (!url) throw new Error("Upload did not return a file URL");
      setEditThumbnail(url);
      toast.success("Thumbnail uploaded");
    } catch (error: unknown) {
      console.error(error);
      const message =
        (error as { response?: { data?: { message?: string } } })?.response?.data
          ?.message ?? "Failed to upload thumbnail";
      toast.error(message);
    } finally {
      setUploadingEditThumbnail(false);
    }
  };

  const handleSaveEditUnit = async () => {
    if (!editingUnitId) return;
    const name = editName.trim();
    if (!name) {
      toast.error("Unit name is required");
      return;
    }
    const sortOrderRaw = editSortOrder.trim();
    if (!sortOrderRaw) {
      toast.error("Sort order is required");
      return;
    }
    const sort_order = Number(sortOrderRaw);
    if (!Number.isInteger(sort_order) || sort_order < 0) {
      toast.error("Sort order must be a whole number of 0 or greater");
      return;
    }

    setSavingEdit(true);
    try {
      const existing = units.find((u) => u.id === editingUnitId);
      const preservedDescription =
        existing?.description && existing.description !== "—"
          ? existing.description
          : null;
      const minioThumbnail = await resolveThumbnailToMinioUrl(editThumbnail);
      await updateExamPrepCatalogUnit(editingUnitId, {
        name,
        description: preservedDescription,
        thumbnail: minioThumbnail || null,
        sort_order,
      });
      await loadUnits();
      toast.success("Unit updated");
      closeEditUnit();
    } catch (error: unknown) {
      console.error(error);
      const message =
        (error as { response?: { data?: { message?: string } } })?.response?.data
          ?.message ?? "Failed to update unit";
      toast.error(message);
    } finally {
      setSavingEdit(false);
    }
  };

  const handleDeleteUnit = async () => {
    if (!deletingUnitId) return;
    setDeletingUnit(true);
    try {
      await deleteExamPrepCatalogUnit(deletingUnitId);
      await loadUnits();
      toast.success("Unit deleted");
      setDeletingUnitId(null);
    } catch (error: unknown) {
      console.error(error);
      const message =
        (error as { response?: { data?: { message?: string } } })?.response?.data
          ?.message ?? "Failed to delete unit";
      toast.error(message);
    } finally {
      setDeletingUnit(false);
    }
  };

  return (
    <div className="space-y-8 animate-in fade-in duration-500 pb-10">
      {/* Navigation */}
      <Link
        to={`/new-content/courses/${programType}`}
        className="flex items-center gap-2.5 text-[15px] font-semibold text-grayScale-600 hover:text-brand-500 transition-colors pt-4 group"
      >
        <ArrowLeft className="h-5 w-5 transition-transform group-hover:-translate-x-1" />
        Back to Courses
      </Link>

      {/* Header section */}
      <div className="flex items-start justify-between">
        <div className="space-y-2">
          <div className="flex flex-wrap items-center gap-2">
            <ContentPublishStatusChip
              publishStatus={catalogCoursePublishStatus}
              updating={catalogCoursePublishStatusUpdating}
              contentLabel="course"
              onToggle={(nextStatus) =>
                void handleCatalogCoursePublishStatus(nextStatus)
              }
            />
          </div>
          <h1 className="text-[28px] font-medium tracking-tight text-grayScale-900">
            {courseDisplayName}
          </h1>
          {catalogCourseDescription ? (
            <ContentPageDescription className="text-[15px] font-medium text-grayScale-500">
              {catalogCourseDescription}
            </ContentPageDescription>
          ) : (
            <p className="max-w-2xl text-[15px] font-medium leading-relaxed text-grayScale-500">
              Manage units and modules inside {courseDisplayName}
            </p>
          )}
        </div>

        <div className="flex items-center gap-3 pt-2">
          <Dialog
            open={addUnitOpen}
            onOpenChange={(open) => {
              if (!open && (creating || uploadingThumbnail)) return;
              setAddUnitOpen(open);
            }}
          >
            <DialogTrigger asChild>
              <Button className="h-10 px-6 rounded-[6px] bg-brand-500 font-bold text-white shadow-sm hover:bg-brand-600 transition-all flex items-center gap-2">
                <Plus className="h-5 w-5" />
                Add Unit
              </Button>
            </DialogTrigger>
            <DialogContent className="flex max-h-[min(90vh,calc(100dvh-2rem))] max-w-[600px] flex-col gap-0 overflow-hidden rounded-[16px] border-none p-0">
              <div className="flex min-h-0 flex-1 flex-col bg-white">
                <DialogHeader className="shrink-0 px-8 py-6 border-b border-grayScale-200 flex flex-row items-center justify-between">
                  <DialogTitle className="text-[20px] font-bold relative top-2 text-grayScale-900">
                    Create Unit
                  </DialogTitle>
                </DialogHeader>

                <div className="min-h-0 flex-1 overflow-y-auto p-8 space-y-8">
                  <div className="space-y-3">
                    <label className="text-[15px] text-grayScale-800">
                      Unit Name
                    </label>
                    <Input
                      value={createName}
                      onChange={(e) => setCreateName(e.target.value)}
                      placeholder="e.g. Reading"
                      className="h-12 border-grayScale-400 rounded-[8px] px-4 placeholder:text-grayScale-400 text-[15px] focus:ring-brand-500/20"
                      disabled={creating || uploadingThumbnail}
                    />
                  </div>

                  <div className="space-y-3">
                    <label
                      htmlFor="create-unit-sort-order"
                      className="text-[15px] text-grayScale-800"
                    >
                      Sort Order
                    </label>
                    <Input
                      id="create-unit-sort-order"
                      type="number"
                      min={0}
                      step={1}
                      inputMode="numeric"
                      value={createSortOrder}
                      onChange={(e) => setCreateSortOrder(e.target.value)}
                      placeholder="e.g. 0"
                      className="h-12 border-grayScale-400 rounded-[8px] px-4 placeholder:text-grayScale-400 text-[15px] focus:ring-brand-500/20"
                      disabled={creating || uploadingThumbnail}
                    />
                    <p className="text-xs text-grayScale-500">
                      Lower numbers appear first when units are listed.
                    </p>
                  </div>

                  <div className="space-y-3">
                    <label className="text-[15px] text-grayScale-800">
                      Thumbnail
                    </label>
                    <input
                      ref={createThumbnailFileInputRef}
                      type="file"
                      accept="image/*"
                      className="sr-only"
                      onChange={(e) => void handleCreateUnitThumbnailFile(e)}
                      disabled={creating || uploadingThumbnail}
                    />
                    <button
                      type="button"
                      className="relative group w-full cursor-pointer"
                      onClick={() => createThumbnailFileInputRef.current?.click()}
                      disabled={creating || uploadingThumbnail}
                    >
                      <div className="flex flex-col items-center justify-center rounded-[12px] border-2 border-dashed border-grayScale-400 bg-white py-8 px-10 transition-all ">
                        <div className="mb-4">
                          <img
                            src={uploadIcon}
                            alt="Upload icon"
                            className="h-10 w-10"
                          />
                        </div>
                        <p className="text-[15px]">
                          <span className="text-brand-500 font-bold hover:underline">
                            {uploadingThumbnail ? "Uploading…" : "Click to upload"}
                          </span>{" "}
                          <span className="text-grayScale-500">
                            or paste a URL below
                          </span>
                        </p>
                        <p className="mt-1.5 text-[12px] text-grayScale-400 uppercase tracking-widest">
                          JPG, PNG (MAX 5 MB)
                        </p>
                      </div>
                    </button>
                    {createThumbnail.trim() ? (
                      <div className="overflow-hidden rounded-xl border border-grayScale-200 bg-grayScale-50">
                        <ResolvedImage
                          src={createThumbnail.trim()}
                          alt=""
                          className="h-28 w-full object-cover"
                        />
                      </div>
                    ) : null}
                    <Input
                      value={createThumbnail}
                      onChange={(e) => setCreateThumbnail(e.target.value)}
                      onPaste={(event) => {
                        const pasted = event.clipboardData?.getData("text")?.trim();
                        if (!pasted) return;
                        setTimeout(() => {
                          void autoUploadCreateThumbnailUrl(pasted);
                        }, 0);
                      }}
                      placeholder="Optional thumbnail URL (or leave empty for null)"
                      className="h-12 border-grayScale-400 rounded-[8px] px-4 placeholder:text-grayScale-400 text-[15px] focus:ring-brand-500/20"
                      disabled={creating || uploadingThumbnail}
                    />
                  </div>
                </div>

                <div className="shrink-0 px-8 py-6 bg-grayScale-50/30 border-t border-grayScale-50 flex justify-end gap-3">
                  <DialogClose asChild>
                    <Button
                      type="button"
                      variant="outline"
                      className="h-11 px-8 rounded-[8px] border-grayScale-200 text-grayScale-700 font-bold"
                      disabled={creating || uploadingThumbnail}
                      onClick={clearCreateUnitForm}
                    >
                      Cancel
                    </Button>
                  </DialogClose>
                  <Button
                    type="button"
                    className="h-11 px-8 rounded-[8px] bg-brand-500 text-white font-bold hover:bg-brand-600"
                    disabled={creating || uploadingThumbnail}
                    onClick={() => void handleCreateUnit()}
                  >
                    {creating ? "Creating..." : "Create Unit"}
                  </Button>
                </div>
              </div>
            </DialogContent>
          </Dialog>
        </div>
      </div>

      {/* Horizontal Divider */}
      <div className="relative">
        <div className="absolute inset-0 flex items-center" aria-hidden="true">
          <div className="w-full border-t border-grayScale-200" />
        </div>
        <div className="relative flex justify-center">
          <div
            className="h-[0.5px] w-full opacity-20 rounded-full"
            style={{
              background: "gray",
            }}
          />
        </div>
      </div>

      {/* Grid of Units */}
      <div className="space-y-4 pt-4">
        {!unitsLoading && units.length > 0 ? (
          <ContentListSearchFilterBar
            search={listSearch}
            onSearchChange={setListSearch}
            publishStatusFilter={publishStatusFilter}
            onPublishStatusFilterChange={setPublishStatusFilter}
            searchPlaceholder="Search units by name or description…"
            searchAriaLabel="Search units"
          />
        ) : null}
        <div className="flex flex-wrap gap-4">
        {unitsLoading ? (
          <p className="text-sm text-grayScale-500">Loading units...</p>
        ) : units.length === 0 ? (
          <div className="w-full rounded-xl border border-dashed border-grayScale-200 bg-grayScale-50/50 px-6 py-14 text-center">
            <p className="text-sm font-medium text-grayScale-600">
              No units for this course yet
            </p>
            <p className="mt-1 text-sm text-grayScale-400">
              Create your first unit to start organizing modules, lessons, and practices.
            </p>
          </div>
        ) : filteredUnits.length === 0 ? (
          <div className="w-full rounded-xl border border-dashed border-grayScale-200 bg-grayScale-50/50 px-6 py-14 text-center">
            <p className="text-sm font-medium text-grayScale-600">
              No units match your search or status filter
            </p>
          </div>
        ) : (
          filteredUnits.map((unit) => (
          <Card
            key={unit.id}
            className="group relative flex w-[400px] flex-col h-full bg-white rounded-[12px] border border-grayScale-100 overflow-hidden shadow-sm hover:shadow-md transition-all"
          >
            <div className="absolute right-2 top-2 z-10 flex translate-y-1 gap-1 opacity-0 pointer-events-none transition-all duration-300 ease-out group-hover:translate-y-0 group-hover:opacity-100 group-hover:pointer-events-auto">
              <Button
                type="button"
                variant="secondary"
                size="icon"
                className="h-8 w-8 rounded-md bg-white/95 text-grayScale-600 shadow-sm transition-colors hover:bg-white"
                onClick={() => openEditUnit(unit)}
                aria-label={`Edit ${unit.name}`}
              >
                <Pencil className="h-3.5 w-3.5" />
              </Button>
              <Button
                type="button"
                variant="secondary"
                size="icon"
                className="h-8 w-8 rounded-md bg-white/95 text-red-600 shadow-sm transition-colors hover:bg-red-50"
                onClick={() => setDeletingUnitId(unit.id)}
                aria-label={`Delete ${unit.name}`}
              >
                <Trash2 className="h-3.5 w-3.5" />
              </Button>
            </div>
            {/* Gradient Header */}
            <div
              className="relative h-36 w-full overflow-hidden transition-transform duration-500"
              style={{ background: unit.gradient }}
            >
              {unit.thumbnail ? (
                <ResolvedImage
                  src={unit.thumbnail}
                  alt={`${unit.name} thumbnail`}
                  className="h-full w-full object-cover"
                  onError={(event) => {
                    event.currentTarget.style.display = "none";
                  }}
                />
              ) : null}
            </div>

            <div className="p-4 flex flex-col flex-1 space-y-6">
              <div className="space-y-3 flex-1">
                <div className="flex flex-wrap gap-2">
                  <ContentPublishStatusChip
                    publishStatus={unit.publishStatus}
                    updating={publishStatusUpdatingId === unit.id}
                    contentLabel="unit"
                    onToggle={(nextStatus) =>
                      void handleUnitPublishStatus(unit.id, nextStatus)
                    }
                  />
                  <ContentAccessTierChip
                    accessTier={unit.accessTier}
                    updating={accessTierUpdatingId === unit.id}
                    contentLabel="unit"
                    onToggle={(nextTier) =>
                      void handleUnitAccessTier(unit.id, nextTier)
                    }
                  />
                </div>
                <h3 className="text-[18px] font-medium text-grayScale-900  transition-colors">
                  {unit.name}
                </h3>
                <p className="text-[12px] text-grayScale-500 font-medium line-clamp-3">
                  {unit.description}
                </p>
              </div>

              {/* Stats Pills */}
              <div className="flex flex-wrap gap-3">
                <div className="h-9 px-3 rounded-[6px] bg-grayScale-100 border border-grayScale-100 flex items-center gap-2 text-grayScale-600">
                  <LayoutGrid className="h-3.5 w-3.5 text-grayScale-400" />
                  <span className="text-[12px] font-bold">
                    {unit.modules} Modules
                  </span>
                </div>
                <div className="h-9 px-3 rounded-[6px] bg-grayScale-100 border border-grayScale-100 flex items-center gap-2 text-grayScale-600">
                  <PlayCircle className="h-3.5 w-3.5 text-grayScale-400" />
                  <span className="text-[12px] font-bold">
                    {unit.lessons} Lessons
                  </span>
                </div>
                <div className="h-9 px-3 rounded-[6px] bg-grayScale-100 border border-grayScale-100 flex items-center gap-2 text-grayScale-600">
                  <ClipboardCheck className="h-3.5 w-3.5 text-grayScale-400" />
                  <span className="text-[12px] font-bold">
                    {unit.practices} Practices
                  </span>
                </div>
              </div>

              {/* Action Button */}
              <Button
                className="w-full h-10 bg-brand-500  text-white rounded-[6px] font-bold flex items-center justify-center gap-2 group/btn"
                onClick={() =>
                  navigate(
                    `/new-content/courses/${programType}/${courseId}/${unit.id}`,
                  )
                }
              >
                View Detail
                <ArrowRight className="ml-2 h-4 w-4" />
              </Button>
            </div>
          </Card>
          ))
        )}
        </div>
      </div>

      <Dialog
        open={editingUnitId !== null}
        onOpenChange={(open) => {
          if (!open && (savingEdit || uploadingEditThumbnail)) return;
          if (!open) closeEditUnit();
        }}
      >
        <DialogContent className="flex max-h-[min(90vh,calc(100dvh-2rem))] max-w-[600px] flex-col gap-0 overflow-hidden rounded-[16px] border-none p-0">
          <div className="flex min-h-0 flex-1 flex-col bg-white">
            <DialogHeader className="shrink-0 px-8 py-6 border-b border-grayScale-200 flex flex-row items-center justify-between">
              <DialogTitle className="text-[20px] font-bold relative top-2 text-grayScale-900">
                Edit Unit
              </DialogTitle>
            </DialogHeader>
            <div className="min-h-0 flex-1 overflow-y-auto p-8 space-y-8">
              <div className="space-y-3">
                <label className="text-[15px] text-grayScale-800">Unit Name</label>
                <Input
                  value={editName}
                  onChange={(e) => setEditName(e.target.value)}
                  className="h-12 border-grayScale-400 rounded-[8px] px-4"
                  disabled={savingEdit || uploadingEditThumbnail}
                />
              </div>
              <div className="space-y-3">
                <label
                  htmlFor="edit-unit-sort-order"
                  className="text-[15px] text-grayScale-800"
                >
                  Sort Order
                </label>
                <Input
                  id="edit-unit-sort-order"
                  type="number"
                  min={0}
                  step={1}
                  inputMode="numeric"
                  value={editSortOrder}
                  onChange={(e) => setEditSortOrder(e.target.value)}
                  placeholder="e.g. 0"
                  className="h-12 border-grayScale-400 rounded-[8px] px-4 placeholder:text-grayScale-400 text-[15px] focus:ring-brand-500/20"
                  disabled={savingEdit || uploadingEditThumbnail}
                />
                <p className="text-xs text-grayScale-500">
                  Lower numbers appear first when units are listed.
                </p>
              </div>
              <div className="space-y-3">
                <label className="text-[15px] text-grayScale-800">Thumbnail</label>
                <input
                  ref={editThumbnailFileInputRef}
                  type="file"
                  accept="image/*"
                  className="sr-only"
                  onChange={(e) => void handleEditUnitThumbnailFile(e)}
                  disabled={savingEdit || uploadingEditThumbnail}
                />
                <button
                  type="button"
                  className="relative group w-full cursor-pointer"
                  onClick={() => editThumbnailFileInputRef.current?.click()}
                  disabled={savingEdit || uploadingEditThumbnail}
                >
                  <div className="flex flex-col items-center justify-center rounded-[12px] border-2 border-dashed border-grayScale-400 bg-white py-8 px-10 transition-all ">
                    <div className="mb-4">
                      <img src={uploadIcon} alt="Upload icon" className="h-10 w-10" />
                    </div>
                    <p className="text-[15px]">
                      <span className="text-brand-500 font-bold hover:underline">
                        {uploadingEditThumbnail ? "Uploading…" : "Click to upload"}
                      </span>{" "}
                      <span className="text-grayScale-500">or paste a URL below</span>
                    </p>
                    <p className="mt-1.5 text-[12px] text-grayScale-400 uppercase tracking-widest">
                      JPG, PNG (MAX 5 MB)
                    </p>
                  </div>
                </button>
                {editThumbnail.trim() ? (
                  <div className="overflow-hidden rounded-xl border border-grayScale-200 bg-grayScale-50">
                    <ResolvedImage
                      src={editThumbnail.trim()}
                      alt=""
                      className="h-28 w-full object-cover"
                    />
                  </div>
                ) : null}
                <Input
                  value={editThumbnail}
                  onChange={(e) => setEditThumbnail(e.target.value)}
                  onPaste={(event) => {
                    const pasted = event.clipboardData?.getData("text")?.trim();
                    if (!pasted) return;
                    setTimeout(() => {
                      void autoUploadEditThumbnailUrl(pasted);
                    }, 0);
                  }}
                  placeholder="Optional thumbnail URL (or leave empty for null)"
                  className="h-12 border-grayScale-400 rounded-[8px] px-4"
                  disabled={savingEdit || uploadingEditThumbnail}
                />
              </div>
            </div>
            <div className="shrink-0 px-8 py-6 bg-grayScale-50/30 border-t border-grayScale-50 flex justify-end gap-3">
              <Button
                type="button"
                variant="outline"
                className="h-11 px-8 rounded-[8px] border-grayScale-200 text-grayScale-700 font-bold"
                disabled={savingEdit || uploadingEditThumbnail}
                onClick={closeEditUnit}
              >
                Cancel
              </Button>
              <Button
                type="button"
                className="h-11 px-8 rounded-[8px] bg-brand-500 text-white font-bold hover:bg-brand-600"
                disabled={savingEdit || uploadingEditThumbnail}
                onClick={() => void handleSaveEditUnit()}
              >
                {savingEdit ? "Saving..." : "Save Changes"}
              </Button>
            </div>
          </div>
        </DialogContent>
      </Dialog>

      <Dialog
        open={deletingUnitId !== null}
        onOpenChange={(open) => {
          if (!open && !deletingUnit) setDeletingUnitId(null);
        }}
      >
        <DialogContent className="max-w-md rounded-[16px] border-none p-0 overflow-hidden">
          <div className="bg-white">
            <DialogHeader className="border-b border-grayScale-100 px-6 py-5">
              <DialogTitle className="text-lg font-bold text-grayScale-900">
                Delete Unit
              </DialogTitle>
            </DialogHeader>
            <div className="px-6 py-6 text-sm text-grayScale-600">
              Are you sure you want to delete this unit? This action cannot be undone.
            </div>
            <div className="flex justify-end gap-3 border-t border-grayScale-100 px-6 py-4">
              <Button
                variant="outline"
                onClick={() => setDeletingUnitId(null)}
                disabled={deletingUnit}
              >
                Cancel
              </Button>
              <Button
                className="bg-red-500 hover:bg-red-600"
                onClick={() => void handleDeleteUnit()}
                disabled={deletingUnit}
              >
                {deletingUnit ? "Deleting..." : "Delete"}
              </Button>
            </div>
          </div>
        </DialogContent>
      </Dialog>
    </div>
  );
}
