"use client";

import { useRouter } from "next/navigation";
import {
  useCallback,
  useEffect,
  useRef,
  useState,
  type ReactNode,
} from "react";
import {
  ProjectActionsDropdown,
  type ProjectActionKey,
} from "@/components/ProjectActionsDropdown";
import {
  CanvasTemplatePreviewModal,
  type CanvasTemplatePreviewData,
} from "@/components/CanvasTemplatePreviewModal";
import {
  ArrowIcon,
  CloseIcon,
  DefaultAvatar,
  LeftOutlinedIcon,
  SearchIcon,
  StartCreation,
} from "@/components/icons";
import { authFetch } from "@/utils/authFetch";
import { useI18n, type TranslationKey } from "@/i18n";
import {
  createCanvasWorkflow,
  deleteCanvasWorkflow,
  getCanvasWorkflowDetail,
  listCanvasWorkflows,
  type CanvasWorkflowListItem,
  type CanvasWorkflowPageInfo,
  updateCanvasWorkflow,
  uploadCanvasWorkflowCover,
} from "@/lib/canvasWorkflowApi";
import { Form, Input, Modal, Tooltip, message } from "antd";
type Translate = (key: TranslationKey, values?: Record<string, string | number>) => string;

type ProjectData = {
  id: number;
  title: string;
  date: string;
  image: string;
  uploadProgress?: number;
};

type ShowData = {
  id: number;
  title: string;
  subtitle: string;
  image: string;
  avatar: string;
  vip?: boolean;
  data: string;
};

type TemplateCategoryData = {
  id: number | null;
  name: string;
};

type CanvasTemplateCategoryItem = {
  id: number;
  name: string;
  sort: number;
  deleted: boolean;
};

type CanvasTemplateItem = {
  id: number;
  categoryId: number;
  type: number;
  coverUrl: string;
  properties: string;
  name: string;
  desp: string;
  deleted: boolean;
  categoryName: string;
  userInfo: {
    avatar: string;
    code: string;
    id: number;
    name: string;
  }
};

type ListResponse<T> = {
  data?: {
    pageInfo?: CanvasWorkflowPageInfo;
    list?: T[];
  };
  status?: string;
};

type HomeProjectsContentProps = {
  heroSection: ReactNode;
};

const DEFAULT_PROJECT_PAGE_INFO: CanvasWorkflowPageInfo = {
  page: 1,
  pageSize: 4,
  pageCount: 1,
  total: 0,
};

const ALL_PROJECTS_LOAD_MORE_OFFSET = 260;
const SHOWS_PAGE_SIZE = 20;
const SHOWS_LOAD_MORE_OFFSET = 260;

function formatProjectTime(value?: string): string {
  if (!value) return "-";
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return value;
  return date.toLocaleDateString();
}

function mapWorkflowToProject(item: CanvasWorkflowListItem): ProjectData {
  return {
    id: item.id,
    title: item.title?.trim() || item.code?.trim() || `#${item.id}`,
    date: formatProjectTime(item.updateTime || item.createTime),
    image: item.coverUrl || "",
  };
}

function buildEmptyWorkflowProperties(title: string): string {
  return JSON.stringify({
    name: title,
    nodes: [],
    edges: [],
    edgeStyle: "curved",
  });
}

function ProjectCard({
  id,
  title,
  date,
  image,
  uploadProgress,
  t,
  onOpen,
  onAction,
}: ProjectData & {
  t: Translate;
  onOpen: () => void;
  onAction: (id: number, action: ProjectActionKey) => void;
}) {
  const isUploadingCover = typeof uploadProgress === "number";

  return (
    <article className="min-w-0">
      <button
        type="button"
        onClick={onOpen}
        disabled={isUploadingCover}
        className="group relative block h-[139px] w-full overflow-hidden rounded-[24px] bg-[#ddd] text-left disabled:cursor-default"
      >
        <img
          src={image || '/empty_project.png'}
          alt=""
          className="h-full w-full object-cover transition duration-500 group-hover:scale-105"
        />
        {isUploadingCover ? (
          <div className="absolute inset-0 flex flex-col items-center justify-center bg-black/45 px-6 text-white">
            <span className="text-[13px] font-medium leading-none">
              {t("home.uploading", { progress: uploadProgress })}
            </span>
            <div className="mt-3 h-1.5 w-full overflow-hidden rounded-full bg-white/35">
              <div
                className="h-full rounded-full bg-white transition-all duration-300"
                style={{ width: `${uploadProgress}%` }}
              />
            </div>
          </div>
        ) : null}
      </button>
      <div className="mt-3 flex items-start justify-between gap-3">
        <div className="min-w-0">
          <button type="button" onClick={onOpen} className="block max-w-full text-left">
            <h3 className="truncate text-[16px] font-medium leading-tight text-[#333]">
              {title}
            </h3>
          </button>
          <p className="mt-1 text-[13px] leading-tight text-[#666]">{date}</p>
        </div>
        <ProjectActionsDropdown
          title={title}
          label={t("home.moreActions")}
          onAction={(action) => onAction(id, action)}
        />
      </div>
    </article>
  );
}

function ShowCard({ id, title, subtitle, image, avatar, vip, data, onOpen }: ShowData & { onOpen: (data: ShowData) => void }) {
  return (
    <article className="group min-w-0" onClick={() => onOpen({ id, title, subtitle, image, avatar, vip, data })}>
      <div className="h-[189px] overflow-hidden rounded-[24px] bg-[#ddd]">
        <img
          src={image || '/empty_project.png'}
          alt=""
          className="h-full w-full object-cover transition duration-500 group-hover:scale-105"
        />
      </div>
      <div className="mt-3">
        <div className="flex items-center gap-[5px]">
          {avatar ?
            <img
              src={avatar || '/empty_project.png'}
              alt=""
              className="grid h-5 w-5 place-items-center rounded-full bg-[#d6ceef] text-[11px]">
            </img>
            :
            <div className="grid h-5 w-5 place-items-center rounded-full bg-[#d6ceef] text-[11px]">
              <DefaultAvatar></DefaultAvatar>
            </div>
          }
          <h3 className="truncate text-[16px] font-medium leading-tight text-[#333]">
            {title}
          </h3>
          {/* {vip ? (
            <span className="rounded-full bg-[linear-gradient(90deg,#d6ceef_45%,#f0f0f0_100%)] px-2.5 py-0.5 text-[12px] font-medium leading-none text-[#5c3bc7]">
              VIP
            </span>
          ) : null} */}
        </div>
        <Tooltip title={subtitle || '-'} placement="top">
          <p className="mt-2 truncate text-[13px] leading-tight text-[#666]">
            {subtitle || '-'}
          </p>
        </Tooltip>
      </div>
    </article>
  );
}

