import React, { useEffect, useMemo, useRef, useState } from 'react';
import MainLayout from '@/layouts/MainLayout';
import { Head } from '@inertiajs/react';
import EmailNavigationMenu from './components/EmailNavigationMenu';
import IconifyIcon from '@/components/wrappers/IconifyIcon';
import clsx from 'clsx';
import { Button, Card, Col, Form, Row, Spinner, Modal } from 'react-bootstrap';
import ComposeEmailModal, { type Mode as ComposeMode } from './components/ComposeEmailModal';


/* ---------- Types ---------- */

type Thread = {
  id: string;
  subject: string | null;
  from_name: string | null;
  from_email: string | null;
  is_unread: boolean;
  snippet: string | null;
  last_date: string | null;
  message_count: number;
};

type Msg = {
  id: string;
  date: string | null;
  from?: { name: string | null; email: string | null } | null;
  to?: { name: string | null; email: string | null }[];
  cc?: { name: string | null; email: string | null }[];
  bcc?: { name: string | null; email: string | null }[];
  headers?: {
    message_id: string | null;
    in_reply_to: string | null;
    references: string | null;
  } | null;
  is_html?: boolean;
  body_html: string | null;
  body_text: string | null;
  attachments: {
    id?: string | number;
    filename?: string;
    name?: string;
    file_name?: string;
    mime?: string;
    size?: number | null;
    download_url?: string;
    url?: string;
    href?: string;
    link?: string;
    inline_url?: string;
    view_url?: string;
    content_id?: string;
    contentId?: string;
    cid?: string;
    [key: string]: any;
  }[];
};

type ThreadShow = { id: string; subject: string | null; messages: Msg[] };
type Folder = { id: string; name: string; unread?: number };
type ThreadDetail = Thread & {
  is_html?: boolean;
  messages: Msg[];
};

/* ---------- Utils ---------- */

const qs = (o: Record<string, any>) =>
  Object.entries(o)
    .filter(([, v]) => v !== undefined && v !== null && v !== '')
    .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`)
    .join('&');

const sanitizeEmailHtml = (raw: string): string => {
  if (!raw) return '';
  let out = raw;

  // 1) Strip out any <script> tags for safety
  out = out.replace(
    /<\s*script[^>]*>[\s\S]*?<\s*\/\s*script\s*>/gi,
    '',
  );
  out = out.replace(/<\s*script[^>]*\/?>/gi, '');

  // 2) Pull out all <style> blocks (often inside <head>) so they still apply
  const styleBlocks: string[] = [];
  out = out.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, (m) => {
    styleBlocks.push(m);
    return '';
  });

  // 3) Remove outer html/body/head wrapper tags, but NOT their contents
  out = out.replace(/<\/?\s*html[^>]*>/gi, '');
  out = out.replace(/<\/?\s*body[^>]*>/gi, '');
  out = out.replace(/<\/?\s*head[^>]*>/gi, '');

  // 4) Prepend the captured styles so they’re still honored inside our viewer
  if (styleBlocks.length) {
    out = styleBlocks.join('\n') + '\n' + out;
  }

  // 5) Upgrade insecure http image URLs to https so the browser
  // doesn’t block them as mixed content (common for logos/social icons)
  out = out.replace(
    /(<img[^>]+src=["'])http:\/\//gi,
    '$1https://',
  );

  return out;
};

const escapeRegExp = (str: string) =>
  str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  
const normalizeRecipients = (raw: any): string[] => {
  if (!raw) return [];
  if (Array.isArray(raw)) return raw.map(r => typeof r === 'string' ? r : r.email || '').filter(Boolean);
  if (typeof raw === 'string') return raw.split(',').map(s => s.trim());
  return [];
};

const rewriteCidSources = (rawHtml: string | null, attachments?: any[]): string => {
  if (!rawHtml) return '';
  let html = rawHtml;

  const escapeRe = (s: string) =>
    s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

  // 0) Outlook / Office 365 often uses data-emb-src with a real URL and src="cid:..."
  //    Prefer the real URL whenever we see it.
  html = html.replace(
    /<img([^>]*?)data-emb-src=["']([^"']+)["']([^>]*)>/gi,
    (_match, before, realUrl, after) => {
      let tag = `<img${before}${after}>`;
      if (/src=["'][^"']*["']/i.test(tag)) {
        // replace existing src
        tag = tag.replace(/src=["'][^"']*["']/i, `src="${realUrl}"`);
      } else {
        // no src present, inject one
        tag = `<img src="${realUrl}"${before}${after}>`;
      }
      return tag;
    },
  );

  if (!attachments || !attachments.length) return html;

  // Only treat a value as a usable URL if it *looks* like one
  const pickUrl = (att: any): string | null => {
    const candidates = [
      att?.inline_url,
      att?.view_url,
      att?.download_url,
      att?.url,
      att?.href,
      att?.link,
      att?.urls?.inline,
      att?.urls?.view,
      att?.urls?.download,
    ];

    for (const v of candidates) {
      if (!v || typeof v !== 'string') continue;
      const s = v.trim();
      // real URL or data URI
      if (/^https?:\/\//i.test(s)) return s;
      if (s.startsWith('data:')) return s;
      // absolute path that isn't just "/2", "/3", etc. (those are numeric part IDs, not URLs)
      if (s.startsWith('/') && !/^\/\d+(\?.*)?$/.test(s)) return s;
    }

    return null;
  };

  attachments.forEach((att) => {
    if (!att) return;

    const url = pickUrl(att);
    if (!url) return; // don't rewrite to "2", "3", etc.

    // Content-ID variants
    let cidRaw: any =
      att.content_id ??
      att.contentId ??
      att['contentid'] ??
      att['ContentId'] ??
      att['Content-ID'] ??
      att['content-id'] ??
      att.cid ??
      att.contentID ??
      null;

    if (typeof att.id === 'string' && att.id.startsWith('cid:') && !cidRaw) {
      cidRaw = att.id.slice(4);
    }

    const filename: string | null =
      (att.filename ?? att.name ?? att.file_name ?? null) &&
      String(att.filename ?? att.name ?? att.file_name);

    const filenameNoExt = filename
      ? filename.replace(/\.[a-z0-9]+$/i, '')
      : null;

    // --- 1) Direct cid match: src="cid:actual-cid" ---
    if (cidRaw) {
      const cid = String(cidRaw).replace(/^<|>$/g, '');
      if (cid) {
        const reCidExact = new RegExp(
          `src=["']cid:${escapeRe(cid)}["']`,
          'gi',
        );
        html = html.replace(reCidExact, `src="${url}"`);

        // Outlook-style: src="cid:image001.png@01D..."
        if (filename) {
          const reCidContains = new RegExp(
            `src=["']cid:[^"']*${escapeRe(filename)}["']`,
            'gi',
          );
          html = html.replace(reCidContains, `src="${url}"`);
        }
      }
    }

    // --- 2) Fallback: cid contains filename without extension ---
    if (filenameNoExt) {
      const reCidContainsNoExt = new RegExp(
        `src=["']cid:[^"']*${escapeRe(filenameNoExt)}["']`,
        'gi',
      );
      html = html.replace(reCidContainsNoExt, `src="${url}"`);
    }

    // --- 3) FINAL fallback: any src="...filename..." (no cid required) ---
    if (filename) {
      const rePlainSrc = new RegExp(
        `src=["'][^"']*${escapeRe(filename)}["']`,
        'gi',
      );
      html = html.replace(rePlainSrc, `src="${url}"`);
    }
  });

  return html;
};

