import { useEffect, useMemo, useRef, useState } from "react";
import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, Home, Mail, Paperclip, RefreshCw, Search, X } from "lucide-react";
import {
  Button,
  DismissibleAlert,
  ExplorerTree,
  LoadingIndicator,
  MessageDisplayPanel,
  formatDateTime,
  i18nMessage,
  type ApiSettings
} from "@govoplan/core-webui";
import {
  getMailboxMessage,
  listMailboxFolders,
  listMailboxMessages,
  listMailServerProfiles,
  type MailImapFolderResponse,
  type MailMailboxMessageDetail,
  type MailMailboxMessageSummary,
  type MailServerProfile } from
"../../api/mail";
import { buildMailboxFolderTree, findFolderNodeId, folderAncestorIds, type MailFolderNode } from "./mailboxFolders";

export default function MailboxPage({ settings }: {settings: ApiSettings;}) {
  const [profiles, setProfiles] = useState<MailServerProfile[]>([]);
  const [selectedProfileId, setSelectedProfileId] = useState("");
  const [folders, setFolders] = useState<MailImapFolderResponse[]>([]);
  const [selectedFolder, setSelectedFolder] = useState("INBOX");
  const [foldersLoadedForProfile, setFoldersLoadedForProfile] = useState("");
  const [expandedFolders, setExpandedFolders] = useState<Set<string>>(() => new Set());
  const [messages, setMessages] = useState<MailMailboxMessageSummary[]>([]);
  const [messageTotalCount, setMessageTotalCount] = useState<number | null>(null);
  const [messagePage, setMessagePage] = useState(1);
  const [messagePageSize, setMessagePageSize] = useState(10);
  const [messageQuery, setMessageQuery] = useState("");
  const [selectedMessage, setSelectedMessage] = useState<MailMailboxMessageDetail | null>(null);
  const [selectedMessageKeyState, setSelectedMessageKeyState] = useState("");
  const [pendingMessageKey, setPendingMessageKey] = useState("");
  const [loadingProfiles, setLoadingProfiles] = useState(true);
  const [loadingFolders, setLoadingFolders] = useState(false);
  const [loadingMessages, setLoadingMessages] = useState(false);
  const [loadingMessage, setLoadingMessage] = useState(false);
  const [error, setError] = useState("");
  const [folderError, setFolderError] = useState("");
  const [messageError, setMessageError] = useState("");
  const [detailError, setDetailError] = useState("");
  const selectedMessageKeyRef = useRef("");
  const folderRequestRef = useRef(0);
  const messageListRequestRef = useRef(0);
  const messageDetailRequestRef = useRef(0);
  const mailboxPageCursorsRef = useRef<Record<string, string | null>>({});

  const selectedProfile = profiles.find((profile) => profile.id === selectedProfileId) ?? null;
  const imapProfiles = useMemo(() => profiles.filter((profile) => profile.is_active && profile.imap), [profiles]);
  const folderTree = useMemo(() => buildMailboxFolderTree(folders), [folders]);
  const selectedFolderNodeId = useMemo(() => findFolderNodeId(folderTree, selectedFolder) ?? "", [folderTree, selectedFolder]);
  const filteredMessages = useMemo(() => filterMessages(messages, messageQuery), [messageQuery, messages]);
  const messagePageCount = Math.max(1, Math.ceil((messageTotalCount ?? 0) / messagePageSize));
  const shellBusy = loadingProfiles || loadingFolders || loadingMessages;
  const noImapProfiles = !loadingProfiles && imapProfiles.length === 0;
  const foldersReady = Boolean(selectedProfileId) && foldersLoadedForProfile === selectedProfileId;
  const selectedMessageKey = pendingMessageKey || selectedMessageKeyState || (selectedMessage ? mailboxMessageKey(selectedMessage.folder || selectedFolder, selectedMessage.uid) : "");
  const messageCountLabel = messageListCountLabel(messages.length, messageTotalCount, loadingMessages, foldersReady);
  const folderEmptyText = folderError || (noImapProfiles ? "i18n:govoplan-mail.no_imap_enabled_mail_profiles.61ae44d8" : loadingFolders ? "i18n:govoplan-mail.loading_folders.17f9f0e2" : "i18n:govoplan-mail.no_folders_available.14133b26");
  const messageEmptyText = messageError || (!selectedProfileId ? "i18n:govoplan-mail.select_an_imap_profile.5445648c" : !foldersReady || loadingMessages ? "i18n:govoplan-mail.loading_messages.77b62232" : messages.length > 0 && filteredMessages.length === 0 ? "i18n:govoplan-mail.no_messages_match_the_current_filter_on_this_pag.9dda6916" : "i18n:govoplan-mail.no_messages_in_this_folder.5c7fa25d");
  const previewEmptyText = detailError || (loadingMessage ? "i18n:govoplan-mail.loading_message.815c2094" : "i18n:govoplan-mail.select_a_message_to_inspect_its_content.5f3d1342");
  const loadingLabel = loadingProfiles ? "i18n:govoplan-mail.loading_mail_profiles.87de3560" : loadingFolders ? "i18n:govoplan-mail.loading_folders.17f9f0e2" : loadingMessages ? "i18n:govoplan-mail.loading_messages.77b62232" : "i18n:govoplan-mail.loading_message.815c2094";

  useEffect(() => {void loadProfiles();}, [settings.apiBaseUrl, settings.apiKey, settings.accessToken]);
  useEffect(() => {selectedMessageKeyRef.current = selectedMessageKeyState;}, [selectedMessageKeyState]);
  useEffect(() => {if (messagePage > messagePageCount) setMessagePage(messagePageCount);}, [messagePage, messagePageCount]);
  useEffect(() => {if (selectedProfileId) void loadFolders(selectedProfileId);}, [selectedProfileId]);
  useEffect(() => {if (selectedProfileId && selectedFolder && foldersReady) void loadMessages(selectedProfileId, selectedFolder, messagePage, messagePageSize);}, [foldersReady, messagePage, messagePageSize, selectedProfileId, selectedFolder]);

  useEffect(() => {
    const handlePreviewShortcut = (event: KeyboardEvent) => {
      if (isEditableTarget(event.target)) return;
      if (event.key === "Escape") {
        if (selectedMessage || selectedMessageKey || pendingMessageKey || detailError) {
          event.preventDefault();
          setSelectedMessage(null);
          setSelectedMessageKeyState("");
          selectedMessageKeyRef.current = "";
          setPendingMessageKey("");
          setDetailError("");
        }
        return;
      }
      if (shellBusy || loadingMessage || filteredMessages.length === 0) return;
      const selectedIndex = filteredMessages.findIndex((message) => mailboxMessageKey(message.folder || selectedFolder, message.uid) === selectedMessageKey);
      let nextIndex: number | null = null;
      if (event.key === "ArrowLeft") nextIndex = selectedIndex > 0 ? selectedIndex - 1 : 0;else
      if (event.key === "ArrowRight") nextIndex = selectedIndex >= 0 ? Math.min(filteredMessages.length - 1, selectedIndex + 1) : 0;else
      if (event.key === "Home") nextIndex = 0;else
      if (event.key === "End") nextIndex = filteredMessages.length - 1;
      if (nextIndex === null) return;
      event.preventDefault();
      const nextMessage = filteredMessages[nextIndex];
      if (nextMessage) void openMessage(nextMessage);
    };

    window.addEventListener("keydown", handlePreviewShortcut);
    return () => window.removeEventListener("keydown", handlePreviewShortcut);
  }, [detailError, filteredMessages, loadingMessage, pendingMessageKey, selectedFolder, selectedMessage, selectedMessageKey, shellBusy]);

  useEffect(() => {
    const ancestorIds = folderAncestorIds(folderTree, selectedFolder);
    if (ancestorIds.length === 0) return;
    setExpandedFolders((current) => {
      const next = new Set(current);
      ancestorIds.forEach((id) => next.add(id));
      return next;
    });
  }, [folderTree, selectedFolder]);

  async function loadProfiles() {
    setLoadingProfiles(true);
    setError("");
    try {
      const loaded = await listMailServerProfiles(settings);
      const usable = loaded.filter((profile) => profile.is_active && profile.imap);
      setProfiles(loaded);
      setSelectedProfileId((current) => current && usable.some((profile) => profile.id === current) ? current : usable[0]?.id ?? "");
      if (usable.length === 0) {
        setFolders([]);
        setFoldersLoadedForProfile("");
        setMessages([]);
        setMessageTotalCount(null);
        setSelectedMessage(null);
        setSelectedMessageKeyState("");
        setPendingMessageKey("");
      }
    } catch (err) {
      setError(errorText(err));
    } finally {
      setLoadingProfiles(false);
    }
  }

  async function loadFolders(profileId = selectedProfileId) {
    if (!profileId) return;
    const requestId = ++folderRequestRef.current;
    messageListRequestRef.current += 1;
    messageDetailRequestRef.current += 1;
    setLoadingFolders(true);
    setFoldersLoadedForProfile("");
    setMessageTotalCount(null);
    setMessagePage(1);
    setSelectedMessage(null);
    setSelectedMessageKeyState("");
    setPendingMessageKey("");
    setFolderError("");
    setMessageError("");
    setDetailError("");
    setError("");
    try {
      const response = await listMailboxFolders(settings, profileId);
      if (requestId !== folderRequestRef.current) return;
      if (!response.ok) throw new Error(response.message || "i18n:govoplan-mail.mailbox_folders_could_not_be_loaded.c3e3880e");
      const loaded = response.folders?.length ? response.folders : [{ name: "INBOX", flags: [] }];
      setFolders(loaded);
      setExpandedFolders(new Set());
      let nextFolder = selectedFolder;
      if (!nextFolder || !loaded.some((folder) => folder.name === nextFolder)) {
        nextFolder = loaded.some((folder) => folder.name === "INBOX") ? "INBOX" : response.detected_sent_folder || loaded[0]?.name || "INBOX";
      }
      setSelectedFolder(nextFolder);
      setFoldersLoadedForProfile(profileId);
    } catch (err) {
      if (requestId !== folderRequestRef.current) return;
      setFolderError(errorText(err));
      setError(errorText(err));
      setFolders([]);
      setFoldersLoadedForProfile("");
      setMessages([]);
      setMessageTotalCount(null);
      setSelectedMessage(null);
      setSelectedMessageKeyState("");
      setPendingMessageKey("");
    } finally {
      if (requestId === folderRequestRef.current) setLoadingFolders(false);
    }
  }

  async function loadMessages(profileId = selectedProfileId, folder = selectedFolder, page = messagePage, pageSize = messagePageSize) {
    if (!profileId || !folder) return;
    const requestId = ++messageListRequestRef.current;
    const offset = (Math.max(1, page) - 1) * pageSize;
    const cursorKey = mailboxCursorKey(profileId, folder, pageSize);
    const cursor = page <= 1 ? null : mailboxPageCursorsRef.current[`${cursorKey}:${page}`] || null;
    setLoadingMessages(true);
    setMessageError("");
    setDetailError("");
    setError("");
    try {
      const response = await listMailboxMessages(settings, profileId, folder, pageSize, offset, cursor);
      if (requestId !== messageListRequestRef.current) return;
      const loaded = response.messages ?? [];
      const total = response.total_count ?? loaded.length;
      if (page <= 1) mailboxPageCursorsRef.current[`${cursorKey}:1`] = null;
      if (response.next_cursor) mailboxPageCursorsRef.current[`${cursorKey}:${page + 1}`] = response.next_cursor;
      setMessages(loaded);
      setMessageTotalCount(total);
      setFolderMessageCount(folder, total);
      const rememberedKey = selectedMessageKeyRef.current;
      if (rememberedKey && !loaded.some((message) => mailboxMessageKey(message.folder || folder, message.uid) === rememberedKey)) {
        setSelectedMessage(null);
        setSelectedMessageKeyState("");
        setPendingMessageKey("");
      }
    } catch (err) {
      if (requestId !== messageListRequestRef.current) return;
      const message = errorText(err);
      setMessageError(message);
      setError(message);
      setMessages([]);
      setMessageTotalCount(null);
      setSelectedMessage(null);
      setSelectedMessageKeyState("");
      setPendingMessageKey("");
    } finally {
      if (requestId === messageListRequestRef.current) setLoadingMessages(false);
    }
  }

  async function openMessage(message: MailMailboxMessageSummary) {
    if (!selectedProfileId) return;
    const folderName = message.folder || selectedFolder;
    const requestId = ++messageDetailRequestRef.current;
    const nextKey = mailboxMessageKey(folderName, message.uid);
    setSelectedMessageKeyState(nextKey);
    selectedMessageKeyRef.current = nextKey;
    setPendingMessageKey(nextKey);
    setSelectedMessage(null);
    setDetailError("");
    setLoadingMessage(true);
    setError("");
    try {
      const response = await getMailboxMessage(settings, selectedProfileId, folderName, message.uid);
      if (requestId !== messageDetailRequestRef.current) return;
      setSelectedMessage(response.message);
      setSelectedMessageKeyState(mailboxMessageKey(response.message.folder || folderName, response.message.uid));
      setPendingMessageKey("");
    } catch (err) {
      if (requestId !== messageDetailRequestRef.current) return;
      const messageText = errorText(err);
      setDetailError(messageText);
      setError(messageText);
      setPendingMessageKey("");
    } finally {
      if (requestId === messageDetailRequestRef.current) setLoadingMessage(false);
    }
  }

  function selectProfile(profileId: string) {
    folderRequestRef.current += 1;
    messageListRequestRef.current += 1;
    messageDetailRequestRef.current += 1;
    setSelectedProfileId(profileId);
    setFolders([]);
    setFoldersLoadedForProfile("");
    setMessages([]);
    setMessageTotalCount(null);
    setMessagePage(1);
    setSelectedMessage(null);
    setSelectedMessageKeyState("");
    selectedMessageKeyRef.current = "";
    setPendingMessageKey("");
    setExpandedFolders(new Set());
    setLoadingFolders(false);
    setLoadingMessages(false);
    setLoadingMessage(false);
  }

  function openFolderNode(node: MailFolderNode) {
    if (node.folderName) {
      if (node.folderName === selectedFolder && foldersReady) void loadMessages(selectedProfileId, node.folderName, messagePage, messagePageSize);else
      {
        setSelectedFolder(node.folderName);
        setMessagePage(1);
        setSelectedMessage(null);
        setSelectedMessageKeyState("");
        selectedMessageKeyRef.current = "";
        setPendingMessageKey("");
        setDetailError("");
      }
      return;
    }
    toggleFolderNode(node);
  }

  function toggleFolderNode(node: MailFolderNode) {
    setExpandedFolders((current) => {
      const next = new Set(current);
      if (next.has(node.id)) next.delete(node.id);else
      next.add(node.id);
      return next;
    });
  }

  function setFolderMessageCount(folderName: string, count: number) {
    setFolders((current) => current.map((folder) => folder.name === folderName ? { ...folder, message_count: count } : folder));
  }

  function changeMessagePage(page: number) {
    const nextPage = Math.min(messagePageCount, Math.max(1, page));
    if (nextPage !== messagePage) setMessagePage(nextPage);
  }

  function changeMessagePageSize(pageSize: number) {
    setMessagePageSize(pageSize);
    setMessagePage(1);
  }

  return (
    <div className="workspace-data-page module-entry-page file-manager-page file-manager-fullscreen mailbox-page">
      {error && <DismissibleAlert tone="danger" resetKey={error} floating>{error}</DismissibleAlert>}

      <div className={`file-manager-shell mailbox-shell ${shellBusy ? "is-loading" : ""}`}>
        <aside className="file-tree-panel" aria-label="i18n:govoplan-mail.mailbox_folders.c92f6de4">
          <div className="file-tree-heading">i18n:govoplan-mail.folders.19adc47b</div>
          <div className="file-tree-list">
            {folderTree.length === 0 && <p className="muted small-text mailbox-tree-empty">{folderEmptyText}</p>}
            <ExplorerTree
              nodes={folderTree}
              getNodeId={(node) => node.id}
              getNodeLabel={(node) => node.label}
              getNodeChildren={(node) => node.children}
              activeId={selectedFolderNodeId}
              expandedIds={expandedFolders}
              onOpen={openFolderNode}
              onToggle={toggleFolderNode}
              disabled={shellBusy}
              renderNodeContent={(node) => {
                const flagText = folderFlagLabel(node.flags);
                const showCount = foldersReady && node.messageCount !== null;
                return (
                  <span className="mailbox-tree-node-label">
                    <span className="mailbox-tree-node-main">
                      <span>{node.label}</span>
                      {showCount && <small className="mailbox-folder-count">{node.messageCount}</small>}
                    </span>
                    {flagText && <small>{flagText}</small>}
                  </span>);

              }} />

          </div>
        </aside>

        <section className="file-list-panel mailbox-message-list-panel" aria-label="i18n:govoplan-mail.mailbox_messages.5c06afaf">
          <div className="file-list-sticky">
            <div className="file-manager-toolbar mailbox-toolbar" aria-label="i18n:govoplan-mail.mail_actions.c08b5f08">
              <label className="mailbox-profile-field">
                <span>i18n:govoplan-mail.imap_profile.5165df81</span>
                <select value={selectedProfileId} disabled={loadingProfiles || loadingFolders || imapProfiles.length === 0} onChange={(event) => selectProfile(event.target.value)}>
                  {imapProfiles.length === 0 && <option value="">i18n:govoplan-mail.no_imap_profiles_available.d64589f8</option>}
                  {imapProfiles.map((profile) => <option key={profile.id} value={profile.id}>{profile.name}</option>)}
                </select>
              </label>
              <span className="mailbox-toolbar-meta">{selectedProfile?.imap ? transportLabel(selectedProfile) : "i18n:govoplan-mail.no_imap_profile_selected.e7d1516f"}</span>
              <div className="mailbox-toolbar-actions">
                <Button onClick={() => void loadProfiles()} disabled={loadingProfiles} title="i18n:govoplan-mail.reload_imap_profiles.b04c11c8">
                  <RefreshCw size={16} aria-hidden="true" />
                  i18n:govoplan-mail.profiles.0c2a9300
                </Button>
                <Button onClick={() => void loadFolders(selectedProfileId)} disabled={!selectedProfileId || loadingFolders} title="i18n:govoplan-mail.refresh_mailbox_folders.d9af9963">
                  <RefreshCw size={16} aria-hidden="true" />
                  i18n:govoplan-mail.folders.19adc47b
                </Button>
                <Button onClick={() => void loadMessages(selectedProfileId, selectedFolder, messagePage, messagePageSize)} disabled={!selectedProfileId || !selectedFolder || !foldersReady || loadingMessages} title="i18n:govoplan-mail.refresh_messages_in_the_current_folder.b6546a2c">
                  <RefreshCw size={16} aria-hidden="true" />
                  i18n:govoplan-mail.messages.f1702b46
                </Button>
              </div>
            </div>

            <nav className="file-breadcrumbs" aria-label="i18n:govoplan-mail.current_mailbox_folder.55e2aea5">
              <span className="file-breadcrumb mailbox-breadcrumb-static"><Home size={15} aria-hidden="true" /> {selectedProfile?.name || "i18n:govoplan-mail.mail.92379cbb"}</span>
              <span className="file-breadcrumb-segment"><ChevronRight size={14} aria-hidden="true" /><span className="file-breadcrumb mailbox-breadcrumb-static">{selectedFolder}</span></span>
            </nav>

            <div className="mailbox-filter-row">
              <label className="mailbox-search-field">
                <Search size={15} aria-hidden="true" />
                <input value={messageQuery} onChange={(event) => setMessageQuery(event.target.value)} placeholder="i18n:govoplan-mail.search_messages.abea65ae" />
                {messageQuery && <button type="button" onClick={() => setMessageQuery("")} aria-label="i18n:govoplan-mail.clear_message_search.cc9f2800"><X size={14} /></button>}
              </label>
            </div>

            <div className="file-list-meta">
              <span>{messageCountLabel}</span>
              <span>{selectedFolder}</span>
              {messageQuery && <span>{filteredMessages.length} match{filteredMessages.length === 1 ? "" : "es"} i18n:govoplan-mail.on_page.ca7166f4</span>}
              {shellBusy && <span>i18n:govoplan-mail.working.049ac820</span>}
              {loadingMessage && <span>{i18nMessage("i18n:govoplan-mail.loading_preview.ebd86225")}</span>}
            </div>

            <div className="file-list-table-head mailbox-message-head" role="row">
              <span>i18n:govoplan-mail.subject.8d183dbd</span>
              <span>i18n:govoplan-mail.date.eb9a4bc1</span>
              <span>i18n:govoplan-mail.size.b7152342</span>
            </div>
          </div>

          <div className="file-list-drop-target mailbox-message-scroll">
            <div className="file-list-table mailbox-message-table" role="table" aria-label="i18n:govoplan-mail.mailbox_messages.5c06afaf">
              {filteredMessages.length === 0 && <div className={`file-list-empty${messageError ? " mailbox-error-state" : ""}`}>{messageEmptyText}</div>}
              {filteredMessages.map((message) => {
                const key = mailboxMessageKey(message.folder || selectedFolder, message.uid);
                const selected = key === selectedMessageKey;
                const loadingSelected = loadingMessage && key === pendingMessageKey;
                return (
                  <div
                    key={message.uid}
                    className={`file-list-row file-row mailbox-message-row ${selected ? "is-selected" : ""} ${loadingSelected ? "is-loading-message" : ""}`}
                    role="row"
                    tabIndex={0}
                    onClick={() => void openMessage(message)}
                    onKeyDown={(event) => {
                      if (event.key === "Enter" || event.key === " ") {
                        event.preventDefault();
                        void openMessage(message);
                      }
                    }}>

                    <div className="file-list-name-cell">
                      <div className="file-list-name">
                        <Mail className="file-row-icon" size={20} aria-hidden="true" />
                        <span>
                          <strong>{message.subject || "i18n:govoplan-mail.no_subject.49b20da0"}</strong>
                          <small>{message.from_header || "-"}</small>
                        </span>
                      </div>
                    </div>
                    <span className="mailbox-message-date">{formatDateTime(message.date, { fallback: "-" })}</span>
                    <span className="file-row-tail mailbox-message-tail">
                      {message.attachment_count ? <span><Paperclip size={14} aria-hidden="true" /> {message.attachment_count}</span> : null}
                      <span>{formatBytes(message.size_bytes)}</span>
                    </span>
                  </div>);

              })}
            </div>
          </div>
          <MailboxPagination
            page={messagePage}
            pageSize={messagePageSize}
            totalRows={messageTotalCount ?? 0}
            disabled={loadingMessages || !foldersReady}
            onPageChange={changeMessagePage}
            onPageSizeChange={changeMessagePageSize} />

        </section>

        <section className="mailbox-preview-panel" aria-label="i18n:govoplan-mail.message_preview.58de1450">
          <div className="file-tree-heading">i18n:govoplan-mail.preview.f1fbb2b4</div>
          <div className="mailbox-preview-scroll">
            <MessageDisplayPanel
              title={selectedMessage?.subject}
              fields={selectedMessage ? [
              { label: "i18n:govoplan-mail.from.3f66052a", value: selectedMessage.from_header || "-" },
              { label: "i18n:govoplan-mail.to.ae79ea1e", value: selectedMessage.to_header || "-" },
              { label: "i18n:govoplan-mail.cc.1fd6a880", value: selectedMessage.cc_header || null },
              { label: "i18n:govoplan-mail.bcc.8431acad", value: selectedMessage.bcc_header || null },
              { label: "i18n:govoplan-mail.date.eb9a4bc1", value: formatDateTime(selectedMessage.date, { fallback: "-" }) }] :
              []}
              bodyText={selectedMessage?.body_text}
              bodyHtml={selectedMessage?.body_html}
              bodyPreview={selectedMessage?.body_preview}
              headers={selectedMessage?.headers}
              attachments={selectedMessage?.attachments?.map((attachment) => ({
                filename: attachment.filename,
                contentType: attachment.content_type,
                sizeBytes: attachment.size_bytes
              }))}
              emptyText={previewEmptyText} />

          </div>
        </section>

        {shellBusy &&
        <div className="file-manager-loading-overlay" aria-live="polite" aria-busy="true">
            <div className="loading-frame-panel"><LoadingIndicator label={loadingLabel} /> <span>{i18nMessage(loadingLabel)}</span></div>
          </div>
        }
      </div>
    </div>);

}