function ProjectSectionGrid({
  projects,
  isLoadingProjects,
  isCreating,
  t,
  showOverflowCue = false,
  pageInfo,
  onPrevPage,
  onNextPage,
  onStartCreation,
  onProjectAction,
}: {
  projects: ProjectData[];
  isLoadingProjects: boolean;
  isCreating: boolean;
  t: Translate;
  showOverflowCue?: boolean;
  pageInfo?: CanvasWorkflowPageInfo;
  onPrevPage?: () => void;
  onNextPage?: () => void;
  onStartCreation: () => void;
  onProjectAction: (id: number, action: ProjectActionKey) => void;
}) {
  const router = useRouter();
  const canGoPrev = !!pageInfo && pageInfo.page > 1;
  const canGoNext = !!pageInfo && pageInfo.page < pageInfo.pageCount;
  const uniqueProjects = projects.filter(
    (project, index, list) => list.findIndex((item) => item.id === project.id) === index
  );
  const [firstProject, ...remainingProjects] = uniqueProjects;

  return (
    <div className="relative grid gap-5 md:grid-cols-2 xl:grid-cols-5">
      <button
        type="button"
        onClick={onStartCreation}
        disabled={isCreating}
        className="flex h-[139px] flex-col items-center justify-center rounded-[24px] border border-[#d6ceef] bg-[linear-gradient(123deg,#f0f0f0_20%,#d6ceef_100%)] transition hover:border-[#5c3bc7] disabled:cursor-not-allowed disabled:opacity-70"
      >
        <StartCreation />
        <span className="mt-2 text-[18px] font-medium leading-none text-[#999]">
          {t("home.startCreation")}
        </span>
      </button>
      {isLoadingProjects && projects.length === 0 ? (
        <div className="flex h-[139px] items-center justify-center rounded-[24px] bg-white text-[14px] text-[#999]">
          {t("home.loading")}
        </div>
      ) : null}
      {firstProject ? (
        <div key={firstProject.id} className="relative z-[15] min-w-0">
          {pageInfo ? (
            <>
              <div className="pointer-events-none absolute left-0 top-0 z-[5] hidden h-[139px] w-[105px] bg-gradient-to-r from-[#f9f9f9] to-[#f9f9f9]/0 xl:block" />
              <button
                type="button"
                aria-label={t("home.prevProject")}
                title={t("home.prevProject")}
                onClick={onPrevPage}
                disabled={!canGoPrev || isLoadingProjects}
                className="absolute left-[-19px] top-[50px] z-[20] hidden h-[39px] w-[39px] items-center justify-center rounded-full bg-white text-[#666] shadow-[0_2px_5px_rgba(0,0,0,0.1)] transition hover:bg-[#f0f0f0] disabled:cursor-not-allowed disabled:opacity-40 xl:flex"
              >
                <span className="rotate-180">
                  <ArrowIcon />
                </span>
              </button>
            </>
          ) : null}
          <ProjectCard
            {...firstProject}
            t={t}
            onOpen={() => router.push(`/canvas?workflowId=${firstProject.id}`)}
            onAction={onProjectAction}
          />
        </div>
      ) : null}
      {remainingProjects.map((project) => (
        <ProjectCard
          key={project.id}
          {...project}
          t={t}
          onOpen={() => router.push(`/canvas?workflowId=${project.id}`)}
          onAction={onProjectAction}
        />
      ))}
      {showOverflowCue && pageInfo && (
        <>
          <div className="pointer-events-none absolute right-0 top-0 hidden h-[139px] w-[105px] bg-gradient-to-r from-[#f9f9f9]/0 to-[#f9f9f9] xl:block" />
          <button
            type="button"
            aria-label={t("home.nextProject")}
            title={t("home.nextProject")}
            onClick={onNextPage}
            disabled={!canGoNext || isLoadingProjects}
            className="absolute right-[-25px] top-[52px] hidden h-[39px] w-[39px] items-center justify-center rounded-full bg-white text-[#666] shadow-[0_2px_5px_rgba(0,0,0,0.1)] transition hover:bg-[#f0f0f0] disabled:cursor-not-allowed disabled:opacity-40 xl:flex"
          >
            <ArrowIcon />
          </button>
        </>
      )}
    </div>
  );
}

function ProjectActionModals({
  t,
  isActionLoading,
  renameOpen,
  renameTitle,
  onRenameTitleChange,
  onCancelRename,
  onConfirmRename,
  deleteTitle,
  onCancelDelete,
  onConfirmDelete,
}: {
  t: Translate;
  isActionLoading: boolean;
  renameOpen: boolean;
  renameTitle: string;
  onRenameTitleChange: (value: string) => void;
  onCancelRename: () => void;
  onConfirmRename: () => void;
  deleteTitle: string | null;
  onCancelDelete: () => void;
  onConfirmDelete: () => void;
}) {
  const modalClassName =
    "[&_.ant-modal-content]:!rounded-[9px] [&_.ant-modal-content]:!p-[30px] [&_.ant-modal-header]:!mb-0 [&_.ant-modal-body]:!pt-2 [&_.ant-modal-footer]:!mt-6 [&_.ant-modal-footer]:!flex [&_.ant-modal-footer]:!justify-end [&_.ant-modal-footer]:!gap-2.5 [&_.ant-modal-footer_.ant-btn+_.ant-btn]:!ml-0 [&_.ant-modal-close]:!right-2.5 [&_.ant-modal-close]:!top-2.5 [&_.ant-modal-close]:!h-5 [&_.ant-modal-close]:!w-5 [&_.ant-modal-close]:!text-[#999] hover:[&_.ant-modal-close]:!text-[#666]";
  const modalTitleClassName = "text-[24px] font-medium leading-[22px] text-[#333]";
  const cancelButtonClassName =
    "!h-[37px] !w-[109px] !rounded-[24px] !border-0 !bg-[#f0f0f0] !p-0 !text-[16px] !font-medium !text-[#666] !shadow-none hover:!bg-[#e6e6e6] hover:!text-[#666]";
  const confirmButtonClassName =
    "!h-[37px] !w-[109px] !rounded-[24px] !border-0 !bg-[#5c3bc7] !p-0 !text-[16px] !font-medium !text-white !shadow-none hover:!bg-[#6b4bd4]";
  const deleteConfirmButtonClassName =
    "!h-[37px] !w-[109px] !rounded-[24px] !border-0 !bg-[#b7301e] !p-0 !text-[16px] !font-medium !text-white !shadow-none hover:!bg-[#a62b1b]";

  return (
    <>
      <Modal
        title={<span className={modalTitleClassName}>{t("home.renameProject")}</span>}
        open={renameOpen}
        closeIcon={<CloseIcon />}
        centered
        width={491}
        className={modalClassName}
        confirmLoading={isActionLoading}
        okText={t("home.confirm")}
        cancelText={t("home.cancelEsc")}
        okButtonProps={{
          className: confirmButtonClassName,
          disabled: !renameTitle.trim(),
        }}
        cancelButtonProps={{ className: cancelButtonClassName }}
        onOk={onConfirmRename}
        onCancel={onCancelRename}
        destroyOnHidden
      >
        <Form layout="vertical" preserve={false} className="!mt-[7px]">
          <Form.Item
            label={<span className="text-[14px] leading-[22px] text-[#666]">{t("home.projectName")}</span>}
            className="!mb-0"
          >
            <Input
              value={renameTitle}
              onChange={(event) => onRenameTitleChange(event.target.value)}
              placeholder={t("home.projectNamePlaceholder")}
              onPressEnter={onConfirmRename}
              autoFocus
              className="!h-[37px] !rounded-[9px] !border-[#e6e6e6] !text-[14px] !shadow-none hover:!border-[#d6ceef] focus:!border-[#5c3bc7]"
            />
          </Form.Item>
        </Form>
      </Modal>
      <Modal
        title={<span className={modalTitleClassName}>{t("home.confirmDelete")}</span>}
        open={deleteTitle !== null}
        closeIcon={<CloseIcon />}
        centered
        width={491}
        className={modalClassName}
        confirmLoading={isActionLoading}
        okText={t("home.confirm")}
        okButtonProps={{
          danger: true,
          className: deleteConfirmButtonClassName,
        }}
        cancelText={t("home.cancelEsc")}
        cancelButtonProps={{ className: cancelButtonClassName }}
        onOk={onConfirmDelete}
        onCancel={onCancelDelete}
        destroyOnHidden
      >
        <p className="m-0 text-[14px] leading-[22px] text-[#666]">
          {t("home.deleteCannotRecover")}
        </p>
      </Modal>
    </>
  );
}