const fmtWhen = (iso?: string | null) => {
  if (!iso) return '';
  try {
    const d = new Date(iso);
    const now = new Date();
    return d.toDateString() === now.toDateString()
      ? d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
      : d.toLocaleDateString([], { month: 'short', day: '2-digit' });
  } catch {
    return '';
  }
};

  const asArray = (value: any): any[] => {
    if (!value) return [];
    return Array.isArray(value) ? value : [value];
  };

  const buildAddressList = (items: any[]): string => {
    return items
      .map((r) => {
        if (!r) return '';
        if (typeof r === 'string') return r.trim();

        const email =
          r.email || r.address || r.mail || r.value || r.email_address || '';
        const name = r.name || r.display_name || r.full_name || r.label || '';

        if (!email) return '';
        return name ? `${name} <${email}>` : email;
      })
      .filter(Boolean)
      .join('; ');
  };

const fmtWhenFull = (iso?: string | null) => {
  if (!iso) return '';
  try {
    const d = new Date(iso);
    return d.toLocaleString();
  } catch {
    return '';
  }
};

const senderText = (t: Thread) => t.from_name || t.from_email || '—';

const extractNameEmail = (
  t: Thread,
): { name: string; email: string } => {
  const rawName = (t.from_name || '').trim();
  const rawEmail = (t.from_email || '').trim();

  let name = rawName;
  let email = rawEmail;

  const re = /^(.+?)\s*<([^>]+)>$/;

  // Case 1: "Blinkist <hello@...>" stored in from_name
  if (rawName && !rawEmail) {
    const m = rawName.match(re);
    if (m) {
      name = m[1].trim();
      email = m[2].trim();
    }
  }

  // Case 2: "Blinkist <hello@...>" stored in from_email
  if (!name && rawEmail) {
    const m = rawEmail.match(re);
    if (m) {
      name = m[1].trim();
      email = m[2].trim();
    }
  }

  // If name still contains the email, strip it out
  if (name && email && name.includes(email)) {
    name = name.replace(email, '').replace(/[<>]/g, '').trim();
  }

  return {
    name: name || email || 'Unknown',
    email,
  };
};

// avoid subject + snippet duplication
const cleanSnippet = (subject: string | null, snippet: string | null): string => {
  if (!snippet) return '';
  if (!subject) return snippet.trim();

  const sNorm = subject.trim().toLowerCase();
  const snNorm = snippet.trim().toLowerCase();

  if (!sNorm || sNorm === snNorm) return '';

  if (snNorm.startsWith(sNorm)) {
    return snippet.slice(subject.length).replace(/^[-–—:\s]+/, '').trim();
  }

  return snippet.trim();
};

// Now that the backend sends correct mailbox IDs (e.g. "INBOX.Sent"),
// just pass them through.
const folderKeyForServer = (raw: string): string => String(raw || 'INBOX');

// Normalise raw thread objects from the backend into our Thread shape
const normalizeThread = (raw: any): Thread => {
  const id =
    raw.id ??
    raw.thread_id ??
    raw.uid ??
    raw.message_id ??
    raw.MessageId;

  const subject = raw.subject ?? raw.Subject ?? null;

  const from_name =
    raw.from_name ??
    raw.fromName ??
    raw.from?.name ??
    null;

  const from_email =
    raw.from_email ??
    raw.fromEmail ??
    raw.from_address ??
    raw.from?.email ??
    null;

  const unreadRaw =
    raw.is_unread ??
    raw.unread ??
    raw.UnRead ??
    raw.unseen ??
    raw.Unseen ??
    raw.unread_count ??
    raw.unseen_count;

  let is_unread: boolean;
  if (typeof unreadRaw === 'boolean') {
    is_unread = unreadRaw;
  } else if (
    unreadRaw !== undefined &&
    unreadRaw !== null &&
    Number.isFinite(Number(unreadRaw))
  ) {
    is_unread = Number(unreadRaw) > 0;
  } else {
    is_unread = true; // fallback
  }

  const last_date =
    raw.last_date ??
    raw.lastDate ??
    raw.date ??
    raw.internalDate ??
    raw.received ??
    null;

  const message_count = Number(
    raw.message_count ?? raw.messages ?? raw.count ?? 0,
  );

  const snippet =
    raw.snippet ??
    raw.preview ??
    raw.body_preview ??
    raw.summary ??
    '';

  return {
    id: String(id),
    subject,
    from_name,
    from_email,
    is_unread,
    snippet,
    last_date,
    message_count,
  };
};