function MailboxPagination({ page, pageSize, totalRows, disabled, onPageChange, onPageSizeChange }: {page: number;pageSize: number;totalRows: number;disabled: boolean;onPageChange: (page: number) => void;onPageSizeChange: (pageSize: number) => void;}) {
  const pageCount = Math.max(1, Math.ceil(totalRows / pageSize));
  const first = totalRows === 0 ? 0 : (page - 1) * pageSize + 1;
  const last = Math.min(totalRows, page * pageSize);
  const options = [10, 25, 50, 100];
  return (
    <div className="data-grid-pagination mailbox-pagination" aria-label="i18n:govoplan-mail.mailbox_message_pagination.965407bf">
      <div className="data-grid-pagination-summary">{first}-{last} of {totalRows}</div>
      <label className="data-grid-page-size">
        <span>i18n:govoplan-mail.rows_per_page.af2f9c1b</span>
        <select value={pageSize} disabled={disabled} onChange={(event) => onPageSizeChange(Number(event.target.value))}>
          {options.map((value) => <option key={value} value={value}>{value}</option>)}
        </select>
      </label>
      <div className="data-grid-page-controls">
        <button type="button" aria-label="i18n:govoplan-mail.first_page.49d74b49" disabled={disabled || page <= 1} onClick={() => onPageChange(1)}><ChevronsLeft size={16} /></button>
        <button type="button" aria-label="i18n:govoplan-mail.previous_page.81f54719" disabled={disabled || page <= 1} onClick={() => onPageChange(page - 1)}><ChevronLeft size={16} /></button>
        <span>i18n:govoplan-mail.page.fb06270f {page} of {pageCount}</span>
        <button type="button" aria-label="i18n:govoplan-mail.next_page.4bfc194b" disabled={disabled || page >= pageCount} onClick={() => onPageChange(page + 1)}><ChevronRight size={16} /></button>
        <button type="button" aria-label="i18n:govoplan-mail.last_page.b01f16ae" disabled={disabled || page >= pageCount} onClick={() => onPageChange(pageCount)}><ChevronsRight size={16} /></button>
      </div>
    </div>);

}