function useProjectSectionState(pageSize: number, t: Translate, initialPage = 1) {
  const router = useRouter();
  const coverInputRef = useRef<HTMLInputElement>(null);
  const coverProjectIdRef = useRef<number | null>(null);
  const coverProgressTimerRef = useRef<number | null>(null);
  const [projects, setProjects] = useState<ProjectData[]>([]);
  const [page, setPage] = useState(initialPage);
  const [pageInfo, setPageInfo] = useState<CanvasWorkflowPageInfo>({
    ...DEFAULT_PROJECT_PAGE_INFO,
    page: initialPage,
    pageSize,
  });
  const [isLoadingProjects, setIsLoadingProjects] = useState(false);
  const [isCreating, setIsCreating] = useState(false);
  const [actionProjectId, setActionProjectId] = useState<number | null>(null);
  const [renamePayload, setRenamePayload] = useState<{
    id: number;
    title: string;
    desp: string;
    properties: string;
    coverUrl: string;
  } | null>(null);
  const [renameTitle, setRenameTitle] = useState("");
  const [coverProjectId, setCoverProjectId] = useState<number | null>(null);
  const [deletePayload, setDeletePayload] = useState<{
    id: number;
    title: string;
  } | null>(null);

  const stopCoverProgressTimer = useCallback(() => {
    if (coverProgressTimerRef.current) {
      window.clearInterval(coverProgressTimerRef.current);
      coverProgressTimerRef.current = null;
    }
  }, []);

  const setProjectCoverProgress = useCallback((id: number, progress?: number) => {
    setProjects((currentProjects) =>
      currentProjects.map((project) =>
        project.id === id ? { ...project, uploadProgress: progress } : project
      )
    );
  }, []);

  const startFakeCoverProgress = useCallback((id: number) => {
    stopCoverProgressTimer();
    setProjectCoverProgress(id, 1);
    coverProgressTimerRef.current = window.setInterval(() => {
      setProjects((currentProjects) =>
        currentProjects.map((project) => {
          if (project.id !== id || typeof project.uploadProgress !== "number") {
            return project;
          }
          const nextProgress = Math.min(
            90,
            project.uploadProgress + Math.max(1, Math.round((90 - project.uploadProgress) * 0.18))
          );
          return { ...project, uploadProgress: nextProgress };
        })
      );
    }, 300);
  }, [setProjectCoverProgress, stopCoverProgressTimer]);

  const finishCoverProgress = useCallback((id: number, coverUrl: string) => {
    stopCoverProgressTimer();
    setProjects((currentProjects) =>
      currentProjects.map((project) =>
        project.id === id
          ? { ...project, image: coverUrl, uploadProgress: 100 }
          : project
      )
    );
    window.setTimeout(() => setProjectCoverProgress(id, undefined), 450);
  }, [setProjectCoverProgress, stopCoverProgressTimer]);

  const loadProjects = useCallback(async (nextPage: number, options?: { append?: boolean }) => {
    setIsLoadingProjects(true);
    try {
      const data = await listCanvasWorkflows({ page: nextPage, pageSize });
      const nextProjects = data.list
        .filter((item) => !item.deleted)
        .map((item) => mapWorkflowToProject(item));
      setProjects((currentProjects) =>
        options?.append ? [...currentProjects, ...nextProjects] : nextProjects
      );
      setPageInfo(data.pageInfo);
    } catch {
      if (!options?.append) {
        setProjects([]);
      }
      setPageInfo({
        ...DEFAULT_PROJECT_PAGE_INFO,
        page: nextPage,
        pageSize,
      });
    } finally {
      setIsLoadingProjects(false);
    }
  }, [pageSize]);

  useEffect(() => {
    void loadProjects(page);
    return undefined;
  }, [loadProjects, page]);

  useEffect(() => {
    return () => {
      stopCoverProgressTimer();
    };
  }, [stopCoverProgressTimer]);

  const handleStartCreation = async () => {
    if (isCreating) {
      message.warning(t("home.createInProgress"));
      return;
    }

    setIsCreating(true);
    const title = t("home.projectFallback");
    try {
      const result = await createCanvasWorkflow({
        title,
        desp: "",
        properties: buildEmptyWorkflowProperties(title),
      });
      const workflowId = (result.data as any)?.id;
      router.push(workflowId ? `/canvas?workflowId=${workflowId}` : "/canvas");
      message.success(t("home.createSuccess"));
    } catch (error) {
      message.error(error instanceof Error ? error.message : t("home.createFailed"));
      setIsCreating(false);
    }
  };

  const buildFullUpdatePayload = async (id: number) => {
    const detail = await getCanvasWorkflowDetail(id);
    return {
      id,
      title: detail.title ?? "",
      desp: detail.desp ?? "",
      properties: detail.properties ?? "",
      coverUrl: detail.coverUrl ?? "",
    };
  };

  const handleProjectAction = async (id: number, action: ProjectActionKey) => {
    if (actionProjectId !== null) return;

    setActionProjectId(id);
    try {
      if (action === "rename") {
        const payload = await buildFullUpdatePayload(id);
        setRenamePayload(payload);
        setRenameTitle(payload.title);
        return;
      }

      if (action === "change-cover") {
        coverProjectIdRef.current = id;
        setCoverProjectId(id);
        coverInputRef.current?.click();
        return;
      }

      if (action === "duplicate") {
        const detail = await getCanvasWorkflowDetail(id);
        const title = detail.title
          ? `${detail.title}${t("home.copySuffix")}`
          : t("home.projectCopyFallback");
        await createCanvasWorkflow({
          title,
          desp: detail.desp ?? "",
          properties: detail.properties ?? "",
          coverUrl: detail.coverUrl ?? "",
        });
        message.success(t("home.copyCreated"));
        await loadProjects(page);

        // const workflowId = (result.data as any)?.id;
        // if (workflowId) {
        //   router.push(`/canvas?workflowId=${workflowId}`);
        // }
        return;
      }

      if (action === "delete") {
        const detail = await getCanvasWorkflowDetail(id);
        setDeletePayload({
          id,
          title: detail.title ?? detail.code ?? `#${id}`,
        });
      }
    } catch (error) {
      message.error(error instanceof Error ? error.message : t("home.actionFailed"));
    } finally {
      setActionProjectId(null);
    }
  };

  const closeRenameModal = () => {
    setRenamePayload(null);
    setRenameTitle("");
  };

  const confirmRenameProject = async () => {
    if (!renamePayload || actionProjectId !== null) return;

    setActionProjectId(renamePayload.id);
    try {
      await updateCanvasWorkflow({
        ...renamePayload,
        title: renameTitle,
      });
      message.success(t("home.renameSuccess"));
      setProjects((currentProjects) =>
        currentProjects.map((project) =>
          project.id === renamePayload.id
            ? { ...project, title: renameTitle.trim() || project.title }
            : project
        )
      );
      closeRenameModal();
    } catch (error) {
      message.error(error instanceof Error ? error.message : t("home.renameFailed"));
    } finally {
      setActionProjectId(null);
    }
  };

  const closeDeleteModal = () => {
    setDeletePayload(null);
  };

  const closeCoverModal = () => {
    coverProjectIdRef.current = null;
    setCoverProjectId(null);
  };

  const handleCoverFileChange = async (file: File | undefined) => {
    const selectedCoverProjectId = coverProjectIdRef.current ?? coverProjectId;
    if (!file || selectedCoverProjectId === null || actionProjectId !== null) return;
    if (!file.type.startsWith("image/")) {
      message.error(t("home.selectImageFile"));
      closeCoverModal();
      return;
    }

    setActionProjectId(selectedCoverProjectId);
    startFakeCoverProgress(selectedCoverProjectId);
    try {
      const coverPayload = await buildFullUpdatePayload(selectedCoverProjectId);
      const uploadedCoverUrl = await uploadCanvasWorkflowCover(file);
      await updateCanvasWorkflow({
        ...coverPayload,
        coverUrl: uploadedCoverUrl,
      });
      message.success(t("home.coverUpdated"));
      finishCoverProgress(selectedCoverProjectId, uploadedCoverUrl);
      closeCoverModal();
    } catch (error) {
      stopCoverProgressTimer();
      setProjectCoverProgress(selectedCoverProjectId, undefined);
      message.error(error instanceof Error ? error.message : t("home.coverUpdateFailed"));
    } finally {
      setActionProjectId(null);
      if (coverInputRef.current) {
        coverInputRef.current.value = "";
      }
    }
  };

  const confirmDeleteProject = async () => {
    if (!deletePayload || actionProjectId !== null) return;

    setActionProjectId(deletePayload.id);
    try {
      await deleteCanvasWorkflow(deletePayload.id);
      message.success(t("home.deleteSuccess"));
      closeDeleteModal();
      await loadProjects(page);
    } catch (error) {
      message.error(error instanceof Error ? error.message : t("home.deleteFailed"));
    } finally {
      setActionProjectId(null);
    }
  };

  return {
    projects,
    pageInfo,
    isLoadingProjects,
    isCreating,
    isActionLoading: actionProjectId !== null,
    renamePayload,
    renameTitle,
    setRenameTitle,
    closeRenameModal,
    confirmRenameProject,
    coverInputRef,
    closeCoverModal,
    handleCoverFileChange,
    deletePayload,
    closeDeleteModal,
    confirmDeleteProject,
    handleStartCreation,
    handleProjectAction,
    goPrevPage: () => setPage((current) => Math.max(1, current - 1)),
    goNextPage: () => setPage((current) => Math.min(pageInfo.pageCount, current + 1)),
  };
}

