import { useEffect, useLayoutEffect, useRef, useState } from "react";
import { threadTitle } from "../../thread-library.js";
import { PullToRefreshIndicator } from "../../shared/PullToRefreshIndicator.jsx";
import { usePullToRefresh } from "../../shared/usePullToRefresh.js";
import { useBackLayer } from "../../app/useBackLayer.js";
import { useExitTransition } from "../../app/useExitTransition.js";
import { useI18n } from "../../shared/I18nProvider.jsx";
import { ArchiveIcon, BackIcon, ChatClassicViewIcon, ChatGroupedViewIcon, FolderClosedIcon, FolderOpenIcon, HideIcon, NewChatIcon, PinIcon, RenameIcon, TrashIcon } from "../../shared/ActionIcons.jsx";
import { chatRowStatus } from "./chat-row-status.js";
import { readChatViewPreference, writeChatViewPreference } from "./chat-view-preference.js";
import { buildProjectGroups, formatThreadAge, nextProjectThreadLimit, projectlessThreads, recentThreads, shouldShowChatLoadMore, visibleProjectThreads } from "./chats-projects.js";
import { VirtualThreadRows } from "./VirtualThreadRows.jsx";

export function ChatsPanel({ active = true, threads, projectThreads, hiddenProjects = [], workspaces, loading, error, nextCursor, searchQuery = "", onSearchQuery, archived = false, onArchivedChange, activeThreadId, activeOwnerId, sessions = [], currentSession, notifications = [], canCreate, createBlockedReason = "", setupPrompt = "", onOpen, onArchive, onDelete, onRename, onPin, onHideProject, onLoadMore, onRetry, onRefresh, onNewChat, onProjectChange, onCreateProjectChat, onCreateEmptyProjectChat }) {
  const { language, t } = useI18n();
  const [selectedProject, setSelectedProject] = useState("");
  const [projectMessage, setProjectMessage] = useState("");
  const [projectMessagePending, setProjectMessagePending] = useState(false);
  const [projectMessageError, setProjectMessageError] = useState("");
  const [groupedView, setGroupedView] = useState(() => readChatViewPreference(globalThis.localStorage) === "grouped");
  const [projectRowLimits, setProjectRowLimits] = useState({});
  const [collapsedProjects, setCollapsedProjects] = useState({});
  const [menu, setMenu] = useState(null);
  const [deleteTarget, setDeleteTarget] = useState(null);
  const menuRef = useRef(null);
  const pressTimerRef = useRef(null);
  const pressOriginRef = useRef(null);
  const suppressClickRef = useRef(false);
  const threadListRef = useRef(null);
  const projects = buildProjectGroups(projectThreads ?? threads, workspaces, hiddenProjects);
  const groupedProjects = projects.map((project) => ({ ...project, threads: project.threads.filter((thread) => !thread.pinned) }));
  const activeProject = projects.find((project) => project.key === selectedProject);
  const pinned = archived ? [] : threads.filter((thread) => thread.pinned);
  const recent = archived ? threads : groupedView ? projectlessThreads(threads).filter((thread) => !thread.pinned) : recentThreads(threads).filter((thread) => !thread.pinned);
  const searching = Boolean(searchQuery.trim());
  const initialArchiveLoading = archived && loading && threads.length === 0;
  const { pull, pullHandlers } = usePullToRefresh({ direction: "down", onRefresh, mouse: false });
  const menuMotion = useExitTransition(() => setMenu(null), 180);
  const closeMenu = useBackLayer(Boolean(menu), menuMotion.startExit, "chat-menu");
  const closeProject = useBackLayer(Boolean(activeProject) && !searching && !archived, () => setSelectedProject(""), "project-chats");
  const closeArchive = useBackLayer(Boolean(archived) && !searching, () => onArchivedChange?.(false), "archived-chats");
  const deleteMotion = useExitTransition(() => setDeleteTarget(null), 220);
  const closeDeleteDialog = useBackLayer(Boolean(deleteTarget), deleteMotion.startExit, "delete-chat");

  useEffect(() => {
    if (!menu) return undefined;
    const closeOutside = (event) => {
      if (!menuRef.current?.contains(event.target)) closeMenu();
    };
    document.addEventListener("pointerdown", closeOutside);
    return () => document.removeEventListener("pointerdown", closeOutside);
  }, [closeMenu, menu]);

  useEffect(() => () => clearTimeout(pressTimerRef.current), []);

  useLayoutEffect(() => {
    if (!menuRef.current || !menu) return;
    const { height: menuHeight, width: menuWidth } = menuRef.current.getBoundingClientRect();
    const maxY = Math.max(12, window.innerHeight - menuHeight - 12);
    const y = Math.max(12, Math.min(maxY, menu.y));
    const x = menu.kind === "project"
      ? Math.max(12, Math.min(window.innerWidth - menuWidth - 12, menu.anchorRight - menuWidth))
      : undefined;
    if (y !== menu.y || x !== menu.x) setMenu((current) => current?.y === menu.y && current?.x === menu.x ? { ...current, y, x } : current);
  }, [menu]);

  function openMenu(target, anchorY, kind = "thread", anchorRight) {
    setMenu({ kind, [kind]: target, y: Math.max(12, anchorY), anchorRight });
  }

  function startLongPress(event, target, kind = "thread") {
    if (event.pointerType === "mouse") return;
    clearTimeout(pressTimerRef.current);
    const { clientX, clientY } = event;
    const anchorRect = event.currentTarget.getBoundingClientRect();
    const anchorY = kind === "project" ? anchorRect.bottom + 6 : clientY;
    const anchorRight = kind === "project" ? anchorRect.right : undefined;
    pressOriginRef.current = { clientX, clientY };
    pressTimerRef.current = setTimeout(() => {
      suppressClickRef.current = true;
      openMenu(target, anchorY, kind, anchorRight);
    }, 500);
  }

  function cancelLongPress() {
    clearTimeout(pressTimerRef.current);
    pressOriginRef.current = null;
  }

  function cancelMovedLongPress(event) {
    const origin = pressOriginRef.current;
    if (!origin) return;
    if (Math.hypot(event.clientX - origin.clientX, event.clientY - origin.clientY) > 8) cancelLongPress();
  }

  function confirmDelete() {
    if (!deleteTarget) return;
    const target = deleteTarget;
    deleteMotion.startExit();
    void onDelete(target);
  }

  async function submitProjectMessage(event) {
    event.preventDefault();
    if (!activeProject?.workspaceId || projectMessagePending) return;
    setProjectMessagePending(true);
    setProjectMessageError("");
    try {
      if (projectMessage.trim()) await onCreateProjectChat(activeProject.workspaceId, projectMessage);
      else await onCreateEmptyProjectChat(activeProject.workspaceId);
      setProjectMessage("");
    } catch (submitError) {
      setProjectMessageError(submitError.message);
    } finally {
      setProjectMessagePending(false);
    }
  }

  function showMoreProjectThreads(projectKey, total) {
    setProjectRowLimits((current) => ({
      ...current,
      [projectKey]: nextProjectThreadLimit(current[projectKey], total)
    }));
  }

  function toggleProject(projectKey) {
    setProjectRowLimits((current) => ({ ...current, [projectKey]: undefined }));
    setCollapsedProjects((current) => ({
      ...current,
      [projectKey]: !current[projectKey]
    }));
  }

  function toggleGroupedView() {
    const nextGroupedView = !groupedView;
    setGroupedView(nextGroupedView);
    setSelectedProject("");
    writeChatViewPreference(globalThis.localStorage, nextGroupedView ? "grouped" : "classic");
  }

  function renderThreadRow(item, projectWorkspaceId = "") {
    const status = chatRowStatus(item, sessions, notifications, currentSession);
    const statusClass = {
      notification: "thread-status-dot--notification",
      active: "thread-status-dot--active",
      idle: "thread-status-dot--idle"
    }[status];
    const row = <button className={activeThreadId === item.id && activeOwnerId === item.ownerId ? "thread-row active" : "thread-row"} data-appearance="plain"
      onPointerDown={(event) => startLongPress(event, item)} onPointerUp={cancelLongPress} onPointerCancel={cancelLongPress} onPointerMove={cancelMovedLongPress}
      onContextMenu={(event) => { event.preventDefault(); cancelLongPress(); openMenu(item, event.clientY); }}
      onClick={() => { if (suppressClickRef.current) { suppressClickRef.current = false; return; } onOpen({ ...item, workspaceId: item.workspaceId || projectWorkspaceId }); }}>
        <span className="thread-title">{threadTitle(item)}</span>
        <span className={`thread-status-dot ${statusClass}`} aria-hidden="true"></span>
        <time>{formatThreadAge(item.updatedAt, Date.now(), language)}</time>
      </button>;
    return <div className={archived ? "thread-row-shell archived" : "thread-row-shell"} key={`${item.ownerId}:${item.id}`}>
      {row}
      {archived && <button type="button" className="archived-chat-delete" aria-label={`${t("chats.delete")}: ${threadTitle(item)}`} onClick={() => setDeleteTarget(item)}>
        <TrashIcon className="archived-chat-delete-icon" />
      </button>}
    </div>;
  }

  const rows = (items, projectWorkspaceId = "") => <VirtualThreadRows
    items={items}
    scrollRootRef={threadListRef}
    itemKey={(item) => `${item.ownerId}:${item.id}`}
    renderItem={(item) => renderThreadRow(item, projectWorkspaceId)}
  />;

  return <section className={`panel chats-panel${active ? "" : " chats-panel--background"}`} aria-hidden={!active} inert={!active}><PullToRefreshIndicator pull={pull} direction="down" />{(activeProject || archived) && !searching && <button type="button" className="screen-back conversation-back" aria-label={archived ? t("chats.backToChats") : t("chats.backToProjects")} onClick={archived ? closeArchive : closeProject}><BackIcon /></button>}<div className="thread-list" ref={threadListRef} {...pullHandlers}>
    {!searching && !activeProject && !archived && <button type="button" className="chat-view-toggle" data-appearance="plain" aria-label={groupedView ? t("chats.showClassicView") : t("chats.showGroupedView")} title={groupedView ? t("chats.showClassicView") : t("chats.showGroupedView")} aria-pressed={groupedView} onClick={toggleGroupedView}>
      {groupedView ? <ChatGroupedViewIcon className="chat-view-toggle-icon" /> : <ChatClassicViewIcon className="chat-view-toggle-icon" />}
    </button>}
    {!searching && !activeProject && !archived && pinned.length > 0 && <section className="thread-section pinned-threads chat-list-top-section"><h2>{t("chats.pinned")}</h2><div className="thread-section-list">{rows(pinned)}</div></section>}
    {!searching && !activeProject && !archived && <section className={`projects-section${pinned.length > 0 ? "" : " chat-list-top-section"}`}><header className="projects-heading"><h2>{t("chats.projects")}</h2></header><div className={groupedView ? "project-list project-list--grouped" : "project-list project-list--classic"}>
      {!groupedView && projects.map((project) => <button type="button" className="project-card" key={project.key}
        onPointerDown={(event) => startLongPress(event, project, "project")} onPointerUp={cancelLongPress} onPointerCancel={cancelLongPress} onPointerMove={cancelMovedLongPress}
        onContextMenu={(event) => { event.preventDefault(); cancelLongPress(); const anchorRect = event.currentTarget.getBoundingClientRect(); openMenu(project, anchorRect.bottom + 6, "project", anchorRect.right); }}
        onClick={() => { if (suppressClickRef.current) { suppressClickRef.current = false; return; } setSelectedProject(project.key); if (project.workspaceId) onProjectChange(project.workspaceId); }}>
        <span>{project.label}</span><small>{project.threads.length}</small>
      </button>)}
      {groupedView && groupedProjects.map((project) => <section className="thread-section project-thread-preview" key={project.key}>
        <button type="button" className="project-button" data-appearance="plain" aria-expanded={!collapsedProjects[project.key]}
          aria-label={`${project.label}: ${collapsedProjects[project.key] ? t("chats.expandProject") : t("chats.collapseProject")}`}
          onPointerDown={(event) => startLongPress(event, project, "project")} onPointerUp={cancelLongPress} onPointerCancel={cancelLongPress} onPointerMove={cancelMovedLongPress}
          onContextMenu={(event) => { event.preventDefault(); cancelLongPress(); const anchorRect = event.currentTarget.getBoundingClientRect(); openMenu(project, anchorRect.bottom + 6, "project", anchorRect.right); }}
          onClick={() => { if (suppressClickRef.current) { suppressClickRef.current = false; return; } toggleProject(project.key); }}>
          {collapsedProjects[project.key] ? <FolderClosedIcon className="project-folder-icon" /> : <FolderOpenIcon className="project-folder-icon" />}<h3>{project.label}</h3>
        </button>
        {!collapsedProjects[project.key] && <>
          <div className="thread-section-list">{rows(visibleProjectThreads(project.threads, projectRowLimits[project.key]), project.workspaceId)}</div>
          {project.threads.length > visibleProjectThreads(project.threads, projectRowLimits[project.key]).length && <button type="button" className="project-load-more" data-appearance="plain" aria-label={`${t("chats.loadMore")}: ${project.label}`} onClick={() => showMoreProjectThreads(project.key, project.threads.length)}>{t("chats.loadMore")}</button>}
        </>}
      </section>)}
    </div></section>}
    {!searching && activeProject && !archived && <section className="thread-section project-threads"><header className="project-chat-header"><h2>{activeProject.label}</h2></header><div className="thread-section-list">
      {activeProject.threads.length > 0 ? rows(activeProject.threads, activeProject.workspaceId) : <p className="thread-state">{t("chats.noProjectChats")}</p>}
    </div></section>}
    {!searching && !activeProject && <section className="thread-section recent-threads">{archived ? <header className="project-chat-header"><h2>{t("chats.archived")}</h2></header> : <h2>{t("chats.recent")}</h2>}<div className="thread-section-list">
      {initialArchiveLoading ? <div className="archive-loading" role="status" aria-busy="true" aria-label={t("chats.loading")}><span className="chat-transition-spinner" aria-hidden="true"></span></div> : rows(recent)}
    </div></section>}
    {searching && <section className="thread-section search-results"><h2>{t("chats.searchResults")}</h2><div className="thread-section-list">{rows(threads)}</div></section>}
    {loading && !initialArchiveLoading && <p className="thread-state">{t("chats.loading")}</p>}
    {error && <p className="thread-state error">{error} <button onClick={onRetry}>{t("chats.retry")}</button></p>}
    {!loading && !error && threads.length === 0 && <p>{searching ? t("chats.noMatches") : archived ? t("chats.noArchived") : t("chats.empty")}</p>}
    {shouldShowChatLoadMore(nextCursor, activeProject) && <button className="load-more" onClick={onLoadMore} disabled={loading}>{t("chats.loadMore")}</button>}
  </div>{menu && <div ref={menuRef} className={`chat-context-menu${menuMotion.exiting ? " chat-context-menu--exit" : ""}`} role="menu" style={menu.kind === "project" ? { top: menu.y, left: menu.x, right: "auto" } : { top: menu.y }}>
    {menu.kind === "project" ? <button type="button" role="menuitem" onClick={() => { const project = menu.project; closeMenu(); void onHideProject(project); }}><HideIcon className="chat-context-menu-icon" />{t("chats.hideProject")}</button> : <>
      {!archived && <button type="button" role="menuitem" onClick={() => { const thread = menu.thread; closeMenu(); onPin(thread); }}><PinIcon pinned={menu.thread.pinned} className="chat-context-menu-icon" />{menu.thread.pinned ? t("chats.unpin") : t("chats.pin")}</button>}
      {!archived && <button type="button" role="menuitem" onClick={() => { const thread = menu.thread; closeMenu(); const name = window.prompt(t("chats.renamePrompt"), thread.name || thread.preview || ""); if (name?.trim()) onRename(thread, name); }}><RenameIcon className="chat-context-menu-icon" />{t("chats.rename")}</button>}
      {!archived && <button type="button" role="menuitem" onClick={() => { const thread = menu.thread; closeMenu(); onArchive(thread); }}><ArchiveIcon className="chat-context-menu-icon" />{t("chats.archive")}</button>}
      {archived && <button type="button" role="menuitem" className="danger-menuitem" onClick={() => { const thread = menu.thread; closeMenu(); setDeleteTarget(thread); }}><TrashIcon className="chat-context-menu-icon" />{t("chats.delete")}</button>}
    </>}
  </div>}{deleteTarget && <div className={`chat-confirm-backdrop${deleteMotion.exiting ? " chat-confirm-backdrop--exit" : ""}`} onPointerDown={(event) => { if (event.target === event.currentTarget) closeDeleteDialog(); }}>
    <section className={`chat-confirm-dialog${deleteMotion.exiting ? " chat-confirm-dialog--exit" : ""}`} role="dialog" aria-modal="true" aria-labelledby="chat-delete-title" aria-describedby="chat-delete-description">
      <h2 id="chat-delete-title">{t("chats.deleteTitle")}</h2>
      <strong className="chat-confirm-thread">{threadTitle(deleteTarget)}</strong>
      <p id="chat-delete-description">{t("chats.deleteConfirm")}</p>
      <div className="chat-confirm-actions">
        <button type="button" className="chat-confirm-cancel" autoFocus onClick={() => closeDeleteDialog()}>{t("chats.cancel")}</button>
        <button type="button" className="chat-confirm-delete" onClick={() => confirmDelete()}>{t("chats.delete")}</button>
      </div>
    </section>
  </div>}{activeProject && !searching && !archived ? <form className="project-chat-composer" onSubmit={submitProjectMessage}>
    <input className="chat-search-input" value={projectMessage} onChange={(event) => setProjectMessage(event.target.value)} placeholder={t("chats.messageProject")} aria-label={t("chats.newChatMessage")} disabled={projectMessagePending} />
    <button type="submit" className="new-chat-fab" aria-label={t("chats.sendCreate")} title={createBlockedReason || setupPrompt || t("chats.sendCreate")} disabled={!canCreate || !activeProject.workspaceId || projectMessagePending}>
      <NewChatIcon />
    </button>
    {projectMessageError && <p className="project-chat-error" role="alert">{projectMessageError}</p>}
  </form> : <div className={archived ? "chat-search-bar archived" : "chat-search-bar"}>
    <input className="chat-search-input" type="search" value={searchQuery} onChange={(event) => onSearchQuery(event.target.value)} placeholder={t("chats.search")} aria-label={t("chats.search")} />
    {!archived && <button type="button" className="new-chat-fab" aria-label={t("chats.new")} title={createBlockedReason || setupPrompt || t("chats.new")} onClick={onNewChat} disabled={!canCreate}>
      <NewChatIcon />
    </button>}
  </div>}</section>;
}