/* ---------- Email body iframe component ---------- */

type EmailBodyProps = {
  html?: string | null;
  text?: string | null;
};

/**
 * Renders a single email body inside an <iframe> so that
 * the email's own CSS/layout is isolated from the CRM UI.
 */
const EmailBody: React.FC<EmailBodyProps> = ({ html, text }) => {
  const iframeRef = useRef<HTMLIFrameElement | null>(null);
  const [height, setHeight] = useState<number>(400);

  const processedHtml = useMemo(() => {
    if (!html) return null;
    return html;
  }, [html]);

  useEffect(() => {
    if (!iframeRef.current || !processedHtml) return;

    const iframe = iframeRef.current;
    const doc = iframe.contentDocument || iframe.contentWindow?.document;
    if (!doc) return;

    const fullHtml = `
      <!DOCTYPE html>
      <html>
        <head>
          <meta charset="utf-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1" />
        </head>
        <body>
          ${processedHtml}
        </body>
      </html>
    `;

    doc.open();
    doc.write(fullHtml);
    doc.close();

    const resize = () => {
      const body = doc.body;
      if (!body) return;
      const newHeight = body.scrollHeight || 400;
      setHeight(newHeight);
    };

    iframe.onload = resize;
    setTimeout(resize, 150);
  }, [processedHtml]);

  // Plain-text fallback if no HTML part
  if (!processedHtml) {
    if (!text) {
      return <div className="gd-email-body-inner text-muted">No content</div>;
    }

    return (
      <div className="gd-email-body-inner">
        <pre className="mb-0" style={{ whiteSpace: 'pre-wrap', fontSize: '0.95rem' }}>
          {text}
        </pre>
      </div>
    );
  }

  // HTML branch (iframe)
  return (
    <div className="gd-email-body-inner">
      <iframe
        ref={iframeRef}
        title="Email body"
        style={{
          width: '100%',
          border: 'none',
          height,
          overflow: 'hidden',
          background: 'transparent',
        }}
      />
    </div>
  );
};

// Format a list of recipients into: "Name <email>, Name2 <email2>"
const formatRecipientList = (
  list?: { name: string | null; email: string | null }[] | null,
): string => {
  if (!list || !list.length) return '';
  return list
    .map((r) => {
      const name = (r.name || '').trim();
      const email = (r.email || '').trim();
      if (name && email) return `${name} <${email}>`;
      return email || name;
    })
    .filter(Boolean)
    .join(', ');
};

// Remove duplicates by email/name
const dedupeRecipients = (
  list: { name: string | null; email: string | null }[],
) => {
  const seen = new Set<string>();
  const out: { name: string | null; email: string | null }[] = [];

  for (const r of list) {
    const key = (r.email || r.name || '').toLowerCase();
    if (!key || seen.has(key)) continue;
    seen.add(key);
    out.push(r);
  }
  return out;
};

/* ---------- Component ---------- */