function mailboxMessageKey(folder: string, uid: string): string {
  return `${folder || "INBOX"}::${uid}`;
}

function mailboxCursorKey(profileId: string, folder: string, pageSize: number): string {
  return `${profileId}::${folder || "INBOX"}::${pageSize}`;
}

function filterMessages(messages: MailMailboxMessageSummary[], query: string): MailMailboxMessageSummary[] {
  const normalized = query.trim().toLocaleLowerCase();
  if (!normalized) return messages;
  return messages.filter((message) => [
  message.subject,
  message.from_header,
  message.to_header,
  message.cc_header,
  message.date,
  message.body_preview].
  some((value) => String(value ?? "").toLocaleLowerCase().includes(normalized)));
}

function messageListCountLabel(visibleCount: number, totalCount: number | null, loading: boolean, ready: boolean): string {
  if (!ready) return "i18n:govoplan-mail.no_folder_loaded.889bdb1b";
  if (loading) return "i18n:govoplan-mail.loading_messages.4294022c";
  if (totalCount !== null && totalCount > visibleCount) return i18nMessage("i18n:govoplan-mail.value_of_value_messages.981a1618", { value0: visibleCount, value1: totalCount });
  const count = totalCount ?? visibleCount;
  return i18nMessage(count === 1 ? "i18n:govoplan-mail.value_message" : "i18n:govoplan-mail.value_messages", { value0: count });
}

