import React, { useEffect, useMemo, useRef, useState } from 'react';

const initialCredentials = {
  mode: 'weektab',
  localPart: '',
  customUser: '',
  password: '',
  customImapHost: 'mail.weektab.org',
  customImapPort: '993'
};

const WEBMAIL_SESSION_KEY = 'weektab_webmail_session_v1';
const WEBMAIL_ACCOUNTS_KEY = 'weektab_webmail_accounts_v1';
const WEBMAIL_DATA_CACHE_KEY = 'weektab_webmail_data_cache_v1';
const DEFAULT_DOMAIN = 'weektab.org';
const DEFAULT_IMAP_HOST = 'mail.weektab.org';
const DEFAULT_IMAP_PORT = '993';
const INBOX_PAGE_SIZE = 50;

function extractEmail(value) {
  const match = String(value || '').match(/<(.*?)>/);
  if (match?.[1]) return match[1];
  return String(value || '').trim();
}

function extractMailBackgroundColor(html) {
  const source = String(html || '');
  if (!source) return '';

  const pickColor = (text) => {
    const candidate = String(text || '').trim();
    if (!candidate) return '';
    if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(candidate)) return candidate;
    if (/^(rgb|rgba|hsl|hsla)\(/i.test(candidate)) return candidate;
    if (/^[a-z]+$/i.test(candidate)) return candidate;
    return '';
  };

  const readStyleColor = (styleValue) => {
    const style = String(styleValue || '');
    if (!style) return '';
    const bgColor = style.match(/background-color\s*:\s*([^;]+)/i)?.[1];
    const fromBgColor = pickColor(bgColor);
    if (fromBgColor) return fromBgColor;
    const bg = style.match(/background\s*:\s*([^;]+)/i)?.[1];
    if (!bg) return '';
    const firstToken = String(bg).trim().split(/\s+/)[0];
    return pickColor(firstToken);
  };

  const bodyTag = source.match(/<body[^>]*>/i)?.[0] || '';
  if (bodyTag) {
    const bodyBg = pickColor(bodyTag.match(/bgcolor=["']?([^"'\s>]+)/i)?.[1]);
    if (bodyBg) return bodyBg;
    const bodyStyle = bodyTag.match(/style=["']([^"']*)["']/i)?.[1];
    const bodyStyleColor = readStyleColor(bodyStyle);
    if (bodyStyleColor) return bodyStyleColor;
  }

  const firstTableTag = source.match(/<table[^>]*>/i)?.[0] || '';
  if (firstTableTag) {
    const tableBg = pickColor(firstTableTag.match(/bgcolor=["']?([^"'\s>]+)/i)?.[1]);
    if (tableBg) return tableBg;
    const tableStyle = firstTableTag.match(/style=["']([^"']*)["']/i)?.[1];
    const tableStyleColor = readStyleColor(tableStyle);
    if (tableStyleColor) return tableStyleColor;
  }

  return '';
}

export default function Webmail() {
  const [credentials, setCredentials] = useState(initialCredentials);
  const [isConnecting, setIsConnecting] = useState(false);
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  const [loginError, setLoginError] = useState('');

  const [folders, setFolders] = useState([]);
  const [activeFolder, setActiveFolder] = useState('INBOX');
  const [emails, setEmails] = useState([]);
  const [isLoadingInbox, setIsLoadingInbox] = useState(false);
  const [isLoadingMore, setIsLoadingMore] = useState(false);
  const [isRefreshingInbox, setIsRefreshingInbox] = useState(false);
  const [pagingByAccount, setPagingByAccount] = useState({});
  const [viewCacheByAccount, setViewCacheByAccount] = useState({});
  const [searchQuery, setSearchQuery] = useState('');
  const [sortOrder, setSortOrder] = useState('newest');

  const [selectedEmailInfo, setSelectedEmailInfo] = useState(null);
  const [activeMessageData, setActiveMessageData] = useState(null);
  const [isLoadingMessage, setIsLoadingMessage] = useState(false);
  const [isEmptyingTrash, setIsEmptyingTrash] = useState(false);
  const [selectedEmailIds, setSelectedEmailIds] = useState([]);
  const [isDeletingSelected, setIsDeletingSelected] = useState(false);
  const [isFullscreen, setIsFullscreen] = useState(false);

  const [replyText, setReplyText] = useState('');
  const [isSending, setIsSending] = useState(false);
  const [isRestoringSession, setIsRestoringSession] = useState(true);
  const [isAddingAccount, setIsAddingAccount] = useState(false);
  const [savedAccounts, setSavedAccounts] = useState([]);
  const [activeAccountId, setActiveAccountId] = useState('');
  const [quotaByAccount, setQuotaByAccount] = useState({});
  const [folderSizesByAccount, setFolderSizesByAccount] = useState({});
  const inboxRequestTokenRef = useRef(0);
  const messageRequestTokenRef = useRef(0);
  const activeFolderRef = useRef('INBOX');
  const activeAccountIdRef = useRef('');
  const prevSortOrderRef = useRef('newest');

  const getAuthFromCredentials = (cred) => {
    const isCustom = cred.mode === 'custom';
    const user = isCustom
      ? String(cred.customUser || '').trim()
      : `${String(cred.localPart || '').trim()}@${DEFAULT_DOMAIN}`;
    const host = isCustom
      ? String(cred.customImapHost || DEFAULT_IMAP_HOST).trim()
      : DEFAULT_IMAP_HOST;
    const port = isCustom
      ? Number(cred.customImapPort || DEFAULT_IMAP_PORT)
      : Number(DEFAULT_IMAP_PORT);

    return {
      user,
      password: cred.password,
      host,
      port,
      tls: true
    };
  };

  const makeAccountId = (auth) => `${String(auth.user || '').toLowerCase()}|${String(auth.host || '').toLowerCase()}|${String(auth.port || '')}`;

  const formatBytes = (bytes) => {
    if (!Number.isFinite(bytes) || bytes <= 0) return '0 B';
    const units = ['B', 'KB', 'MB', 'GB', 'TB'];
    let value = bytes;
    let unitIndex = 0;
    while (value >= 1024 && unitIndex < units.length - 1) {
      value /= 1024;
      unitIndex += 1;
    }
    return `${value.toFixed(value >= 10 || unitIndex === 0 ? 0 : 1)} ${units[unitIndex]}`;
  };

  const buildFirstPageView = (emailList, totalCount, direction) => {
    const sorted = [...(Array.isArray(emailList) ? emailList : [])]
      .sort((a, b) => Number(a?.id || 0) - Number(b?.id || 0));
    const visible = direction === 'oldest'
      ? sorted.slice(0, INBOX_PAGE_SIZE)
      : sorted.slice(Math.max(0, sorted.length - INBOX_PAGE_SIZE));
    const safeTotal = Number(totalCount || sorted.length || 0);
    const nextOffset = Math.min(safeTotal, visible.length);
    const hasMore = nextOffset < safeTotal;
    return {
      emails: visible,
      paging: {
        total: safeTotal,
        nextOffset,
        hasMore,
        loadedAll: !hasMore,
        direction,
        updatedAt: Date.now()
      }
    };
  };

  const persistAccounts = (accounts) => {
    try {
      localStorage.setItem(WEBMAIL_ACCOUNTS_KEY, JSON.stringify(accounts));
    } catch {
      // Ignore storage errors.
    }
  };

  const readDataCache = () => {
    try {
      const raw = localStorage.getItem(WEBMAIL_DATA_CACHE_KEY);
      const parsed = raw ? JSON.parse(raw) : {};
      return parsed && typeof parsed === 'object' ? parsed : {};
    } catch {
      return {};
    }
  };

  const writeDataCache = (cache) => {
    try {
      localStorage.setItem(WEBMAIL_DATA_CACHE_KEY, JSON.stringify(cache));
    } catch {
      // Ignore storage errors.
    }
  };

  const getAccountCache = (accountId) => {
    const cache = readDataCache();
    return cache[accountId] || null;
  };

  const upsertAccountCache = ({ accountId, foldersMeta, folderName, folderEmails }) => {
    if (!accountId) return;

    const cache = readDataCache();
    const existing = cache[accountId] || { folders: [], emailsByFolder: {}, updatedAt: 0 };
    const next = {
      ...existing,
      folders: Array.isArray(foldersMeta) ? foldersMeta : existing.folders,
      emailsByFolder: {
        ...(existing.emailsByFolder || {}),
        ...(folderName ? { [folderName]: folderEmails } : {})
      },
      updatedAt: Date.now()
    };

    cache[accountId] = next;
    writeDataCache(cache);
  };

  const authPayload = useMemo(() => getAuthFromCredentials(credentials), [credentials]);

  useEffect(() => {
    activeFolderRef.current = activeFolder;
  }, [activeFolder]);

  useEffect(() => {
    activeAccountIdRef.current = activeAccountId;
  }, [activeAccountId]);

  const handleLoginChange = (event) => {
    const { name, value } = event.target;
    setCredentials((prev) => ({ ...prev, [name]: value }));
  };

  const postJson = async (url, payload) => {
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload)
    });
    const data = await res.json().catch(() => ({}));
    if (!res.ok) {
      throw new Error(data.error || `Request failed (${res.status})`);
    }
    return data;
  };

  const saveSession = (credState, lastFolder) => {
    try {
      localStorage.setItem(WEBMAIL_SESSION_KEY, JSON.stringify({
        credentials: credState,
        lastFolder: lastFolder || 'INBOX'
      }));
    } catch {
      // Ignore storage errors.
    }
  };

  const clearSession = () => {
    try {
      localStorage.removeItem(WEBMAIL_SESSION_KEY);
    } catch {
      // Ignore storage errors.
    }
  };

  const removeAccountCache = (accountId) => {
    if (!accountId) return;
    const cache = readDataCache();
    if (Object.prototype.hasOwnProperty.call(cache, accountId)) {
      delete cache[accountId];
      writeDataCache(cache);
    }
  };

  const clearAllAccountCaches = () => {
    try {
      localStorage.removeItem(WEBMAIL_DATA_CACHE_KEY);
    } catch {
      // Ignore storage errors.
    }
  };

  const setFolderPaging = (accountId, folderName, nextPaging) => {
    if (!accountId || !folderName) return;
    setPagingByAccount((prev) => ({
      ...prev,
      [accountId]: {
        ...(prev[accountId] || {}),
        [folderName]: {
          ...(prev[accountId]?.[folderName] || {}),
          ...(nextPaging || {})
        }
      }
    }));
  };

  const getViewCache = (accountId, folderName, direction) => (
    viewCacheByAccount?.[accountId]?.[folderName]?.[direction] || null
  );

  const setViewCache = (accountId, folderName, direction, emailsList, paging) => {
    if (!accountId || !folderName || !direction) return;
    setViewCacheByAccount((prev) => ({
      ...prev,
      [accountId]: {
        ...(prev[accountId] || {}),
        [folderName]: {
          ...(prev[accountId]?.[folderName] || {}),
          [direction]: {
            emails: Array.isArray(emailsList) ? emailsList : [],
            paging: paging || {}
          }
        }
      }
    }));
  };

  const upsertAccount = (credState, lastFolder = 'INBOX') => {
    const auth = getAuthFromCredentials(credState);
    const accountId = makeAccountId(auth);
    const account = {
      id: accountId,
      email: auth.user,
      host: auth.host,
      port: auth.port,
      lastFolder,
      credentials: { ...credState }
    };

    setSavedAccounts((prev) => {
      const next = [...prev];
      const index = next.findIndex((a) => a.id === accountId);
      if (index >= 0) next[index] = account;
      else next.push(account);
      persistAccounts(next);
      return next;
    });
    setActiveAccountId(accountId);
  };

  const fetchInbox = async (
    folderName,
    authOverride = authPayload,
    persistSession = false,
    credOverride = credentials,
    options = {}
  ) => {
    const requestToken = ++inboxRequestTokenRef.current;
    const isRequestCurrent = () => requestToken === inboxRequestTokenRef.current;
    const {
      keepSelection = false,
      silent = false,
      append = false,
      fetchAll = false,
      forceRefresh = false,
      syncOnly = false,
      resetToFirstPage = false
    } = options;
    const folder = folderName || activeFolder || 'INBOX';
    const accountId = makeAccountId(authOverride);
    const requestDirection = String(sortOrder || 'newest');
    const viewCache = getViewCache(accountId, folder, requestDirection);
    const accountCache = getAccountCache(accountId);
    const cachedFolderEntry = accountCache?.emailsByFolder?.[folder];
    const viewCachedEmails = Array.isArray(viewCache?.emails) ? viewCache.emails : [];
    const legacyCachedEmails = Array.isArray(cachedFolderEntry)
      ? cachedFolderEntry
      : Array.isArray(cachedFolderEntry?.emails)
        ? cachedFolderEntry.emails
        : [];
    const cachedFolderEmails = viewCachedEmails;
    const currentFolderPaging = viewCache?.paging || pagingByAccount?.[accountId]?.[folder] || {};
    const currentOffset = append ? Number(currentFolderPaging.nextOffset || emails.length || 0) : 0;
    const currentEmails = append ? emails : [];
    const folderChanged = Boolean(folderName) && String(folderName) !== String(activeFolderRef.current);
    const shouldResetWindow = !append && (resetToFirstPage || folderChanged);
    const baseEmailsForSync = cachedFolderEmails;
    const lastLoadedDirection = String(currentFolderPaging.direction || requestDirection);
    const canUseIncrementalSync = !append
      && !fetchAll
      && cachedFolderEmails.length > 0
      && (syncOnly || !forceRefresh)
      && baseEmailsForSync.length > 0
      && lastLoadedDirection === 'newest';

    setActiveFolder(folder);
    if (!append && !forceRefresh && cachedFolderEmails.length > 0) {
      const initial = shouldResetWindow
        ? buildFirstPageView(cachedFolderEmails, currentFolderPaging.total || cachedFolderEmails.length, requestDirection)
        : { emails: cachedFolderEmails, paging: currentFolderPaging };
      setEmails(initial.emails);
      setIsLoadingInbox(false);
      if (!currentFolderPaging.nextOffset) {
        const paging = buildFirstPageView(cachedFolderEmails, cachedFolderEmails.length, requestDirection).paging;
        setFolderPaging(accountId, folder, paging);
        setViewCache(accountId, folder, requestDirection, cachedFolderEmails, paging);
      } else if (shouldResetWindow) {
        setFolderPaging(accountId, folder, initial.paging);
        setViewCache(accountId, folder, requestDirection, cachedFolderEmails, initial.paging);
      }
    } else if (!append && !forceRefresh && viewCachedEmails.length === 0 && legacyCachedEmails.length > 0) {
      // Legacy storage fallback: show quickly, but do not treat as direction cache.
      const firstPage = buildFirstPageView(legacyCachedEmails, legacyCachedEmails.length, requestDirection);
      setEmails(firstPage.emails);
    }

    // Show loading only if there is no cached folder list to show immediately.
    if (!silent && !append && (!cachedFolderEmails.length || forceRefresh)) {
      setIsLoadingInbox(true);
    }
    if (append) setIsLoadingMore(true);
    if (!keepSelection) {
      messageRequestTokenRef.current += 1;
      setSelectedEmailInfo(null);
      setActiveMessageData(null);
      setSelectedEmailIds([]);
    }

    try {
      if (canUseIncrementalSync) {
        const knownIds = baseEmailsForSync
          .map((item) => Number(item?.id))
          .filter((uid) => Number.isFinite(uid) && uid > 0);
        const maxUid = knownIds.length ? Math.max(...knownIds) : 0;

        const syncData = await postJson('/api/webmail/inbox', {
          ...authOverride,
          folder,
          sync: true,
          sinceUid: maxUid,
          knownUids: knownIds
        });

        const deletedSet = new Set(
          Array.isArray(syncData?.deletedUids)
            ? syncData.deletedUids.map((uid) => Number(uid))
            : []
        );
        const merged = baseEmailsForSync.filter((msg) => !deletedSet.has(Number(msg?.id)));
        const mergedSet = new Set(merged.map((msg) => Number(msg?.id)));
        const newEmails = Array.isArray(syncData?.newEmails) ? syncData.newEmails : [];
        for (const msg of newEmails) {
          const uid = Number(msg?.id);
          if (!mergedSet.has(uid)) {
            merged.push(msg);
            mergedSet.add(uid);
          }
        }

        const total = Number(syncData?.total || merged.length || 0);
        const firstPageState = shouldResetWindow
          ? buildFirstPageView(merged, total, lastLoadedDirection)
          : null;
        const paging = shouldResetWindow
          ? firstPageState.paging
          : {
            total,
            nextOffset: merged.length,
            hasMore: merged.length < total,
            loadedAll: merged.length >= total,
            direction: lastLoadedDirection,
            updatedAt: Date.now()
          };
        const visibleEmails = shouldResetWindow
          ? firstPageState.emails
          : merged;

        if (!isRequestCurrent()) return;
        setEmails(visibleEmails);
        setFolderPaging(accountId, folder, paging);
        setViewCache(accountId, folder, lastLoadedDirection, merged, paging);
        if (persistSession) {
          saveSession(credOverride, folder);
          upsertAccount(credOverride, folder);
        }
        upsertAccountCache({
          accountId,
          folderName: folder,
          folderEmails: merged
        });
        return;
      }

      const data = await postJson('/api/webmail/inbox', {
        ...authOverride,
        folder,
        offset: fetchAll ? 0 : currentOffset,
        limit: INBOX_PAGE_SIZE,
        fetchAll,
        direction: requestDirection
      });
      const incomingEmails = Array.isArray(data.emails) ? data.emails : [];
      const nextEmails = append
        ? [...currentEmails, ...incomingEmails.filter((msg) => !currentEmails.some((existing) => existing.id === msg.id))]
        : incomingEmails;
      const safeTotal = Number(data.total || nextEmails.length || 0);
      const safeNextOffset = Number(data.nextOffset || nextEmails.length || 0);
      const hasMore = Boolean(data.hasMore);
      const loadedAll = fetchAll || safeNextOffset >= safeTotal || !hasMore;
      const paging = {
        total: safeTotal,
        nextOffset: safeNextOffset,
        hasMore,
        loadedAll,
        direction: requestDirection,
        updatedAt: Date.now()
      };
      const visibleState = shouldResetWindow
        ? buildFirstPageView(nextEmails, safeTotal, requestDirection)
        : { emails: nextEmails, paging };

      if (!isRequestCurrent()) return;
      setEmails(visibleState.emails);
      setFolderPaging(accountId, folder, visibleState.paging);
      setViewCache(accountId, folder, requestDirection, nextEmails, paging);
      if (persistSession) {
        saveSession(credOverride, folder);
        upsertAccount(credOverride, folder);
      }
      upsertAccountCache({
        accountId,
        folderName: folder,
        folderEmails: nextEmails
      });
    } catch (error) {
      if (!isRequestCurrent()) return;
      setLoginError(error.message || 'Failed to load mailbox.');
    } finally {
      if (!isRequestCurrent()) return;
      if (!silent && !append && (!cachedFolderEmails.length || forceRefresh)) {
        setIsLoadingInbox(false);
      }
      if (append) setIsLoadingMore(false);
    }
  };

  const connectWithCredentials = async (auth, lastFolder, credOverride = credentials, options = {}) => {
    const { skipInitialFetchIfCached = false } = options;
    try {
      const data = await postJson('/api/webmail/connect', auth);
      const folderList = Array.isArray(data.folders) ? data.folders : [];
      const normalized = folderList.map((f) => (typeof f === 'string' ? { name: f, unseen: 0, total: 0 } : f));
      const accountId = makeAccountId(auth);
      const accountCache = getAccountCache(accountId);

      setFolders(normalized);
      setIsLoggedIn(true);
      setIsAddingAccount(false);
      setActiveAccountId(accountId);

      const defaultFolder = normalized.find((f) => String(f.name).toUpperCase() === String(lastFolder || '').toUpperCase())?.name
        || normalized.find((f) => String(f.name).toUpperCase() === 'INBOX')?.name
        || normalized[0]?.name
        || 'INBOX';

      const cachedDefaultFolderEntry = accountCache?.emailsByFolder?.[defaultFolder];
      const cachedDefaultEmails = Array.isArray(cachedDefaultFolderEntry)
        ? cachedDefaultFolderEntry
        : Array.isArray(cachedDefaultFolderEntry?.emails)
          ? cachedDefaultFolderEntry.emails
          : null;

      if (cachedDefaultEmails) {
        const firstPage = buildFirstPageView(cachedDefaultEmails, cachedDefaultEmails.length, sortOrder);
        setActiveFolder(defaultFolder);
        setEmails(firstPage.emails);
      }

      upsertAccountCache({
        accountId,
        foldersMeta: normalized
      });

      if (skipInitialFetchIfCached && cachedDefaultEmails) {
        await fetchInbox(defaultFolder, auth, true, credOverride, {
          keepSelection: true,
          silent: true,
          syncOnly: true,
          resetToFirstPage: true
        });
      } else {
        await fetchInbox(defaultFolder, auth, true, credOverride, {
          keepSelection: true,
          silent: Boolean(cachedDefaultEmails),
          resetToFirstPage: true
        });
      }
      saveSession(credOverride, defaultFolder);
      upsertAccount(credOverride, defaultFolder);
      return true;
    } catch (error) {
      setLoginError(error.message || 'Login failed.');
      setIsLoggedIn(false);
      return false;
    }
  };

  const connectIMAP = async (event) => {
    event.preventDefault();
    setIsConnecting(true);
    setLoginError('');

    try {
      const localPart = String(credentials.localPart || '').trim();
      const customUser = String(credentials.customUser || '').trim();
      const customHost = String(credentials.customImapHost || '').trim();

      if (credentials.mode === 'custom') {
        if (!customUser || !customHost) {
          setLoginError('Please fill in custom email and IMAP host.');
          return;
        }
      } else if (!localPart) {
        setLoginError('Please enter your username.');
        return;
      }

      await connectWithCredentials(authPayload, undefined, credentials);
      await fetchQuota(authPayload);
      await fetchFolderSizes(authPayload);
    } finally {
      setIsConnecting(false);
    }
  };

  const fetchMessage = async (email) => {
    if (!email?.id) return;
    const requestToken = ++messageRequestTokenRef.current;
    const folderAtRequest = activeFolderRef.current;
    const accountAtRequest = activeAccountIdRef.current;
    setSelectedEmailInfo(email);
    setIsLoadingMessage(true);

    try {
      const data = await postJson('/api/webmail/message', {
        ...authPayload,
        folder: folderAtRequest || 'INBOX',
        uid: email.id
      });
      if (
        requestToken !== messageRequestTokenRef.current
        || folderAtRequest !== activeFolderRef.current
        || accountAtRequest !== activeAccountIdRef.current
      ) return;
      setActiveMessageData(data);
    } catch (error) {
      if (
        requestToken !== messageRequestTokenRef.current
        || folderAtRequest !== activeFolderRef.current
        || accountAtRequest !== activeAccountIdRef.current
      ) return;
      setActiveMessageData({
        html: `<p style="color:#b91c1c;">${error.message || 'Failed to load message.'}</p>`
      });
    } finally {
      if (requestToken !== messageRequestTokenRef.current) return;
      setIsLoadingMessage(false);
    }
  };

  const handleOpenMessageWindow = () => {
    if (!selectedEmailInfo) return;
    const popup = window.open('about:blank', '_blank', 'width=1200,height=800');
    if (!popup) return;

    const escapeHtml = (value) => String(value || '')
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#39;');

    const subject = escapeHtml(selectedEmailInfo.subject || '(No Subject)');
    const sender = escapeHtml(selectedEmailInfo.sender || 'Unknown');
    const body = activeMessageData?.html || '<p style="font-family:system-ui,sans-serif;color:#6b7280;">No content.</p>';

    const popupHtml = `<!doctype html>
<html>
<head>
  <meta charset="utf-8" />
  <title>${subject}</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <style>
    body { margin: 0; background: #f5f6f8; color: #111827; font-family: "Segoe UI", Arial, sans-serif; }
    .wrap { max-width: 980px; margin: 20px auto; background: #fff; border: 1px solid #e5e7eb; border-radius: 12px; overflow: hidden; }
    .head { padding: 18px 22px; border-bottom: 1px solid #e5e7eb; }
    .subj { margin: 0 0 8px; font-size: 22px; line-height: 1.2; }
    .meta { margin: 0; color: #6b7280; font-size: 13px; }
    .body { padding: 22px; }
    .body img { max-width: 100%; height: auto; }
    a { color: #2563eb; }
  </style>
</head>
<body>
  <div class="wrap">
    <div class="head">
      <h1 class="subj">${subject}</h1>
      <p class="meta">From: ${sender}</p>
    </div>
    <div class="body">${body}</div>
  </div>
</body>
</html>`;

    try {
      popup.document.open();
      popup.document.write(popupHtml);
      popup.document.close();
    } catch {
      popup.location.href = `data:text/html;charset=utf-8,${encodeURIComponent(popupHtml)}`;
    }
  };

  const handleDeleteMessage = async () => {
    if (!selectedEmailInfo?.id) return;
    const confirmed = window.confirm('Delete this email?');
    if (!confirmed) return;

    try {
      const uid = Number(selectedEmailInfo.id);
      await postJson('/api/webmail/delete', {
        ...authPayload,
        folder: activeFolder || 'INBOX',
        uid
      });

      setEmails((prev) => prev.filter((msg) => Number(msg?.id) !== uid));
      setSelectedEmailInfo(null);
      setActiveMessageData(null);
      setSelectedEmailIds((prev) => prev.filter((id) => Number(id) !== uid));

      const accountId = makeAccountId(authPayload);
      setViewCacheByAccount((prev) => {
        const accountCache = prev?.[accountId];
        if (!accountCache) return prev;
        const folderCache = accountCache?.[activeFolder];
        if (!folderCache) return prev;

        const nextFolderCache = {};
        for (const directionKey of Object.keys(folderCache)) {
          const directionView = folderCache[directionKey];
          const directionEmails = Array.isArray(directionView?.emails) ? directionView.emails : [];
          const filtered = directionEmails.filter((msg) => Number(msg?.id) !== uid);
          const total = Math.max(0, Number(directionView?.paging?.total || filtered.length) - 1);
          const nextOffset = Math.min(Number(directionView?.paging?.nextOffset || filtered.length), filtered.length);
          const hasMore = nextOffset < total;
          nextFolderCache[directionKey] = {
            ...directionView,
            emails: filtered,
            paging: {
              ...(directionView?.paging || {}),
              total,
              nextOffset,
              hasMore,
              loadedAll: !hasMore
            }
          };
        }

        return {
          ...prev,
          [accountId]: {
            ...accountCache,
            [activeFolder]: nextFolderCache
          }
        };
      });

      await fetchInbox(activeFolder, authPayload, true, credentials, {
        keepSelection: false,
        silent: true,
        syncOnly: true
      });
    } catch (error) {
      setLoginError(error.message || 'Failed to delete email.');
    }
  };

  const handleEmptyTrash = async () => {
    if (!isTrashFolder) return;
    const confirmed = window.confirm('Permanently delete all emails in Trash?');
    if (!confirmed) return;

    setIsEmptyingTrash(true);
    try {
      await postJson('/api/webmail/empty-trash', {
        ...authPayload,
        folder: activeFolder || 'INBOX.Trash'
      });

      setEmails([]);
      setSelectedEmailInfo(null);
      setActiveMessageData(null);
      setSelectedEmailIds([]);

      const accountId = makeAccountId(authPayload);
      setViewCacheByAccount((prev) => {
        const accountCache = prev?.[accountId];
        if (!accountCache) return prev;
        const folderCache = accountCache?.[activeFolder] || {};
        const nextFolderCache = {};
        for (const key of Object.keys(folderCache)) {
          nextFolderCache[key] = {
            ...(folderCache[key] || {}),
            emails: [],
            paging: {
              ...(folderCache[key]?.paging || {}),
              total: 0,
              nextOffset: 0,
              hasMore: false,
              loadedAll: true
            }
          };
        }
        return {
          ...prev,
          [accountId]: {
            ...accountCache,
            [activeFolder]: nextFolderCache
          }
        };
      });
    } catch (error) {
      setLoginError(error.message || 'Failed to empty trash.');
    } finally {
      setIsEmptyingTrash(false);
    }
  };

  const fetchQuota = async (authOverride = authPayload) => {
    const accountId = makeAccountId(authOverride);
    try {
      const data = await postJson('/api/webmail/quota', authOverride);
      setQuotaByAccount((prev) => ({
        ...prev,
        [accountId]: data?.supported
          ? {
            supported: true,
            usedBytes: Number(data.usedBytes || 0),
            limitBytes: Number(data.limitBytes || 0),
            percent: Number.isFinite(data.percent) ? data.percent : 0
          }
          : data?.estimated
            ? {
              supported: false,
              estimated: true,
              usedBytes: Number(data.usedBytes || 0)
            }
            : { supported: false }
      }));
    } catch {
      setQuotaByAccount((prev) => ({ ...prev, [accountId]: { supported: false } }));
    }
  };

  const fetchFolderSizes = async (authOverride = authPayload) => {
    const accountId = makeAccountId(authOverride);
    try {
      const data = await postJson('/api/webmail/folder-sizes', authOverride);
      const sizes = data?.sizes && typeof data.sizes === 'object' ? data.sizes : {};
      setFolderSizesByAccount((prev) => ({ ...prev, [accountId]: sizes }));
    } catch {
      setFolderSizesByAccount((prev) => ({ ...prev, [accountId]: {} }));
    }
  };

  const sendReply = async () => {
    if (!replyText.trim() || !selectedEmailInfo) return;

    setIsSending(true);
    try {
      const smtpHost = authPayload.host.replace(/^imap\./i, 'smtp.');
      const to = extractEmail(selectedEmailInfo.sender);

      await postJson('/api/webmail/send', {
        user: authPayload.user,
        password: credentials.password,
        host: smtpHost,
        port: 465,
        to,
        subject: `Re: ${selectedEmailInfo.subject || ''}`,
        body: `<p>${replyText.replace(/\n/g, '<br>')}</p>`
      });

      setReplyText('');
    } catch (error) {
      setLoginError(error.message || 'Failed to send reply.');
    } finally {
      setIsSending(false);
    }
  };

  const handleLogout = () => {
    inboxRequestTokenRef.current += 1;
    messageRequestTokenRef.current += 1;
    const currentId = activeAccountId;
    const remainingAccounts = savedAccounts.filter((a) => a.id !== currentId);

    removeAccountCache(currentId);
    persistAccounts(remainingAccounts);

    setIsLoggedIn(false);
    setFolders([]);
    setEmails([]);
    setSelectedEmailInfo(null);
    setActiveMessageData(null);
    setReplyText('');
    setCredentials(initialCredentials);
    setSavedAccounts(remainingAccounts);
    setActiveAccountId(remainingAccounts[0]?.id || '');
    setQuotaByAccount((prev) => {
      const next = { ...prev };
      delete next[currentId];
      return next;
    });
    setFolderSizesByAccount((prev) => {
      const next = { ...prev };
      delete next[currentId];
      return next;
    });
    setViewCacheByAccount((prev) => {
      const next = { ...prev };
      delete next[currentId];
      return next;
    });
    setPagingByAccount((prev) => {
      const next = { ...prev };
      delete next[currentId];
      return next;
    });
    setIsAddingAccount(false);
    clearSession();
  };

  const handleLogoutAll = () => {
    inboxRequestTokenRef.current += 1;
    messageRequestTokenRef.current += 1;
    clearSession();
    clearAllAccountCaches();
    persistAccounts([]);

    setIsLoggedIn(false);
    setFolders([]);
    setEmails([]);
    setSelectedEmailInfo(null);
    setActiveMessageData(null);
    setReplyText('');
    setCredentials(initialCredentials);
    setSavedAccounts([]);
    setActiveAccountId('');
    setQuotaByAccount({});
    setFolderSizesByAccount({});
    setViewCacheByAccount({});
    setPagingByAccount({});
    setLoginError('');
    setIsAddingAccount(false);
  };

  const handleAddAccount = () => {
    inboxRequestTokenRef.current += 1;
    messageRequestTokenRef.current += 1;
    setIsLoggedIn(false);
    setIsConnecting(false);
    setLoginError('');
    setFolders([]);
    setEmails([]);
    setSelectedEmailInfo(null);
    setActiveMessageData(null);
    setReplyText('');
    setCredentials(initialCredentials);
    setViewCacheByAccount({});
    setIsAddingAccount(true);
    clearSession();
  };

  const handleCancelAddAccount = async () => {
    if (savedAccounts.length === 0) {
      setIsAddingAccount(false);
      return;
    }
    const targetId = activeAccountId || savedAccounts[0].id;
    setIsAddingAccount(false);
    await handleSwitchAccount(targetId);
  };

  const handleSwitchAccount = async (accountId) => {
    const account = savedAccounts.find((a) => a.id === accountId);
    if (!account) return;

    setIsConnecting(true);
    setLoginError('');
    setCredentials(account.credentials);
    setActiveAccountId(account.id);

    try {
      const auth = getAuthFromCredentials(account.credentials);
      const cached = getAccountCache(account.id);
      const targetFolder = account.lastFolder || 'INBOX';

      if (cached?.folders?.length) {
        setFolders(cached.folders);
      }
      const cachedTargetEntry = cached?.emailsByFolder?.[targetFolder];
      const cachedTargetEmails = Array.isArray(cachedTargetEntry)
        ? cachedTargetEntry
        : Array.isArray(cachedTargetEntry?.emails)
          ? cachedTargetEntry.emails
          : null;
      if (cachedTargetEmails) {
        const firstPage = buildFirstPageView(cachedTargetEmails, cachedTargetEmails.length, sortOrder);
        setActiveFolder(targetFolder);
        setEmails(firstPage.emails);
      }

      await connectWithCredentials(auth, account.lastFolder || 'INBOX', account.credentials);
      await fetchQuota(auth);
      await fetchFolderSizes(auth);
    } finally {
      setIsConnecting(false);
    }
  };

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

    const restoreSession = async () => {
      try {
        const rawAccounts = localStorage.getItem(WEBMAIL_ACCOUNTS_KEY);
        if (rawAccounts) {
          const parsedAccounts = JSON.parse(rawAccounts);
          if (Array.isArray(parsedAccounts)) {
            setSavedAccounts(parsedAccounts);
          }
        }

        const raw = localStorage.getItem(WEBMAIL_SESSION_KEY);
        if (!raw) return;

        const parsed = JSON.parse(raw);
        const parsedCredentials = parsed?.credentials || {};
        let savedCredentials = { ...initialCredentials, ...parsedCredentials };

        // Backward compatibility with old saved format (user/imapHost/imapPort).
        if (!Object.prototype.hasOwnProperty.call(parsedCredentials, 'mode') && parsedCredentials.user) {
          const oldUser = String(parsedCredentials.user || '').trim();
          const oldHost = String(parsedCredentials.imapHost || DEFAULT_IMAP_HOST).trim();
          const oldPort = String(parsedCredentials.imapPort || DEFAULT_IMAP_PORT).trim();
          const oldPassword = String(parsedCredentials.password || '').trim();

          if (oldUser.toLowerCase().endsWith(`@${DEFAULT_DOMAIN}`)) {
            savedCredentials = {
              ...initialCredentials,
              mode: 'weektab',
              localPart: oldUser.slice(0, oldUser.indexOf('@')),
              password: oldPassword,
              customImapHost: DEFAULT_IMAP_HOST,
              customImapPort: DEFAULT_IMAP_PORT
            };
          } else {
            savedCredentials = {
              ...initialCredentials,
              mode: 'custom',
              customUser: oldUser,
              password: oldPassword,
              customImapHost: oldHost || DEFAULT_IMAP_HOST,
              customImapPort: oldPort || DEFAULT_IMAP_PORT
            };
          }
        }

        const savedIsCustom = savedCredentials.mode === 'custom';
        const savedAuth = {
          user: savedIsCustom
            ? String(savedCredentials.customUser || '').trim()
            : `${String(savedCredentials.localPart || '').trim()}@${DEFAULT_DOMAIN}`,
          password: savedCredentials.password,
          host: savedIsCustom
            ? String(savedCredentials.customImapHost || DEFAULT_IMAP_HOST).trim()
            : DEFAULT_IMAP_HOST,
          port: savedIsCustom
            ? Number(savedCredentials.customImapPort || DEFAULT_IMAP_PORT)
            : Number(DEFAULT_IMAP_PORT),
          tls: true
        };

        if (!savedAuth.user || !savedAuth.password || !savedAuth.host) {
          clearSession();
          return;
        }

        setCredentials(savedCredentials);
        setActiveAccountId(makeAccountId(savedAuth));
        setIsConnecting(true);
        setLoginError('');

        if (!cancelled) {
          await connectWithCredentials(savedAuth, parsed?.lastFolder || 'INBOX', savedCredentials, {
            skipInitialFetchIfCached: true
          });
          await fetchQuota(savedAuth);
          await fetchFolderSizes(savedAuth);
        }
      } catch {
        clearSession();
      } finally {
        if (!cancelled) {
          setIsConnecting(false);
          setIsRestoringSession(false);
        }
      }
    };

    restoreSession();

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

  useEffect(() => {
    const onKeyDown = (event) => {
      if (event.key === 'Escape') {
        setIsFullscreen(false);
      }
    };
    window.addEventListener('keydown', onKeyDown);
    return () => window.removeEventListener('keydown', onKeyDown);
  }, []);

  useEffect(() => {
    if (!isLoggedIn || !activeAccountId || !activeFolder) return undefined;

    const intervalId = window.setInterval(() => {
      fetchInbox(activeFolder, authPayload, true, credentials, {
        keepSelection: true,
        silent: true,
        syncOnly: true
      });
    }, 5 * 60 * 1000);

    return () => window.clearInterval(intervalId);
  }, [isLoggedIn, activeAccountId, activeFolder, authPayload, credentials, sortOrder]);

  const activeFolderPaging = getViewCache(activeAccountId, activeFolder, sortOrder)?.paging
    || pagingByAccount?.[activeAccountId]?.[activeFolder]
    || {};

  useEffect(() => {
    if (prevSortOrderRef.current === sortOrder) return;
    prevSortOrderRef.current = sortOrder;
    if (!isLoggedIn || !activeAccountId || !activeFolder) return;

    const cachedView = getViewCache(activeAccountId, activeFolder, sortOrder);
    if (cachedView?.emails?.length) {
      const firstPage = buildFirstPageView(
        cachedView.emails,
        cachedView.paging?.total || cachedView.emails.length,
        sortOrder
      );
      setEmails(firstPage.emails);
      setFolderPaging(activeAccountId, activeFolder, firstPage.paging);
      setViewCache(activeAccountId, activeFolder, sortOrder, cachedView.emails, firstPage.paging);
      return;
    }

    fetchInbox(activeFolder, authPayload, true, credentials, {
      keepSelection: true,
      forceRefresh: true,
      resetToFirstPage: true
    });
  }, [sortOrder, isLoggedIn, activeAccountId, activeFolder, authPayload, credentials, viewCacheByAccount]);

  const filteredEmails = useMemo(() => {
    const q = String(searchQuery || '').trim().toLowerCase();
    if (!q) return emails;

    return emails.filter((email) => {
      const haystack = [
        email?.subject,
        email?.sender,
        email?.snippet,
        email?.preview,
        email?.text,
        email?.body
      ]
        .filter(Boolean)
        .join(' ')
        .toLowerCase();

      return haystack.includes(q);
    });
  }, [emails, searchQuery]);

  const displayedEmails = useMemo(() => {
    const list = [...filteredEmails];
    list.sort((a, b) => {
      const aId = Number(a?.id || 0);
      const bId = Number(b?.id || 0);
      return sortOrder === 'newest' ? bId - aId : aId - bId;
    });
    return list;
  }, [filteredEmails, sortOrder]);

  const canShowLoadMore = useMemo(() => {
    if (isLoadingInbox) return false;
    if (String(searchQuery || '').trim()) return false;
    const loadedCount = Number(emails?.length || 0);
    const totalCount = Number(activeFolderPaging?.total || 0);
    if (totalCount > loadedCount) return true;
    return Boolean(activeFolderPaging?.hasMore);
  }, [isLoadingInbox, searchQuery, emails, activeFolderPaging]);

  const isTrashFolder = useMemo(() => /trash$/i.test(String(activeFolder || '')), [activeFolder]);
  const selectedCount = selectedEmailIds.length;
  const mailBackgroundColor = useMemo(
    () => extractMailBackgroundColor(activeMessageData?.html),
    [activeMessageData?.html]
  );

  useEffect(() => {
    setSelectedEmailIds([]);
  }, [activeFolder, sortOrder]);

  const toggleEmailSelection = (emailId) => {
    const uid = Number(emailId);
    if (!Number.isFinite(uid)) return;
    setSelectedEmailIds((prev) => (
      prev.includes(uid)
        ? prev.filter((id) => id !== uid)
        : [...prev, uid]
    ));
  };

  const getSenderInitial = (sender) => {
    const clean = String(sender || '').replace(/<.*?>/g, '').trim();
    const first = clean.charAt(0).toUpperCase();
    return first || '?';
  };

  const handleDeleteSelected = async () => {
    if (selectedEmailIds.length === 0) return;
    const confirmed = window.confirm(`Delete ${selectedEmailIds.length} selected email(s)?`);
    if (!confirmed) return;

    setIsDeletingSelected(true);
    try {
      const uids = selectedEmailIds
        .map((id) => Number(id))
        .filter((uid) => Number.isFinite(uid) && uid > 0);

      // Use proven single-delete endpoint per UID for maximum compatibility.
      await Promise.all(
        uids.map((uid) => postJson('/api/webmail/delete', {
          ...authPayload,
          folder: activeFolder || 'INBOX',
          uid
        }))
      );

      const deleteSet = new Set(uids);
      setEmails((prev) => prev.filter((msg) => !deleteSet.has(Number(msg?.id))));

      if (selectedEmailInfo?.id && deleteSet.has(Number(selectedEmailInfo.id))) {
        setSelectedEmailInfo(null);
        setActiveMessageData(null);
      }

      const accountId = makeAccountId(authPayload);
      setViewCacheByAccount((prev) => {
        const accountCache = prev?.[accountId];
        if (!accountCache) return prev;
        const folderCache = accountCache?.[activeFolder];
        if (!folderCache) return prev;

        const nextFolderCache = {};
        for (const directionKey of Object.keys(folderCache)) {
          const directionView = folderCache[directionKey];
          const directionEmails = Array.isArray(directionView?.emails) ? directionView.emails : [];
          const filtered = directionEmails.filter((msg) => !deleteSet.has(Number(msg?.id)));
          const total = Math.max(0, Number(directionView?.paging?.total || filtered.length) - deleteSet.size);
          const nextOffset = Math.min(Number(directionView?.paging?.nextOffset || filtered.length), filtered.length);
          const hasMore = nextOffset < total;
          nextFolderCache[directionKey] = {
            ...directionView,
            emails: filtered,
            paging: {
              ...(directionView?.paging || {}),
              total,
              nextOffset,
              hasMore,
              loadedAll: !hasMore
            }
          };
        }

        return {
          ...prev,
          [accountId]: {
            ...accountCache,
            [activeFolder]: nextFolderCache
          }
        };
      });

      setSelectedEmailIds([]);
      await fetchInbox(activeFolder, authPayload, true, credentials, {
        keepSelection: false,
        silent: true,
        syncOnly: true
      });
    } catch (error) {
      setLoginError(error.message || 'Failed to delete selected emails.');
    } finally {
      setIsDeletingSelected(false);
    }
  };

  const handleLoadMore = async () => {
    if (!isLoggedIn || !activeFolder) return;
    if (isLoadingMore || isLoadingInbox) return;
    if (!activeFolderPaging.hasMore || activeFolderPaging.loadedAll) return;

    await fetchInbox(activeFolder, authPayload, true, credentials, {
      keepSelection: true,
      append: true,
      silent: true
    });
  };

  const handleManualRefresh = async () => {
    setIsRefreshingInbox(true);
    try {
      await fetchInbox(activeFolder, authPayload, true, credentials, {
        keepSelection: true,
        syncOnly: true
      });
      await fetchFolderSizes(authPayload);
      await fetchQuota(authPayload);
    } finally {
      setIsRefreshingInbox(false);
    }
  };

  const activeQuota = quotaByAccount[activeAccountId] || null;
  const activeFolderSizes = folderSizesByAccount[activeAccountId] || {};

  const loginForm = (
    <form className="login-form login-form--billing" onSubmit={connectIMAP}>
      {loginError && <div className="login-error">{loginError}</div>}

      <div className="form-group">
        <label className="form-label">{credentials.mode === 'custom' ? 'Email' : 'Username'}</label>
        {credentials.mode === 'custom' ? (
          <input
            type="email"
            name="customUser"
            required
            value={credentials.customUser}
            onChange={handleLoginChange}
            placeholder="name@yourdomain.tld"
          />
        ) : (
          <div className="email-fixed-domain">
            <input
              type="text"
              name="localPart"
              required
              value={credentials.localPart}
              onChange={handleLoginChange}
              placeholder="e.g. max.mustermann"
            />
            <span className="email-domain">@{DEFAULT_DOMAIN}</span>
          </div>
        )}
      </div>

      <div className="form-group">
        <label className="form-label">Password</label>
        <input
          type="password"
          name="password"
          required
          value={credentials.password}
          onChange={handleLoginChange}
          placeholder="Password"
        />
      </div>

      <div className="custom-email-box">
        <div className="custom-email-box__header">
          <h3>CUSTOM E-MAIL</h3>
          <button
            type="button"
            className={`custom-email-toggle ${credentials.mode === 'custom' ? 'active' : ''}`}
            onClick={() => setCredentials((prev) => ({
              ...prev,
              mode: prev.mode === 'custom' ? 'weektab' : 'custom'
            }))}
          >
            {credentials.mode === 'custom' ? 'Active' : 'Enable'}
          </button>
        </div>

        <p className="custom-email-box__hint">
          Optional: Use your own mail domain. Then you can set host and port.
        </p>

        {credentials.mode === 'custom' && (
          <>
            <div className="form-group">
              <label className="form-label">CUSTOM IMAP Host</label>
              <input
                type="text"
                name="customImapHost"
                required
                value={credentials.customImapHost}
                onChange={handleLoginChange}
                placeholder="imap.yourdomain.tld"
              />
            </div>

            <div className="form-group">
              <label className="form-label">CUSTOM Port</label>
              <input
                type="number"
                name="customImapPort"
                required
                value={credentials.customImapPort}
                onChange={handleLoginChange}
                placeholder="993"
              />
            </div>
          </>
        )}
      </div>

      <button type="submit" className="login-btn" disabled={isConnecting}>
        {isConnecting ? 'Connecting...' : 'Sign in'}
      </button>

      {isAddingAccount && savedAccounts.length > 0 && (
        <button type="button" className="cancel-account-btn" onClick={handleCancelAddAccount}>
          Cancel
        </button>
      )}

      <p className="login-hint">Use your IMAP credentials to sign in.</p>
    </form>
  );

  const webmailWorkspace = (
    <div className={`webmail-app ${isFullscreen ? 'webmail-app--fullscreen' : ''}`}>
      <div className="missive-sidebar">
        <div className="sidebar-header">
          <div className="sidebar-actions">
            <button
              className="fullscreen-btn"
              onClick={() => setIsFullscreen((prev) => !prev)}
              title={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}
            >
              <i className={isFullscreen ? 'ri-fullscreen-exit-line' : 'ri-fullscreen-line'} />
            </button>
          </div>
          <button
            className={`add-btn ${isRefreshingInbox ? 'syncing' : ''}`}
            onClick={handleManualRefresh}
            disabled={isRefreshingInbox}
            title="Refresh"
          >
            <i className="ri-refresh-line" />
          </button>
        </div>

        <div className="sidebar-scroll">
          {(folders.length ? folders : [{ name: 'INBOX', unseen: 0, total: 0 }]).map((folder, index) => {
            const folderName = typeof folder === 'string' ? folder : folder.name;
            const displayFolderName = folderName === 'INBOX'
              ? 'INBOX'
              : String(folderName || '').replace(/^INBOX\./i, '');
            const unseen = folder.unseen || 0;
            const total = folder.total || 0;
            const isActive = activeFolder === folderName;
            const sizeBytes = Number(activeFolderSizes[folderName] || 0);
            const sizeLabel = sizeBytes > 0 ? formatBytes(sizeBytes) : '';

            return (
              <div
                key={`${folderName}-${index}`}
                className={`sidebar-item ${isActive ? 'active' : ''}`}
                onClick={() => fetchInbox(folderName, authPayload, true, credentials, {
                  resetToFirstPage: true,
                  syncOnly: true
                })}
              >
                <i className="ri-folder-2-fill" />
                <span className="label" style={{ textTransform: 'capitalize' }}>{displayFolderName}</span>
                {unseen > 0 && <span className="sidebar-badge badge-blue">{unseen}</span>}
                {total > 0 && <span className="sidebar-badge badge-gray">{total}</span>}
                {sizeLabel && <span className="sidebar-folder-size">{sizeLabel}</span>}
              </div>
            );
          })}

        </div>

        <div className="sidebar-account-switcher">
          <div className="account-switcher-header">
            <label htmlFor="account-switcher">Email account</label>
            <button
              type="button"
              className="add-account-icon-btn"
              onClick={handleAddAccount}
              title="Add new email"
              aria-label="Add new email"
            >
              +
            </button>
          </div>
          <select
            id="account-switcher"
            value={activeAccountId}
            onChange={(e) => handleSwitchAccount(e.target.value)}
          >
            {savedAccounts.length === 0 && <option value="">No accounts</option>}
            {savedAccounts.map((account) => (
              <option key={account.id} value={account.id}>
                {account.email}
              </option>
            ))}
          </select>
          {activeQuota?.supported ? (
            <div className="account-quota">
              <div className="account-quota__text">
                Storage {formatBytes(activeQuota.usedBytes)} / {formatBytes(activeQuota.limitBytes)}
              </div>
              <div className="account-quota__bar" aria-hidden="true">
                <span style={{ width: `${Math.max(0, Math.min(100, activeQuota.percent || 0))}%` }} />
              </div>
            </div>
          ) : activeQuota?.estimated ? (
            <div className="account-quota">
              <div className="account-quota__text">
                Total mailbox size: {formatBytes(activeQuota.usedBytes)}
              </div>
            </div>
          ) : (
            <div className="account-quota account-quota--muted">Checking storage usage...</div>
          )}
          {savedAccounts.length > 1 ? (
            <div className="logout-grid">
              <button type="button" className="logout-btn" onClick={handleLogout}>
                Log out
              </button>
              <button type="button" className="logout-all-btn" onClick={handleLogoutAll}>
                Logout all
              </button>
            </div>
          ) : (
            <button type="button" className="logout-btn logout-btn--single" onClick={handleLogout}>
              Log out
            </button>
          )}
        </div>
      </div>

      <div className="missive-list">
        <div className="list-search">
          <i className="ri-search-line" />
          <input
            type="text"
            placeholder="Search emails"
            value={searchQuery}
            onChange={(e) => setSearchQuery(e.target.value)}
          />
          <button
            type="button"
            className="list-sort-btn"
            onClick={() => setSortOrder((prev) => (prev === 'newest' ? 'oldest' : 'newest'))}
            title={sortOrder === 'newest' ? 'Sorted: newest first' : 'Sorted: oldest first'}
            aria-label={sortOrder === 'newest' ? 'Sorted: newest first' : 'Sorted: oldest first'}
          >
            <i className={sortOrder === 'newest' ? 'ri-sort-desc' : 'ri-sort-asc'} />
          </button>
        </div>

        <div className="list-section-header">
          <span>{activeFolder || 'INBOX'}</span>
          <div className="list-section-actions">
            {selectedCount > 0 && (
              <button
                type="button"
                className="header-delete-btn"
                onClick={handleDeleteSelected}
                disabled={isDeletingSelected}
              >
                {isDeletingSelected ? 'Deleting...' : `Delete (${selectedCount})`}
              </button>
            )}
            {isTrashFolder && selectedCount === 0 && (
              <button
                type="button"
                className="empty-trash-btn"
                onClick={handleEmptyTrash}
                disabled={isEmptyingTrash}
              >
                {isEmptyingTrash ? 'Emptying...' : 'Empty trash'}
              </button>
            )}
          </div>
        </div>

        <div className="list-scroll">
          {isLoadingInbox ? (
            <div className="loading-state">Loading messages...</div>
          ) : filteredEmails.length === 0 ? (
            <div className="loading-state">
              {emails.length === 0 ? 'No emails found.' : 'No results for your search.'}
            </div>
          ) : (
            displayedEmails.map((email) => {
              const isSelected = selectedEmailInfo?.id === email.id;
              const isChecked = selectedEmailIds.includes(Number(email.id));
              const simpleSender = String(email.sender || '').split('<')[0].trim() || email.sender;
              const senderInitial = getSenderInitial(simpleSender);

              return (
                <div
                  key={email.id}
                  className={`list-item ${isSelected ? 'active' : ''} ${isChecked ? 'checked' : ''}`}
                  onClick={() => fetchMessage(email)}
                >
                  <span className="email-sender-avatar" aria-hidden="true">
                    <span className="email-sender-avatar__fallback">{senderInitial}</span>
                    {email.avatar && (
                      <img
                        src={email.avatar}
                        alt=""
                        loading="lazy"
                        referrerPolicy="no-referrer"
                        onError={(e) => {
                          e.currentTarget.style.display = 'none';
                        }}
                      />
                    )}
                  </span>
                  <input
                    type="checkbox"
                    className="email-select-checkbox"
                    checked={isChecked}
                    onChange={() => toggleEmailSelection(email.id)}
                    onClick={(e) => e.stopPropagation()}
                    aria-label="Select email"
                  />
                  <div className="item-top">
                    <div className="item-sender">
                      <span className="name">{simpleSender || 'Unknown'}</span>
                    </div>
                    <span className="item-time">{String(email.time || '').split(',')[0]}</span>
                  </div>
                  <div className="item-subject">
                    <span>{email.subject || '(No Subject)'}</span>
                  </div>
                </div>
              );
            })
          )}
          {canShowLoadMore && (
            <div className="list-load-more-wrap">
              <button
                type="button"
                className="list-load-more-btn"
                onClick={handleLoadMore}
                disabled={isLoadingMore}
              >
                {isLoadingMore ? 'Loading...' : 'Load more'}
              </button>
            </div>
          )}
        </div>
      </div>

      <div className="missive-reading">
        {!selectedEmailInfo ? (
          <div className="empty-reading-state">
            <p>Select a message from the list.</p>
          </div>
        ) : (
          <>
            <div className="reading-toolbar">
              <div className="toolbar-left">
                <button
                  type="button"
                  className="toolbar-action-btn"
                  title="Open in new window"
                  aria-label="Open in new window"
                  onClick={handleOpenMessageWindow}
                >
                  <i className="ri-external-link-line" />
                </button>
                <button
                  type="button"
                  className="toolbar-action-btn toolbar-action-btn--danger"
                  title="Delete email"
                  aria-label="Delete email"
                  onClick={handleDeleteMessage}
                >
                  <i className="ri-delete-bin-line" />
                </button>
              </div>
              <div className="toolbar-center" />
              <div className="toolbar-right">
                <i className="ri-reply-line" />
              </div>
            </div>

            <div className="reading-content">
              {(() => {
                const rawSender = String(selectedEmailInfo.sender || 'Unknown');
                const senderMatch = rawSender.match(/^(.*?)\s*<([^>]+)>$/);
                const senderName = (senderMatch?.[1] || rawSender).trim().replace(/^"(.*)"$/, '$1') || 'Unknown';
                const senderEmail = (senderMatch?.[2] || rawSender).trim();
                return (
                  <>
                    <div className="mail-meta-card">
                      <h2 className="mail-meta-card__title">{selectedEmailInfo.subject || '(No Subject)'}</h2>
                      <div className="msg-header">
                        <div className="msg-sender-info">
                          <span className="msg-sender-avatar" aria-hidden="true">
                            <span className="msg-sender-avatar__fallback">
                              {getSenderInitial(senderName)}
                            </span>
                            {selectedEmailInfo?.avatar && (
                              <img
                                src={selectedEmailInfo.avatar}
                                alt=""
                                loading="lazy"
                                referrerPolicy="no-referrer"
                                onError={(e) => {
                                  e.currentTarget.style.display = 'none';
                                }}
                              />
                            )}
                          </span>
                          <div className="msg-names">
                            <div className="msg-name">{senderName}</div>
                            <div className="msg-email">{senderEmail}</div>
                          </div>
                        </div>
                      </div>
                    </div>
                    <div className="mail-body-panel" style={mailBackgroundColor ? { backgroundColor: mailBackgroundColor } : undefined}>
                      <div className={`msg-body ${activeMessageData?.isPlainText ? 'msg-body--plain' : ''}`}>
                        {isLoadingMessage ? (
                          <div style={{ color: '#888', padding: '16px' }}>Loading message...</div>
                        ) : activeMessageData?.html ? (
                          <div dangerouslySetInnerHTML={{ __html: activeMessageData.html }} />
                        ) : (
                          <div style={{ color: '#888', padding: '16px' }}>No content.</div>
                        )}
                      </div>
                    </div>
                  </>
                );
              })()}
            </div>

            <div className="reading-footer">
              <div className="chat-input-wrapper">
                <input
                  type="text"
                  placeholder="Write a reply..."
                  value={replyText}
                  onChange={(e) => setReplyText(e.target.value)}
                  onKeyDown={(e) => e.key === 'Enter' && sendReply()}
                />
                <div className="chat-actions">
                  {isSending ? (
                    <span style={{ fontSize: '12px' }}>Sending...</span>
                  ) : (
                    <i className="ri-send-plane-2-line" onClick={sendReply} style={{ color: '#4e5cf4', cursor: 'pointer' }} />
                  )}
                </div>
              </div>
            </div>
          </>
        )}
      </div>
    </div>
  );

  return (
    <>
      <div className="webmail-stage">
        <p>Webmail</p>
        <h1>Mailbox and message management</h1>
        <p>This layout uses the same page frame as the homepage.</p>
      </div>

      {!isLoggedIn ? (
        <div className="webmail-hero-split">
          <div className="webmail-hero-split__left">{loginForm}</div>
          <div className="webmail-hero-split__right">
            <div className="webmail-info-tile">
              <h3>Login notes</h3>
              <ul className="webmail-info-list">
                <li>Use your IMAP credentials including server and port.</li>
                <li>Your login stays saved in this browser until you click logout.</li>
                <li>After login, your mailbox is loaded automatically.</li>
                <li>Errors are shown directly in the form.</li>
              </ul>
            </div>
          </div>
        </div>
      ) : (
        <div className="webmail-shell-scroll">{webmailWorkspace}</div>
      )}

      {isRestoringSession && (
        <p className="loading-state" style={{ marginTop: '12px' }}>Restoring saved session...</p>
      )}
    </>
  );
}