function useAllProjectsState(t: Translate) {
  const pageSize = 20;
  const router = useRouter();
  const coverInputRef = useRef<HTMLInputElement>(null);
  const coverProjectIdRef = useRef<number | null>(null);
  const coverProgressTimerRef = useRef<number | null>(null);
  const loadingMorePageRef = useRef<number | null>(null);
  const [projects, setProjects] = useState<ProjectData[]>([]);
  const [page, setPage] = useState(1);
  const [pageInfo, setPageInfo] = useState<CanvasWorkflowPageInfo>({
    ...DEFAULT_PROJECT_PAGE_INFO,
    page: 1,
    pageSize,
  });
  const [isLoadingProjects, setIsLoadingProjects] = useState(false);
  const [isCreating, setIsCreating] = useState(false);
  const [actionProjectId, setActionProjectId] = useState<number | null>(null);
  const [renamePayload, setRenamePayload] = useState<{
    id: number;
    title: string;
    desp: string;
    properties: string;
    coverUrl: string;
  } | null>(null);
  const [renameTitle, setRenameTitle] = useState("");
  const [coverProjectId, setCoverProjectId] = useState<number | null>(null);
  const [deletePayload, setDeletePayload] = useState<{
    id: number;
    title: string;
  } | null>(null);

  const stopCoverProgressTimer = useCallback(() => {
    if (coverProgressTimerRef.current) {
      window.clearInterval(coverProgressTimerRef.current);
      coverProgressTimerRef.current = null;
    }
  }, []);

  const setProjectCoverProgress = useCallback((id: number, progress?: number) => {
    setProjects((currentProjects) =>
      currentProjects.map((project) =>
        project.id === id ? { ...project, uploadProgress: progress } : project
      )
    );
  }, []);

  const startFakeCoverProgress = useCallback((id: number) => {
    stopCoverProgressTimer();
    setProjectCoverProgress(id, 1);
    coverProgressTimerRef.current = window.setInterval(() => {
      setProjects((currentProjects) =>
        currentProjects.map((project) => {
          if (project.id !== id || typeof project.uploadProgress !== "number") return project;
          const nextProgress = Math.min(
            90,
            project.uploadProgress + Math.max(1, Math.round((90 - project.uploadProgress) * 0.18))
          );
          return { ...project, uploadProgress: nextProgress };
        })
      );
    }, 300);
  }, [setProjectCoverProgress, stopCoverProgressTimer]);

  const finishCoverProgress = useCallback((id: number, coverUrl: string) => {
    stopCoverProgressTimer();
    setProjects((currentProjects) =>
      currentProjects.map((project) =>
        project.id === id ? { ...project, image: coverUrl, uploadProgress: 100 } : project
      )
    );
    window.setTimeout(() => setProjectCoverProgress(id, undefined), 450);
  }, [setProjectCoverProgress, stopCoverProgressTimer]);

  const loadProjectsPage = useCallback(async (
    nextPage: number,
    options?: { append?: boolean }
  ) => {
    setIsLoadingProjects(true);
    try {
      const data = await listCanvasWorkflows({ page: nextPage, pageSize });
      const nextProjects = data.list
        .filter((item) => !item.deleted)
        .map((item) => mapWorkflowToProject(item));
      setProjects((currentProjects) => {
        if (!options?.append) return nextProjects;
        const existingIds = new Set(currentProjects.map((project) => project.id));
        const uniqueNextProjects = nextProjects.filter((project) => !existingIds.has(project.id));
        return [...currentProjects, ...uniqueNextProjects];
      });
      setPageInfo(data.pageInfo);
      setPage(nextPage);
    } catch {
      if (!options?.append) {
        setProjects([]);
      }
      setPageInfo({
        ...DEFAULT_PROJECT_PAGE_INFO,
        page: nextPage,
        pageSize,
      });
    } finally {
      setIsLoadingProjects(false);
    }
  }, []);

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

  useEffect(() => {
    return () => {
      stopCoverProgressTimer();
    };
  }, [stopCoverProgressTimer]);

  const handleStartCreation = async () => {
    if (isCreating) {
      message.warning(t("home.createInProgress"));
      return;
    }

    setIsCreating(true);
    const title = t("home.projectFallback");
    try {
      const result = await createCanvasWorkflow({
        title,
        desp: "",
        properties: buildEmptyWorkflowProperties(title),
      });
      const workflowId = (result.data as any)?.id;
      router.push(workflowId ? `/canvas?workflowId=${workflowId}` : "/canvas");
      message.success(t("home.createSuccess"));
    } catch (error) {
      message.error(error instanceof Error ? error.message : t("home.createFailed"));
      setIsCreating(false);
    }
  };

  const buildFullUpdatePayload = async (id: number) => {
    const detail = await getCanvasWorkflowDetail(id);
    return {
      id,
      title: detail.title ?? "",
      desp: detail.desp ?? "",
      properties: detail.properties ?? "",
      coverUrl: detail.coverUrl ?? "",
    };
  };

  const handleProjectAction = async (id: number, action: ProjectActionKey) => {
    if (actionProjectId !== null) return;

    setActionProjectId(id);
    try {
      if (action === "rename") {
        const payload = await buildFullUpdatePayload(id);
        setRenamePayload(payload);
        setRenameTitle(payload.title);
        return;
      }

      if (action === "change-cover") {
        coverProjectIdRef.current = id;
        setCoverProjectId(id);
        coverInputRef.current?.click();
        return;
      }

      if (action === "duplicate") {
        const detail = await getCanvasWorkflowDetail(id);
        const title = detail.title
          ? `${detail.title}${t("home.copySuffix")}`
          : t("home.projectCopyFallback");
        await createCanvasWorkflow({
          title,
          desp: detail.desp ?? "",
          properties: detail.properties ?? "",
          coverUrl: detail.coverUrl ?? "",
        });
        message.success(t("home.copyCreated"));
        await loadProjectsPage(1);
        return;
      }

      if (action === "delete") {
        const detail = await getCanvasWorkflowDetail(id);
        setDeletePayload({
          id,
          title: detail.title ?? detail.code ?? `#${id}`,
        });
      }
    } catch (error) {
      message.error(error instanceof Error ? error.message : t("home.actionFailed"));
    } finally {
      setActionProjectId(null);
    }
  };

  const closeRenameModal = () => {
    setRenamePayload(null);
    setRenameTitle("");
  };

  const confirmRenameProject = async () => {
    if (!renamePayload || actionProjectId !== null) return;

    setActionProjectId(renamePayload.id);
    try {
      await updateCanvasWorkflow({
        ...renamePayload,
        title: renameTitle,
      });
      message.success(t("home.renameSuccess"));
      setProjects((currentProjects) =>
        currentProjects.map((project) =>
          project.id === renamePayload.id
            ? { ...project, title: renameTitle.trim() || project.title }
            : project
        )
      );
      closeRenameModal();
    } catch (error) {
      message.error(error instanceof Error ? error.message : t("home.renameFailed"));
    } finally {
      setActionProjectId(null);
    }
  };

  const closeDeleteModal = () => {
    setDeletePayload(null);
  };

  const closeCoverModal = () => {
    coverProjectIdRef.current = null;
    setCoverProjectId(null);
  };

  const handleCoverFileChange = async (file: File | undefined) => {
    const selectedCoverProjectId = coverProjectIdRef.current ?? coverProjectId;
    if (!file || selectedCoverProjectId === null || actionProjectId !== null) return;
    if (!file.type.startsWith("image/")) {
      message.error(t("home.selectImageFile"));
      closeCoverModal();
      return;
    }

    setActionProjectId(selectedCoverProjectId);
    startFakeCoverProgress(selectedCoverProjectId);
    try {
      const coverPayload = await buildFullUpdatePayload(selectedCoverProjectId);
      const uploadedCoverUrl = await uploadCanvasWorkflowCover(file);
      await updateCanvasWorkflow({
        ...coverPayload,
        coverUrl: uploadedCoverUrl,
      });
      message.success(t("home.coverUpdated"));
      finishCoverProgress(selectedCoverProjectId, uploadedCoverUrl);
      closeCoverModal();
    } catch (error) {
      stopCoverProgressTimer();
      setProjectCoverProgress(selectedCoverProjectId, undefined);
      message.error(error instanceof Error ? error.message : t("home.coverUpdateFailed"));
    } finally {
      setActionProjectId(null);
      if (coverInputRef.current) {
        coverInputRef.current.value = "";
      }
    }
  };

  const confirmDeleteProject = async () => {
    if (!deletePayload || actionProjectId !== null) return;

    setActionProjectId(deletePayload.id);
    try {
      await deleteCanvasWorkflow(deletePayload.id);
      message.success(t("home.deleteSuccess"));
      closeDeleteModal();
      await loadProjectsPage(1);
    } catch (error) {
      message.error(error instanceof Error ? error.message : t("home.deleteFailed"));
    } finally {
      setActionProjectId(null);
    }
  };

  const loadNextPage = useCallback(() => {
    const nextPage = page + 1;
    if (isLoadingProjects || nextPage > pageInfo.pageCount) return;
    if (loadingMorePageRef.current === nextPage) return;
    loadingMorePageRef.current = nextPage;
    void loadProjectsPage(nextPage, { append: true }).finally(() => {
      loadingMorePageRef.current = null;
    });
  }, [isLoadingProjects, loadProjectsPage, page, pageInfo.pageCount]);

  return {
    projects,
    pageInfo,
    isLoadingProjects,
    isCreating,
    isActionLoading: actionProjectId !== null,
    renamePayload,
    renameTitle,
    setRenameTitle,
    closeRenameModal,
    confirmRenameProject,
    coverInputRef,
    closeCoverModal,
    handleCoverFileChange,
    deletePayload,
    closeDeleteModal,
    confirmDeleteProject,
    handleStartCreation,
    handleProjectAction,
    loadNextPage,
  };
}