function folderFlagLabel(flags: string[]): string {
  const labels = flags.map(displayFolderFlag).filter((label): label is string => Boolean(label));
  return Array.from(new Set(labels)).join(" ");
}

function displayFolderFlag(flag: string): string | null {
  const normalized = flag.replace(/^\\/, "").toLowerCase();
  switch (normalized) {
    case "sent":
      return "i18n:govoplan-mail.sent.35f49dcf";
    case "drafts":
      return "i18n:govoplan-mail.drafts.22a31d86";
    case "trash":
      return "i18n:govoplan-mail.trash.e3bf62bb";
    case "archive":
      return "i18n:govoplan-mail.archive.2621c6fd";
    case "junk":
      return "i18n:govoplan-mail.junk.86c7d94c";
    case "flagged":
      return "i18n:govoplan-mail.flagged.f8db8a17";
    case "haschildren":
    case "hasnochildren":
    case "noselect":
      return null;
    default:
      return null;
  }
}

function transportLabel(profile: MailServerProfile): string {
  const imap = profile.imap;
  if (!imap?.host) return "i18n:govoplan-mail.imap_not_configured.b2892af3";
  return `${imap.host}:${imap.port ?? "?"} ${imap.security ?? ""}`.trim();
}

function formatBytes(value?: number | null): string {
  if (!value) return "-";
  if (value < 1024) return i18nMessage("i18n:govoplan-mail.bytes_b", { value0: value });
  if (value < 1024 * 1024) return i18nMessage("i18n:govoplan-mail.bytes_kb", { value0: (value / 1024).toFixed(1) });
  return i18nMessage("i18n:govoplan-mail.bytes_mb", { value0: (value / 1024 / 1024).toFixed(1) });
}

function errorText(error: unknown): string {
  return error instanceof Error ? error.message : String(error);
}

function isEditableTarget(target: EventTarget | null): boolean {
  if (!(target instanceof HTMLElement)) return false;
  return target.isContentEditable || ["INPUT", "SELECT", "TEXTAREA"].includes(target.tagName);
}