export default function InboxPage() {
  // threads + list state
  
  const page = usePage<{ props: InboxPageProps }>() as any;
  const serverThreads = (page.props?.threads ?? []) as ThreadRow[];
  const serverActiveThread = (page.props?.activeThread ?? null) as ActiveThread | null;  
  const [threads, setThreads] = useState<Thread[]>([]);
  const [loading, setLoading] = useState<boolean>(false);
  const [error, setError] = useState<string | null>(null);

  const [activeId, setActiveId] = useState<string | null>(null);
  const activeIdRef = useRef<string | null>(null);
  const [detail, setDetail] = useState<ThreadShow | null>(null);
  const [loadingDetail, setLoadingDetail] = useState(false);

  const [q, setQ] = useState('');
  const [offset, setOffset] = useState(0);
  const [hasMore, setHasMore] = useState(true);
  const PAGE_SIZE = 50;

  // list filter: all vs unread
  const [filterMode, setFilterMode] = useState<'all' | 'unread'>('all');

  // raw IMAP mailbox id/path, e.g. "INBOX", "Drafts", "[Gmail]/Spam", etc.
  const [activeFolder, setActiveFolder] = useState<string>('INBOX');
  const [folders, setFolders] = useState<Folder[]>([]);
  const [isRefreshing, setIsRefreshing] = useState(false);

  // compose modal
  // compose modal
  const [composeShow, setComposeShow] = useState(false);
  const [composeMode, setComposeMode] = useState<ComposeMode>('new');
  const [showMoveModal, setShowMoveModal] = useState(false);
  const [isMoving, setIsMoving] = useState(false);

    const [composeInit, setComposeInit] = useState<{
      to?: string;
      cc?: string;
      subject?: string;
      body?: string;
      quotedHtml?: string | null;
    }>({});

  const listWrapRef = useRef<HTMLDivElement | null>(null);

  // --- resizable divider between list and details ---
  const [listWidth, setListWidth] = useState<number>(() => {
    if (typeof window !== 'undefined') {
      const stored = window.localStorage.getItem('gd_email_list_width');
      const n = stored ? Number(stored) : NaN;
      if (Number.isFinite(n) && n >= 25 && n <= 70) {
        return n;
      }
    }
    return 40; // default
  }); // % of right-hand area
  const panesContainerRef = useRef<HTMLDivElement | null>(null);
  const dragInfoRef = useRef<{ startX: number; startWidth: number } | null>(null);

  const handleDragMove = (e: MouseEvent) => {
    const info = dragInfoRef.current;
    if (!info || !panesContainerRef.current) return;

    const bounds = panesContainerRef.current.getBoundingClientRect();
    if (!bounds.width) return;

    const deltaPx = e.clientX - info.startX;
    const deltaPct = (deltaPx / bounds.width) * 100;

    let next = info.startWidth + deltaPct;
    // clamp between 25% and 70% so neither pane gets too tiny
    next = Math.max(25, Math.min(70, next));
    setListWidth(next);
  };

  const handleDragEnd = () => {
    dragInfoRef.current = null;
    window.removeEventListener('mousemove', handleDragMove);
    window.removeEventListener('mouseup', handleDragEnd);
  };

  const handleDragStart = (e: React.MouseEvent<HTMLDivElement>) => {
    if (!panesContainerRef.current) return;

    dragInfoRef.current = {
      startX: e.clientX,
      startWidth: listWidth,
    };

    window.addEventListener('mousemove', handleDragMove);
    window.addEventListener('mouseup', handleDragEnd);
    e.preventDefault();
  };

  // clean up if component unmounts
  useEffect(() => {
    return () => {
      window.removeEventListener('mousemove', handleDragMove);
      window.removeEventListener('mouseup', handleDragEnd);
    };
  }, []);
  // Persist splitter width across page reloads
  useEffect(() => {
    if (typeof window !== 'undefined') {
      window.localStorage.setItem(
        'gd_email_list_width',
        String(listWidth),
      );
    }
  }, [listWidth]);

  /* --------- helper to fetch folders so we can reuse for refresh --------- */
  const fetchFolders = () => {
    fetch('/email/folders', {
      credentials: 'same-origin',
      headers: { 'X-Requested-With': 'XMLHttpRequest' },
    })
      .then((r) => (r.ok ? r.json() : null))
      .then((data) => {
        console.log('email.folders raw:', data);

        let list: any[] = [];

        if (Array.isArray(data)) {
          list = data;
        } else if (Array.isArray((data as any)?.folders)) {
          list = (data as any).folders;
        } else if (data && typeof data === 'object') {
          const maybeFolders = (data as any).folders ?? data;
          if (maybeFolders && typeof maybeFolders === 'object') {
            const entries = Object.entries(maybeFolders);
            if (entries.length) {
              list = entries.map(([id, info]) => ({
                id,
                ...(info as any),
              }));
            }
          }
        }

        if (!list.length) {
          throw new Error('empty folders');
        }

        const normalizeCount = (f: any): number | undefined => {
          if (!f || typeof f !== 'object') return undefined;

          const entries = Object.entries(f);

          const pick = (...needles: string[]): any => {
            for (const [key, value] of entries) {
              const lk = key.toLowerCase();
              if (needles.some((n) => lk === n || lk.includes(n))) {
                return value;
              }
            }
            return undefined;
          };

          const value =
            pick('unread', 'unseen') ??
            pick('messages', 'message', 'total', 'cnt', 'count', 'size');

          const n = Number(value);
          return Number.isFinite(n) ? n : undefined;
        };

        setFolders(
          list.map((f: any) => ({
            id: String(f.id ?? f.path ?? f.mailbox ?? f.name),
            name: String(f.name ?? f.display ?? f.id ?? f.path ?? ''),
            unread: normalizeCount(f),
          })),
        );
      })
      .catch((err) => {
        console.error('email.folders error:', err);
        setFolders([
          { id: 'INBOX', name: 'Inbox' },
          { id: 'Drafts', name: 'Drafts' },
          { id: 'Sent', name: 'Sent' },
          { id: 'Junk', name: 'Junk' },
          { id: 'Trash', name: 'Trash' },
          { id: 'Archive', name: 'Archive' },
        ]);
      });
  };

  /* --------- initial folders (with robust parsing + counts) --------- */
  useEffect(() => {
    fetchFolders();
  }, []);

  const loadThreads = async (reset: boolean = false, folderOverride?: string) => {
    try {
      setLoading(true);
      setError(null);

      const folder = (folderOverride || activeFolder || 'INBOX').toString();
      const nextOffset = reset ? 0 : offset;

      const params = {
        folder,
        offset: nextOffset,
        limit: PAGE_SIZE,
        days: 365,
      };

      const query = qs(params);

      const res = await fetch(`/api/email/threads?${query}`, {
        credentials: 'same-origin',
        headers: { Accept: 'application/json' },
      });

      if (!res.ok) {
        throw new Error(`Failed to load messages (${res.status})`);
      }

      const data = await res.json();

      if (!Array.isArray(data)) {
        throw new Error('Invalid response from /api/email/threads');
      }

      const normalized = data.map((raw: any) => normalizeThread(raw));

      if (reset) {
        setThreads(normalized);
        setOffset(normalized.length);
      } else {
        setThreads((prev) => [...prev, ...normalized]);
        setOffset(nextOffset + normalized.length);
      }

      setHasMore(normalized.length >= PAGE_SIZE);

      // Only auto-select the first thread if we don't already have one
      if (!activeIdRef.current && normalized.length > 0) {
        setActiveId(normalized[0].id);
      }
    } catch (e: any) {
      console.error('loadThreads error', e);
      setError(e?.message || 'Failed to load messages');
      setThreads([]);
      setHasMore(false);
    } finally {
      setLoading(false);
    }
  };

  /* first load */
  useEffect(() => {
    loadThreads(true, activeFolder);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  /* reload when folder changes */
  useEffect(() => {
    loadThreads(true, activeFolder);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [activeFolder]);

  /* auto-refresh every 2 minutes */
  useEffect(() => {
    const id = setInterval(() => {
      loadThreads(true);
      fetchFolders(); // also refresh folder unread counts
    }, 120_000);
    return () => clearInterval(id);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const doSearch = () => {
    setOffset(0);
    // search is client-side for now (on the loaded slice)
  };

  const loadMore = () => {
    if (!hasMore || loading) return;
    loadThreads(false);
  };

  useEffect(() => {
    activeIdRef.current = activeId;
  }, [activeId]);

  /* --------- open / mark read --------- */
  useEffect(() => {
    if (!activeId) return;

    const tokenEl = document.querySelector(
      'meta[name="csrf-token"]'
    ) as HTMLMetaElement | null;
    const csrf = tokenEl?.content || '';

    // Fire-and-forget server mark-read
    fetch(`/email/messages/${encodeURIComponent(activeId)}/read`, {
      method: 'POST',
      credentials: 'same-origin',
      headers: {
        'X-Requested-With': 'XMLHttpRequest',
        'X-CSRF-TOKEN': csrf,
      },
    }).catch(() => {});

    // Was this thread unread before we touched it?
    const target = threads.find((t) => t.id === activeId);
    const wasUnread = !!target?.is_unread;

    // Mark as read in local slice
    setThreads((prev) =>
      prev.map((t) =>
        t.id === activeId ? { ...t, is_unread: false } : t
      ),
    );

    // Only decrement folder unread count if we just transitioned
    // from unread -> read
    if (wasUnread) {
      setFolders((prev) =>
        prev.map((f) => {
          const key = folderKeyForServer(f.id || f.name);
          if (key !== activeFolder) return f;

          const current =
            typeof f.unread === 'number' ? f.unread : 0;
          return { ...f, unread: Math.max(0, current - 1) };
        }),
      );
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [activeId, activeFolder]);

  /* --------- load details --------- */
  useEffect(() => {
    if (!activeId) {
      setDetail(null);
      return;
    }
    setLoadingDetail(true);

  /* --------- filtered list --------- */
  const filtered = useMemo(() => {
    const term = q.trim().toLowerCase();

    // base: all threads or only unread
    let base = threads;
    if (filterMode === 'unread') {
      base = base.filter((t) => t.is_unread);
    }

    if (!term) return base;

    return base.filter(
      (t) =>
        (t.subject || '').toLowerCase().includes(term) ||
        senderText(t).toLowerCase().includes(term) ||
        (t.snippet || '').toLowerCase().includes(term),
    );
  }, [threads, q, filterMode]);

  // total unread in current slice
  const unreadCount = useMemo(
    () => threads.filter((t) => t.is_unread).length,
    [threads],
  );

    /* --------- reply / reply-all / forward --------- */
    
    const buildQuotedHtml = (m: Msg, subj: string) => {
      const clean = sanitizeEmailHtml(m.body_html || '');
      const fallback = (m.body_text || '')
        .split('\n')
        .map((l) => `<p>&gt; ${l.replace(/</g, '&lt;')}</p>`)
        .join('');
    
      return clean
        ? `
    <hr/>
    <div style="border-left:3px solid #ccc;padding-left:8px;margin-top:12px">
      <p><b>On ${m.date ? new Date(m.date).toLocaleString() : ''}, ${
            m.from?.name || m.from?.email || 'someone'
          } wrote:</b></p>
      ${clean}
    </div>`
        : `
    <hr/>
    <div style="border-left:3px solid #ccc;padding-left:8px;margin-top:12px">${fallback}</div>`;
    };
    
  const openReply = () => {
    if (!detail || !detail.messages.length) return;

    const last = detail.messages[detail.messages.length - 1];
    const from = last.from;

    const toLabel =
      from?.email && from?.name
        ? `${from.name} <${from.email}>`
        : from?.email || '';

    const subject =
      (detail.subject || '').toLowerCase().startsWith('re:')
        ? detail.subject || ''
        : `Re: ${detail.subject || ''}`;

    setComposeMode('reply');
    setComposeInit({
      to: toLabel,
      cc: '',
      subject,
      body: '',
      quotedHtml: last.body_html || last.body_text || '',
    });
    setComposeShow(true);
  };

  const openReplyAll = () => {
    if (!detail || !detail.messages.length) return;

    const last = detail.messages[detail.messages.length - 1];
    const from = last.from;

    const toLabel =
      from?.email && from?.name
        ? `${from.name} <${from.email}>`
        : from?.email || '';

    const ccList = [
      ...asArray(last.to),
      ...asArray(last.cc),
    ];

    const ccLabel = buildAddressList(ccList);

    const subject =
      (detail.subject || '').toLowerCase().startsWith('re:')
        ? detail.subject || ''
        : `Re: ${detail.subject || ''}`;

    setComposeMode('reply-all');
    setComposeInit({
      to: toLabel,
      cc: ccLabel,
      subject,
      body: '',
      quotedHtml: last.body_html || last.body_text || '',
    });
    setComposeShow(true);
  };

  const openForward = () => {
    if (!detail || !detail.messages.length) return;

    const last = detail.messages[detail.messages.length - 1];

    const subject =
      (detail.subject || '').toLowerCase().startsWith('fwd:')
        ? detail.subject || ''
        : `Fwd: ${detail.subject || ''}`;

    setComposeMode('forward');
    setComposeInit({
      to: '',
      cc: '',
      subject,
      body: '',
      quotedHtml: last.body_html || last.body_text || '',
    });
    setComposeShow(true);
  };
  
  /* --------- after send: close modal + refresh list --------- */
  const handleSent = () => {
    setComposeShow(false);
    setOffset(0);
    // reload the current folder and folder counts
    loadThreads(true, activeFolder);
    fetchFolders();
  };


  /* --------- delete --------- */
    const del = async () => {
      if (!activeId) return;
      if (!confirm('Delete this message?')) return;
    
      // Grab CSRF token from <meta name="csrf-token">
      const tokenEl = document.querySelector(
        'meta[name="csrf-token"]'
      ) as HTMLMetaElement | null;
      const csrf = tokenEl?.content || '';
    
      try {
        const res = await fetch('/api/email/delete', {
          method: 'POST',
          credentials: 'same-origin',
          headers: {
            'Content-Type': 'application/json',
            'X-Requested-With': 'XMLHttpRequest',
            'X-CSRF-TOKEN': csrf,
          },
          body: JSON.stringify({
            id: activeId,
            folder: activeFolder, // adjust name if your backend expects "mailbox"
          }),
        });
    
        if (!res.ok) {
          let extra = '';
          try {
            const txt = await res.text();
            if (txt) extra = `: ${txt.slice(0, 200)}`;
          } catch {
            // ignore
          }
          throw new Error(`Delete failed (${res.status})${extra}`);
        }
    
        // Remove deleted thread from list + update selection
        const next = threads.filter((t) => t.id !== activeId);
        setThreads(next);
        setActiveId(next[0]?.id ?? null);
        setDetail(null);
      } catch (e: any) {
        console.error('delete error', e);
        alert(e?.message || 'Delete failed');
      }
    };


  /* --------- move to another folder --------- */
  const handleMoveMessage = async (targetFolderId: string) => {
    if (!activeId) return;

    // Defensive: don’t let user click again while moving
    if (isMoving) return;

    setIsMoving(true);

    // Grab CSRF token (same pattern as mark-read effect)
    const tokenEl = document.querySelector(
      'meta[name="csrf-token"]'
    ) as HTMLMetaElement | null;
    const csrf = tokenEl?.content || '';

    // Normalize to the server’s mailbox key
    const targetMailbox = folderKeyForServer(targetFolderId);

    try {
      const res = await fetch('/api/email/move', {
        method: 'POST',
        credentials: 'same-origin',
        headers: {
          'Content-Type': 'application/json',
          'X-Requested-With': 'XMLHttpRequest',
          'X-CSRF-TOKEN': csrf,
        },
        body: JSON.stringify({
          id: activeId,
          from: activeFolder,    // current mailbox
          to: targetMailbox,     // destination mailbox
        }),
      });

      if (!res.ok) {
        let extra = '';
        try {
          const txt = await res.text();
          if (txt) extra = `: ${txt.slice(0, 200)}`;
        } catch {
          // ignore
        }
        throw new Error(`Move failed (${res.status})${extra}`);
      }

      // Optimistic UI: clear selection + remove from current list
      setThreads((prev) => prev.filter((t) => t.id !== activeId));
      setActiveId(null);
      setDetail(null);

      // Optional: reload threads + folder counts for a fully fresh view
      await Promise.all([
        loadThreads(true, activeFolder),
        (async () => fetchFolders())(),
      ]);
    } catch (e: any) {
      console.error('handleMoveMessage error', e);
      alert(e?.message || 'Move failed');
    } finally {
      setIsMoving(false);
      setShowMoveModal(false);
    }
  };
  
return (
        <MainLayout title="Inbox">
          <div className="gd-page-index gd-inbox-page gd-account-show-page">

      <Head title="Inbox" />
        {/* Main vertical layout with scrolling panes */}
        <div className="inbox-shell">
          {/* ---- Title + search bar ---- */}
          <Row>
            <Col xs={12}>
              <div className="page-title-head d-flex align-items-sm-center flex-sm-row flex-column">
                <div className="flex-grow-1">
                  <h4 className="fs-18 fw-semibold m-0">Inbox</h4>
                </div>

                <div className="mt-3 mt-sm-0">
                  <form
                    onSubmit={(e) => {
                      e.preventDefault();
                      doSearch();
                    }}
                    className="d-flex gap-2 align-items-center header-search"
                  >
                    <Form.Control
                      placeholder="Search emails"
                      value={q}
                      onChange={(e) => setQ(e.target.value)}
                      className="gd-inbox-top-search"
                    />

                    <button
                      type="submit"
                      className="btn btn-sm btn-gd-primary"
                    >
                      Search
                    </button>
                    
                    <button
                      type="button"
                      className="btn btn-sm btn-gd-secondary"
                      onClick={() => {
                        setQ('');
                        setOffset(0);
                      }}
                    >
                      Clear
                    </button>
                  </form>
                </div>
              </div>
            </Col>
          </Row>
            
        {/* ---- Main inbox header (navy) ---- */}
        <div className="account-header-bar gd-inbox-header-bar">
          <div className="d-flex align-items-center justify-content-between gap-2 w-100">
            {/* left: icon + title */}
            <div className="d-flex align-items-center gap-2 min-w-0">
              <IconifyIcon icon="tabler:mail" className="gd-inbox-header-icon" />
              <div className="account-show-title text-white text-truncate">Inbox</div>
            </div>
        
            {/* right: icon-only actions */}
            <div className="d-flex align-items-center gap-2 flex-nowrap ms-auto">
              <button
                type="button"
                className="btn-icon"
                title="Refresh"
                onClick={async () => {
                  setIsRefreshing(true);
                  setOffset(0);
                  try {
                    await loadThreads(true, activeFolder);
                    fetchFolders();
                  } finally {
                    setIsRefreshing(false);
                  }
                }}
                disabled={isRefreshing}
              >
                {isRefreshing ? <Spinner size="sm" /> : <IconifyIcon icon="tabler:refresh" />}
              </button>
        
              <button
                type="button"
                className="btn-icon"
                title="Settings"
                onClick={() => alert('Settings coming next.')}
              >
                <IconifyIcon icon="tabler:settings" />
              </button>
            </div>
          </div>
        </div>

            {/* Grey sub row (50px strip like other index pages) */}
            <div className="gd-index-strip">
              <div className="d-flex align-items-center justify-content-between">
                <div className="d-flex align-items-center gap-2">
                  <span className="gd-index-strip-title">Threads</span>
                  <span className="gd-index-strip-meta">({threads?.length ?? 0})</span>
                </div>
                <span className="gd-index-strip-right">Preview</span>
              </div>
            </div>


              <Card className="gd-list-card gd-inbox-card shadow-sm border-0">
            <Card.Body className="p-0">
              <Row className="g-0 gd-inbox-main-row">
                {/* Left: folders */}
                <Col md={3} lg={2} className="border-end gd-inbox-folders-col">
                    <EmailNavigationMenu
                      active={activeFolder}
                      folders={folders}
                      onSelectFolder={(mailboxId) => {
                        const serverFolder = folderKeyForServer(mailboxId);
                        setActiveFolder(serverFolder);
                        setOffset(0);
                        setThreads([]);
                        setActiveId(null);
                        loadThreads(true, serverFolder);
                      }}
                      onCompose={() => {
                        setComposeMode('new');
                        setComposeInit({
                          to: '',
                          subject: '',
                          body: '',
                          quotedHtml: '',
                        });
                        setComposeShow(true);
                      }}
                      isRefreshing={isRefreshing}
                      onRefresh={async () => {
                        setIsRefreshing(true);
                        setOffset(0);
                        try {
                          await loadThreads(true, activeFolder);
                          fetchFolders();
                        } finally {
                          setIsRefreshing(false);
                        }
                      }}
                    />
                </Col>

                {/* Right side: list + resizer + details */}
                <Col md={9} lg={10} className="p-0 gd-inbox-right-col">
                  <div
                    ref={panesContainerRef}
                    className="d-flex h-100"
                    style={{ minHeight: 0 }}
                  >
                    {/* Subject list */}
                    <div
                      ref={listWrapRef}
                      className="p-2 pane border-end"
                      style={{
                        flexBasis: `${listWidth}%`,
                        maxWidth: `${listWidth}%`,
                        minWidth: 0,
                      }}
                    >
                      {/* header is always visible so All/Unread is usable even with 0 messages */}
                      <div className="inbox-thread-header d-flex align-items-center gap-2">
                        <div
                          className="text-uppercase fw-semibold inbox-thread-header-title"
                          style={{ fontSize: '0.9rem', padding: '0.15rem 0' }}
                        >
                          Subject
                        </div>

                        <div className="ms-auto btn-group btn-group-sm">
                          <button
                            type="button"
                            className={clsx('btn btn-inbox-filter', {
                              active: filterMode === 'all',
                            })}
                            onClick={() => setFilterMode('all')}
                          >
                            All
                          </button>
                          <button
                            type="button"
                            className={clsx('btn btn-inbox-filter', {
                              active: filterMode === 'unread',
                            })}
                            onClick={() => setFilterMode('unread')}
                          >
                            Unread{unreadCount ? ` (${unreadCount})` : ''}
                          </button>
                        </div>
                      </div>

                      {loading && !threads.length ? (
                        <div className="p-3 text-center">
                          <Spinner size="sm" /> Loading
                        </div>
                      ) : error ? (
                        <div className="p-3 text-danger">Error: {error}</div>
                      ) : filtered.length === 0 ? (
                        <div className="p-3 text-muted small">
                          No messages in this view.
                        </div>
                      ) : (
                        <>
                          {filtered.map((t) => {
                            const selected = activeId === t.id;

                            const rawWhen =
                              (t.last_date as string | null) ||
                              ((t as any).date as string | null) ||
                              ((t as any).internal_date as string | null) ||
                              ((t as any).created_at as string | null) ||
                              null;

                            const whenShort = fmtWhen(rawWhen);

                            const { name, email } = extractNameEmail(t);

                            const subjectText = (t.subject || '(no subject)').trim();
                            const snippet = cleanSnippet(subjectText, t.snippet || '');

                            return (
                              <div
                                key={t.id}
                                className={clsx(
                                  'inbox-thread-row cursor-pointer row-hover',
                                  selected && 'table-active',
                                )}
                                onClick={() => setActiveId(t.id)}
                              >
                                {/* Row 1 — Sender name + time */}
                                <div className="d-flex justify-content-between align-items-center mb-1">
                                  <div
                                    className={clsx(
                                      'text-truncate',
                                      t.is_unread ? 'fw-semibold' : 'fw-normal',
                                    )}
                                    style={{ fontSize: '0.95rem' }}
                                  >
                                    {name || 'Unknown'}
                                  </div>

                                  {whenShort && (
                                    <div className="text-muted small flex-shrink-0 ms-2">
                                      {whenShort}
                                    </div>
                                  )}
                                </div>

                                {/* Row 2 — Email address */}
                                {email && (
                                  <div
                                    className="text-muted text-truncate"
                                    style={{ fontSize: '0.80rem', marginTop: '-4px' }}
                                  >
                                    {email}
                                  </div>
                                )}

                                {/* Row 3 — Subject + snippet */}
                                <div
                                  className={clsx(
                                    'text-truncate',
                                    t.is_unread ? 'fw-semibold text-dark' : 'text-muted',
                                  )}
                                  style={{
                                    fontSize: '0.82rem',
                                    marginTop: email ? '2px' : '0',
                                  }}
                                >
                                  {subjectText || '(no subject)'}
                                  {snippet && (
                                    <>
                                      {' — '}
                                      <span className="text-muted">{snippet}</span>
                                    </>
                                  )}
                                </div>
                              </div>
                            );
                          })}

                          {hasMore && !loading && (
                            <div className="p-2 text-center">
                              <Button
                                size="sm"
                                variant="outline-primary"
                                onClick={loadMore}
                              >
                                Load more
                              </Button>
                            </div>
                          )}
                        </>
                      )}
                    </div>

                    {/* Resizer */}
                    <div className="inbox-resizer" onMouseDown={handleDragStart} />

                    {/* Message preview */}
                    <div
                      className="p-3 pane"
                      style={{ flex: 1, minWidth: 0 }}
                    >
                      {!activeId ? (
                        <div className="text-muted">Choose a thread to view details.</div>
                      ) : loadingDetail ? (
                        <div>
                          <Spinner size="sm" /> Loading
                        </div>
                      ) : !detail ? (
                        <div className="text-muted">No details.</div>
                      ) : (
                        <>
                          {/* Header: subject + actions */}
                          <div className="inbox-detail-header border-bottom mb-3 bg-white">
                            <div className="d-flex justify-content-between align-items-center gap-2">
                              <div className="inbox-detail-subject text-truncate">
                                {detail.subject || '(no subject)'}
                              </div>

                              <div className="inbox-action-icons d-flex align-items-center gap-2">
                                {/* Reply */}
                                <div
                                  className="icon-btn"
                                  title="Reply"
                                  onClick={openReply}
                                >
                                  <IconifyIcon icon="solar:reply-outline" />
                                </div>

                                {/* Reply all */}
                                <div
                                  className="icon-btn"
                                  title="Reply all"
                                  onClick={openReplyAll}
                                >
                                  <IconifyIcon icon="mdi:reply-all-outline" />
                                </div>

                                {/* Forward */}
                                <div
                                  className="icon-btn"
                                  title="Forward"
                                  onClick={openForward}
                                >
                                  <IconifyIcon icon="solar:forward-outline" />
                                </div>

                                {/* Move */}
                                <div
                                  className="icon-btn"
                                  title="Move"
                                  onClick={() => setShowMoveModal(true)}
                                >
                                  <IconifyIcon icon="solar:folder-linear" />
                                </div>

                                {/* Delete */}
                                <div
                                  className="icon-btn"
                                  title="Delete"
                                  onClick={del}
                                >
                                  <IconifyIcon icon="solar:trash-bin-minimalistic-outline" />
                                </div>
                              </div>
                            </div>
                          </div>

                          {/* Messages in this thread */}
                          {detail.messages.map((m) => (
                            <div key={m.id} className="mb-4 pb-3 border-bottom">
                              <div className="mb-2">
                                {/* From */}
                                <div
                                  className="fw-semibold email-meta"
                                  style={{ fontSize: '1.05rem', color: '#013254' }}
                                >
                                  {m.from?.name || m.from?.email || 'Unknown sender'}
                                  {m.from?.email && (
                                    <span
                                      className="email-meta-muted ms-2"
                                      style={{ fontSize: '0.95rem' }}
                                    >
                                      {m.from.email}
                                    </span>
                                  )}
                                </div>

                                {/* To / Cc / Bcc */}
                                {formatRecipientList(m.to) && (
                                  <div className="email-meta-muted">
                                    <strong>To:</strong> {formatRecipientList(m.to)}
                                  </div>
                                )}
                                {formatRecipientList(m.cc) && (
                                  <div className="email-meta-muted">
                                    <strong>Cc:</strong> {formatRecipientList(m.cc)}
                                  </div>
                                )}
                                {formatRecipientList(m.bcc) && (
                                  <div className="email-meta-muted">
                                    <strong>Bcc:</strong> {formatRecipientList(m.bcc)}
                                  </div>
                                )}

                                {/* Date/time */}
                                <div className="email-meta-muted mt-1">
                                  {fmtWhenFull(m.date)}
                                </div>
                              </div>

                              {/* Body */}
                              <div className="gd-email-body">
                                <EmailBody
                                  html={
                                    m.body_html
                                      ? sanitizeEmailHtml(
                                          rewriteCidSources(m.body_html, m.attachments)
                                        )
                                      : null
                                  }
                                  text={m.body_text || ''}
                                />
                              </div>

                              {/* Attachments */}
                              {m.attachments && m.attachments.length > 0 && (
                                <div className="mt-3">
                                  <div
                                    className="fw-semibold mb-1"
                                    style={{ fontSize: 13 }}
                                  >
                                    Attachments
                                  </div>
                                  <ul className="list-unstyled mb-0">
                                    {m.attachments.map((att: any, idx: number) => {
                                      const label =
                                        att.filename ||
                                        att.name ||
                                        att.file_name ||
                                        `Attachment ${idx + 1}`;

                                      const href =
                                        att.download_url ||
                                        att.url ||
                                        att.href ||
                                        att.link ||
                                        null;

                                      return (
                                        <li key={att.id ?? idx}>
                                          {href ? (
                                            <a
                                              href={href}
                                              target="_blank"
                                              rel="noreferrer"
                                            >
                                              {label}
                                            </a>
                                          ) : (
                                            <span>{label}</span>
                                          )}
                                        </li>
                                      );
                                    })}
                                  </ul>
                                </div>
                              )}
                            </div>
                          ))}
                        </>
                      )}
                    </div>
                  </div>
                </Col>
              </Row>
            </Card.Body>
          </Card>
        </div>

        {/* Move message modal */}
        <Modal
          show={showMoveModal}
          onHide={() => {
            if (!isMoving) setShowMoveModal(false);
          }}
          centered
        >
          <Modal.Header closeButton={!isMoving}>
            <Modal.Title>Move message</Modal.Title>
          </Modal.Header>
          <Modal.Body>
            {folders.length === 0 ? (
              <div className="text-muted small">
                No folders available.
              </div>
            ) : (
              <>
                <div className="mb-2 small text-muted">
                  Choose a folder to move this message to:
                </div>
                <div className="d-flex flex-column gap-2">
                  {folders.map((f) => {
                    const folderId = f.id || f.name;
                    const serverKey = folderKeyForServer(folderId);
                    const isCurrent =
                      serverKey === folderKeyForServer(activeFolder);

                    return (
                      <Button
                        key={folderId}
                        size="sm"
                        variant={isCurrent ? 'secondary' : 'light'}
                        className="d-flex justify-content-between align-items-center text-start"
                        disabled={isCurrent || isMoving}
                        onClick={() => handleMoveMessage(folderId)}
                      >
                        <span>{f.name || folderId}</span>
                        {typeof f.unread === 'number' && f.unread > 0 && (
                          <span className="badge bg-primary ms-2">
                            {f.unread}
                          </span>
                        )}
                      </Button>
                    );
                  })}
                </div>
              </>
            )}
          </Modal.Body>
          <Modal.Footer>
            <Button
              variant="secondary"
              onClick={() => setShowMoveModal(false)}
              disabled={isMoving}
            >
              Close
            </Button>
          </Modal.Footer>
        </Modal>

        {/* Compose modal */}
        <ComposeEmailModal
          show={composeShow}
          mode={composeMode}
          onClose={() => setComposeShow(false)}
          onSent={handleSent}
          initialTo={composeInit.to}
          initialCc={composeInit.cc}
          initialSubject={composeInit.subject}
          initialBody={composeInit.body}
          quotedHtml={composeInit.quotedHtml}
        />
      </div>
    </MainLayout>
  );
}