function RecentProjectsSection({
  className = "",
  onAllProjectsClick,
}: {
  className?: string;
  onAllProjectsClick: () => void;
}) {
  const { t } = useI18n();
  const {
    projects,
    pageInfo,
    isLoadingProjects,
    isCreating,
    isActionLoading,
    renamePayload,
    renameTitle,
    setRenameTitle,
    closeRenameModal,
    confirmRenameProject,
    coverInputRef,
    closeCoverModal,
    handleCoverFileChange,
    deletePayload,
    closeDeleteModal,
    confirmDeleteProject,
    handleStartCreation,
    handleProjectAction,
    goPrevPage,
    goNextPage,
  } = useProjectSectionState(4, t);

  return (
    <section className={`${className}`}>
      <div className="mb-5 flex items-center justify-between">
        <div className="flex items-center justify-center gap-x-1 overflow-hidden whitespace-nowrap">
          <h2 className="text-[20px] font-bold leading-none text-[#333]">
            {t("home.recentProjects")}
          </h2>
        </div>
        <button
          type="button"
          onClick={onAllProjectsClick}
          className="flex h-8 cursor-pointer items-center justify-center gap-1 rounded-[8px] px-2 text-[16px] leading-none !text-[#666] transition hover:bg-[#f0f0f0] hover:text-[#333]"
        >
          <span>{t("home.allProjects")}</span>
          <ArrowIcon />
        </button>
      </div>
      <ProjectSectionGrid
        projects={projects}
        isLoadingProjects={isLoadingProjects}
        isCreating={isCreating}
        t={t}
        showOverflowCue
        pageInfo={pageInfo}
        onPrevPage={goPrevPage}
        onNextPage={goNextPage}
        onStartCreation={handleStartCreation}
        onProjectAction={handleProjectAction}
      />
      <ProjectActionModals
        t={t}
        isActionLoading={isActionLoading}
        renameOpen={!!renamePayload}
        renameTitle={renameTitle}
        onRenameTitleChange={setRenameTitle}
        onCancelRename={closeRenameModal}
        onConfirmRename={confirmRenameProject}
        deleteTitle={deletePayload?.title ?? null}
        onCancelDelete={closeDeleteModal}
        onConfirmDelete={confirmDeleteProject}
      />
      <input
        ref={coverInputRef}
        type="file"
        accept="image/*"
        className="hidden"
        onChange={(event) => {
          const file = event.target.files?.[0];
          if (!file) {
            closeCoverModal();
            return;
          }
          void handleCoverFileChange(file);
        }}
      />
    </section>
  );
}

function AllProjectsSection({ onBackClick }: { onBackClick: () => void }) {
  const { t } = useI18n();
  const [stickyTop, setStickyTop] = useState(90);
  const {
    projects,
    pageInfo,
    isLoadingProjects,
    isCreating,
    isActionLoading,
    renamePayload,
    renameTitle,
    setRenameTitle,
    closeRenameModal,
    confirmRenameProject,
    coverInputRef,
    closeCoverModal,
    handleCoverFileChange,
    deletePayload,
    closeDeleteModal,
    confirmDeleteProject,
    handleStartCreation,
    handleProjectAction,
    loadNextPage,
  } = useAllProjectsState(t);
  const canLoadMoreProjects = pageInfo.page < pageInfo.pageCount;

  useEffect(() => {
    const updateStickyTop = () => {
      const header = document.querySelector("header");
      setStickyTop(header?.getBoundingClientRect().height ?? 0);
    };

    updateStickyTop();
    window.addEventListener("resize", updateStickyTop);
    return () => {
      window.removeEventListener("resize", updateStickyTop);
    };
  }, []);

  useEffect(() => {
    const handleScroll = () => {
      if (!canLoadMoreProjects || isLoadingProjects) return;
      const distanceToBottom =
        document.documentElement.scrollHeight - window.innerHeight - window.scrollY;
      if (distanceToBottom <= ALL_PROJECTS_LOAD_MORE_OFFSET) {
        loadNextPage();
      }
    };

    window.addEventListener("scroll", handleScroll, { passive: true });
    handleScroll();
    return () => {
      window.removeEventListener("scroll", handleScroll);
    };
  }, [canLoadMoreProjects, isLoadingProjects, loadNextPage]);

  return (
    <section>
      <div
        className="sticky z-20 -mx-5 mb-5 flex items-center justify-between border-b border-[#f0f0f0] bg-[#f9f9f9]/95 px-5 py-3 backdrop-blur"
        style={{ top: stickyTop }}
      >
        <div className="flex items-center justify-center gap-x-1 overflow-hidden whitespace-nowrap">
          <button
            type="button"
            onClick={onBackClick}
            className="flex h-8 items-center justify-center gap-1 rounded-[8px] px-2 text-[16px] leading-none text-[#666] transition hover:bg-[#f0f0f0] hover:text-[#333]"
          >
            <LeftOutlinedIcon />
            <span>{t("home.back")}</span>
          </button>
          <h2 className="text-[20px] font-bold leading-none text-[#333]">
            {t("home.allProjects")}
          </h2>
        </div>
      </div>
      <ProjectSectionGrid
        projects={projects}
        isLoadingProjects={isLoadingProjects}
        isCreating={isCreating}
        t={t}
        onStartCreation={handleStartCreation}
        onProjectAction={handleProjectAction}
      />
      <div className="flex h-14 items-center justify-center text-[13px] font-medium text-[#999]">
        {isLoadingProjects && projects.length > 0
          ? t("home.loading")
          : canLoadMoreProjects
            ? t("home.loadMorePull")
            : projects.length > 0
              ? t("home.noMoreProjects")
              : null}
      </div>
      <ProjectActionModals
        t={t}
        isActionLoading={isActionLoading}
        renameOpen={!!renamePayload}
        renameTitle={renameTitle}
        onRenameTitleChange={setRenameTitle}
        onCancelRename={closeRenameModal}
        onConfirmRename={confirmRenameProject}
        deleteTitle={deletePayload?.title ?? null}
        onCancelDelete={closeDeleteModal}
        onConfirmDelete={confirmDeleteProject}
      />
      <input
        ref={coverInputRef}
        type="file"
        accept="image/*"
        className="hidden"
        onChange={(event) => {
          const file = event.target.files?.[0];
          if (!file) {
            closeCoverModal();
            return;
          }
          void handleCoverFileChange(file);
        }}
      />
    </section>
  );
}


function mapTemplateToShow(item: CanvasTemplateItem, t: Translate): ShowData {
  return {
    id: item.id,
    title: item.name || '',
    subtitle: item.desp || '',
    image: item.coverUrl || '',
    avatar: item?.userInfo?.avatar || '',
    vip: item.type === 1,
    data: item.properties || '',
  };
}

function ShowsSection() {
  const { t } = useI18n();
  const [activeTab, setActiveTab] = useState(0);
  const [categoryList, setCategoryList] = useState<TemplateCategoryData[]>([
    { id: null, name: t("home.allCategory") },
  ]);
  const [dataList, setDataList] = useState<ShowData[]>([]);
  const [searchQuery, setSearchQuery] = useState("");
  const [submittedSearchQuery, setSubmittedSearchQuery] = useState("");
  const selectedCategoryId = categoryList[activeTab]?.id ?? null;
  const [previewShow, setPreviewShow] = useState<ShowData | null>(null);
  const [isCopyingShow, setIsCopyingShow] = useState(false);
  const [isLoadingShows, setIsLoadingShows] = useState(false);
  const [showsPage, setShowsPage] = useState(1);
  const [showsPageInfo, setShowsPageInfo] = useState<CanvasWorkflowPageInfo>({
    ...DEFAULT_PROJECT_PAGE_INFO,
    page: 1,
    pageSize: SHOWS_PAGE_SIZE,
  });
  const [stickyTop, setStickyTop] = useState(90);
  const loadingMoreShowsPageRef = useRef<number | null>(null);

  const router = useRouter();

  useEffect(() => {
    setCategoryList((currentCategories) =>
      currentCategories.map((category) =>
        category.id === null ? { ...category, name: t("home.allCategory") } : category
      )
    );
  }, [t]);

  useEffect(() => {
    let canceled = false;

    async function loadCategories() {
      try {
        const params = new URLSearchParams({ keyword: "" });
        const response = await authFetch(`/api/canvas-templates/categories?${params.toString()}`);
        if (!response.ok) return;

        const result = (await response.json()) as ListResponse<CanvasTemplateCategoryItem>;
        const list = result.data?.list;
        if (!Array.isArray(list)) return;

        const categories = list
          .filter((item) => !item.deleted)
          .sort((a, b) => a.sort - b.sort)
          .map((item) => ({ id: item.id, name: item.name }))
          .filter((item) => item.name);

        if (!canceled && categories.length > 0) {
          setCategoryList([{ id: null, name: t("home.allCategory") }, ...categories]);
        }
      } catch {
        // Keep fallback category.
      }
    }

    loadCategories();

    return () => {
      canceled = true;
    };
  }, []);

  useEffect(() => {
    const updateStickyTop = () => {
      const header = document.querySelector("header");
      setStickyTop(header?.getBoundingClientRect().height ?? 0);
    };

    updateStickyTop();
    window.addEventListener("resize", updateStickyTop);
    return () => {
      window.removeEventListener("resize", updateStickyTop);
    };
  }, []);

  const loadShowsPage = useCallback(async (
    nextPage: number,
    options?: { append?: boolean; signal?: AbortSignal }
  ) => {
    setIsLoadingShows(true);
    try {
      const params = new URLSearchParams({
        keyword: submittedSearchQuery,
        categoryId: selectedCategoryId ? String(selectedCategoryId) : "",
        type: "",
        userId: "",
        page: String(nextPage),
        pageSize: String(SHOWS_PAGE_SIZE),
      });
      const response = await authFetch(`/api/canvas-templates?${params.toString()}`, {
        signal: options?.signal,
      });
      if (!response.ok) {
        if (!options?.append) {
          setDataList([]);
        }
        return;
      }

      const result = (await response.json()) as ListResponse<CanvasTemplateItem>;
      const list = result.data?.list;
      if (!Array.isArray(list)) {
        if (!options?.append) {
          setDataList([]);
        }
        return;
      }

      const nextShows = list
        .filter((item) => !item.deleted)
        .map((item) => mapTemplateToShow(item, t));
      setDataList((currentShows) => {
        if (!options?.append) return nextShows;
        const existingIds = new Set(currentShows.map((show) => show.id));
        return [...currentShows, ...nextShows.filter((show) => !existingIds.has(show.id))];
      });
      setShowsPageInfo(
        result.data?.pageInfo ?? {
          page: nextPage,
          pageSize: SHOWS_PAGE_SIZE,
          pageCount: nextShows.length < SHOWS_PAGE_SIZE ? nextPage : nextPage + 1,
          total: nextShows.length,
        }
      );
      setShowsPage(nextPage);
    } catch {
      if (!options?.signal?.aborted && !options?.append) {
        setDataList([]);
      }
    } finally {
      if (!options?.signal?.aborted) {
        setIsLoadingShows(false);
      }
    }
  }, [submittedSearchQuery, selectedCategoryId, t]);

  useEffect(() => {
    const controller = new AbortController();
    setShowsPage(1);
    setShowsPageInfo({
      ...DEFAULT_PROJECT_PAGE_INFO,
      page: 1,
      pageSize: SHOWS_PAGE_SIZE,
    });
    void loadShowsPage(1, { signal: controller.signal });

    return () => {
      controller.abort();
      loadingMoreShowsPageRef.current = null;
    };
  }, [loadShowsPage]);

  const canLoadMoreShows = showsPage < showsPageInfo.pageCount;

  const loadNextShowsPage = useCallback(() => {
    const nextPage = showsPage + 1;
    if (isLoadingShows || nextPage > showsPageInfo.pageCount) return;
    if (loadingMoreShowsPageRef.current === nextPage) return;
    loadingMoreShowsPageRef.current = nextPage;
    void loadShowsPage(nextPage, { append: true }).finally(() => {
      loadingMoreShowsPageRef.current = null;
    });
  }, [isLoadingShows, loadShowsPage, showsPage, showsPageInfo.pageCount]);

  const handleSubmitSearch = useCallback(() => {
    setSubmittedSearchQuery(searchQuery.trim());
  }, [searchQuery]);

  const handleClearSearch = useCallback(() => {
    setSearchQuery("");
    setSubmittedSearchQuery("");
  }, []);

  useEffect(() => {
    const handleScroll = () => {
      if (!canLoadMoreShows || isLoadingShows) return;
      const distanceToBottom =
        document.documentElement.scrollHeight - window.innerHeight - window.scrollY;
      if (distanceToBottom <= SHOWS_LOAD_MORE_OFFSET) {
        loadNextShowsPage();
      }
    };

    window.addEventListener("scroll", handleScroll, { passive: true });
    handleScroll();
    return () => {
      window.removeEventListener("scroll", handleScroll);
    };
  }, [canLoadMoreShows, isLoadingShows, loadNextShowsPage]);

  const handleCopyShow = useCallback(async (data: CanvasTemplatePreviewData) => {
    if (isCopyingShow) return;
    setIsCopyingShow(true);
    const title = data.title || t("home.projectFallback");
    try {
      const result = await createCanvasWorkflow({
        title,
        desp: data.subtitle || "",
        properties: data.data || buildEmptyWorkflowProperties(title),
        coverUrl: data.image  || "",
      });
      const workflowId = (result.data as any)?.id;
      router.push(workflowId ? `/canvas?workflowId=${workflowId}` : "/canvas");
    } catch (error) {
      message.error(error instanceof Error ? error.message : t("home.createFailed"));
      setIsCopyingShow(false);
    }
  }, [isCopyingShow, router, t]);

  return (
    <section className="mt-[64px]">
      <div
        className="sticky z-20 -mx-5 mb-5 flex flex-col gap-4 border-b border-[#f0f0f0] bg-[#f9f9f9]/95 px-5 py-3 backdrop-blur lg:flex-row lg:items-end lg:justify-between"
        style={{ top: stickyTop }}
      >
        <div>
          <h2 className="text-[20px] font-bold leading-none text-[#333]">
            {t("home.tvShow")}
          </h2>
          <div className="mt-5 flex flex-wrap items-center gap-1 text-[16px]">
            {categoryList.map((tab, index) => (
              <button
                key={`${tab.id ?? "all"}-${tab.name}`}
                type="button"
                onClick={() => setActiveTab(index)}
                className={
                  index === activeTab
                    ? "min-w-[54px] rounded-[9px] bg-[#f0f0f0] px-[15px] py-[5px] text-center text-[#333] transition hover:bg-[#f0f0f0]"
                    : "min-w-[54px] rounded-[9px] bg-[#f9f9f9] px-[15px] py-[5px] text-center text-[#666] transition hover:bg-[#f0f0f0] hover:text-[#333]"
                }
              >
                {tab.name}
              </button>
            ))}
          </div>
        </div>
        <div className="flex h-[35px] w-full items-center justify-between rounded-full border border-transparent bg-white px-[15px] text-[#999] shadow-[0_2px_5px_rgba(0,0,0,0.1)] transition focus-within:border-[#5c3bc7] lg:w-[295px]">
          <input
            value={searchQuery}
            onChange={(e) => setSearchQuery(e.target.value)}
            onKeyDown={(event) => {
              if (event.key === "Enter") {
                handleSubmitSearch();
              }
            }}
            placeholder={t("home.searchPlaceholder")}
            className="min-w-0 flex-1 bg-transparent text-[14px] outline-none placeholder:text-[#999]"
          />
          {searchQuery ? (
            <button
              type="button"
              onClick={handleClearSearch}
              aria-label={t("common.clear")}
              title={t("common.clear")}
              className="mr-1 grid h-7 w-7 shrink-0 place-items-center rounded-full text-[#999] transition hover:bg-[#f0f0f0] hover:text-[#666]"
            >
              <CloseIcon />
            </button>
          ) : null}
          <button
            type="button"
            onClick={handleSubmitSearch}
            aria-label={t("home.searchPlaceholder")}
            title={t("home.searchPlaceholder")}
            className="grid h-7 w-7 shrink-0 place-items-center rounded-full text-[#999] transition hover:bg-[#f0f0f0] hover:text-[#5c3bc7]"
          >
            <SearchIcon />
          </button>
        </div>
      </div>
      <div className="grid gap-5 md:grid-cols-2 xl:grid-cols-4">
        {dataList.map((show) => (
          <ShowCard key={show.id} {...show} onOpen={setPreviewShow} />
        ))}
      </div>
      <div className="flex h-14 items-center justify-center text-[13px] font-medium text-[#999]">
        {isLoadingShows && dataList.length > 0
          ? t("home.loading")
          : canLoadMoreShows
            ? t("home.loadMorePullUp")
            : dataList.length > 0
              ? t("home.noMoreContent")
              : isLoadingShows
                ? t("home.loading")
                : null}
      </div>
      <CanvasTemplatePreviewModal
        open={previewShow !== null}
        template={previewShow}
        copying={isCopyingShow}
        onClose={() => setPreviewShow(null)}
        onCopy={handleCopyShow}
      />
    </section>
  );
}

export function HomeProjectsContent({
  heroSection,
}: HomeProjectsContentProps) {
  const [isShowAll, setIsShowAll] = useState(false);

  return (
    <div className="mx-auto w-full max-w-[1456px] px-5 pt-[30px]">
      {isShowAll ? (
        <AllProjectsSection onBackClick={() => setIsShowAll(false)} />
      ) : (
        <>
          {heroSection}

          <RecentProjectsSection
            className="mt-[64px]"
            onAllProjectsClick={() => setIsShowAll(true)}
          />

          <ShowsSection />
        </>
      )}
    </div>
  );
}
