// ============================================================================
//  Вкладка «Пошта» — спільна скринька компанії info@digital-shop.com.ua.
//  Десктоп: 3 панелі (папки · список · читання). Мобільний: список → читання →
//  композер. Підключено до реального бекенду /api/mail/* (emailsDb + mailService).
//
//  Перенесено з дизайн-прототипу (mail/HANDOFF.md). Глобальні примітиви Icon/Button
//  беремо з ui.jsx; решта (статуси листа, чипи, кольоровий аватар, модалки) —
//  локальні, з префіксом, щоб не конфліктувати з рештою CRM.
// ============================================================================
const { useState, useEffect, useRef, useMemo, useCallback } = React;

const MAILBOX = "info@digital-shop.com.ua";

// Статус листа (міні-хелпдеск). Ключі = значення в БД (emailsDb.status).
const MAIL_STATUS = {
  needs_reply: { label: "Потрібна відповідь", color: "var(--warning)", soft: "rgba(245,158,11,.14)", icon: "reply" },
  in_progress: { label: "В роботі",           color: "var(--info)",    soft: "rgba(59,130,246,.14)", icon: "loader" },
  done:        { label: "Оброблено",          color: "var(--success)", soft: "rgba(16,185,129,.14)", icon: "check" },
};

const MAIL_FOLDERS = [
  { key: "inbox",   label: "Вхідні",      icon: "inbox" },
  { key: "sent",    label: "Відправлені", icon: "send" },
  { key: "drafts",  label: "Чернетки",    icon: "file-edit" },
  { key: "archive", label: "Архів",       icon: "archive" },
];

// Авто-категорії (правила на бекенді: mailService.classify)
const MAIL_CATEGORIES = [
  { key: "client",      label: "Клієнти",   color: "#10B981", icon: "user" },
  { key: "cooperation", label: "Співпраця", color: "#6366F1", icon: "handshake" },
  { key: "system",      label: "Системні",  color: "#3B82F6", icon: "bell" },
  { key: "spam",        label: "Спам",      color: "#F43F5E", icon: "ban" },
];
const catMeta = (k) => MAIL_CATEGORIES.find(c => c.key === k) || null;

const MAIL_MONTHS = ["січ.", "лют.", "бер.", "квіт.", "трав.", "черв.", "лип.", "серп.", "вер.", "жовт.", "лист.", "груд."];

function mmoney(n) {
  if (n == null || n === "") return "—";
  return new Intl.NumberFormat("uk-UA").format(Number(n)).replace(/,/g, " ") + " ₴";
}

// epoch ms → {label (Сьогодні/Вчора/12 черв.), time, dateFull}
function fmtMailDate(ms) {
  const d = new Date(Number(ms) || Date.now());
  const now = new Date();
  const time = String(d.getHours()).padStart(2, "0") + ":" + String(d.getMinutes()).padStart(2, "0");
  const yest = new Date(now); yest.setDate(now.getDate() - 1);
  let label;
  if (d.toDateString() === now.toDateString()) label = "Сьогодні";
  else if (d.toDateString() === yest.toDateString()) label = "Вчора";
  else label = d.getDate() + " " + MAIL_MONTHS[d.getMonth()];
  const dateFull = d.getDate() + " " + MAIL_MONTHS[d.getMonth()] + " " + d.getFullYear() + ", " + time;
  return { label, time, dateFull };
}

// Сирий рядок з /api/mail → плоский об'єкт для рендера
function mapMailRow(r) {
  const dt = fmtMailDate(r.date);
  const outgoing = r.direction === "out";
  return {
    id: r.id, folder: r.folder, outgoing,
    unread: !r.is_read,
    status: r.status || null,
    from: { name: r.from_name || r.from_addr || "—", email: r.from_addr || "" },
    to: { name: r.to_addr || "", email: r.to_addr || "" },
    subject: r.subject || "(без теми)",
    preview: r.preview || "",
    orderId: r.order_id || null,
    hasAttach: !!r.has_attach,
    category: r.category || null,
    assignedTo: r.assigned_to || "",
    date: r.date,
    dateLabel: dt.label, time: dt.time, dateFull: dt.dateFull,
  };
}

// Horoshop numeric status → ключ STATUSES (для StatusChip)
function orderStatusKey(status) {
  if (status == null) return "new";
  return HOROSHOP_STATUS_MAP[Number(status)] || "new";
}

// ── Шаблони відповідей (клієнтські; підставляють дані прив'язаного замовлення) ─
const MAIL_TEMPLATES = [
  { key: "invoice", title: "Ваш рахунок", icon: "file-text", desc: "Лист із рахунком на оплату",
    subject: "Рахунок на оплату за замовленням {order}",
    body: "Доброго дня!\n\nНадсилаємо рахунок на оплату за замовленням {order} на суму {sum}.\nРахунок у вкладенні. Після оплати надішлемо ТТН.\n\nДякуємо за замовлення." },
  { key: "requisites", title: "Реквізити", icon: "credit-card", desc: "Картка для оплати (з ваших карток)",
    subject: "Реквізити для оплати — Digitalshop", body: "" },
  { key: "ttn", title: "Відправили ТТН", icon: "truck", desc: "Номер експрес-накладної",
    subject: "Ваше замовлення {order} відправлено",
    body: "Доброго дня!\n\nЗамовлення {order} передано в Нову пошту.\nЕкспрес-накладна: {ttn}\nВідстежити: novaposhta.ua/tracking\n\nОрієнтовна доставка — 1–2 дні." },
];

function signatureHtml() {
  const lines = ["digital-shop.com.ua", MAILBOX];
  return `<div style="margin-top:18px;padding-top:12px;border-top:1px solid #2a2f3a;color:#8a93a2;font-size:13px;line-height:1.6">`
    + `<div style="font-weight:600;color:#b4bac6">DIGITALSHOP</div>`
    + lines.map(l => `<div>${l}</div>`).join("") + `</div>`;
}

// Заповнення плейсхолдерів шаблону даними замовлення
function fillTemplate(s, order) {
  const num = order ? `№${order.order_id}` : "№____";
  const sum = order && order.total != null ? mmoney(order.total) : "____ ₴";
  const ttn = order && order.ttn ? order.ttn : "____";
  return String(s).replace(/{order}/g, num).replace(/{sum}/g, sum).replace(/{ttn}/g, ttn);
}

// ── API ───────────────────────────────────────────────────────────────────────
const MailAPI = {
  list: (params) => fetch("/api/mail?" + new URLSearchParams(params)).then(r => r.json()),
  counts: () => fetch("/api/mail/counts").then(r => r.json()),
  sync: () => fetch("/api/mail/sync", { method: "POST" }).then(r => r.json()),
  full: (id) => fetch("/api/mail/" + id).then(r => r.json()),
  suggestions: (id) => fetch(`/api/mail/${id}/suggestions`).then(r => r.json()),
  searchOrders: (q) => fetch("/api/mail/search-orders?q=" + encodeURIComponent(q)).then(r => r.json()),
  orderDocs: (orderId) => fetch("/api/mail/order-docs?orderId=" + orderId).then(r => r.json()),
  setStatus: (id, status) => fetch(`/api/mail/${id}/status`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ status }) }).then(r => r.json()),
  setRead: (id, read) => fetch(`/api/mail/${id}/read`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ read }) }).then(r => r.json()),
  link: (id, orderId) => fetch(`/api/mail/${id}/link`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ orderId }) }).then(r => r.json()),
  setLabels: (id, labels) => fetch(`/api/mail/${id}/labels`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ labels }) }).then(r => r.json()),
  assign: (id, manager) => fetch(`/api/mail/${id}/assign`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ manager }) }).then(r => r.json()),
  setCategory: (id, category) => fetch(`/api/mail/${id}/category`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ category }) }).then(r => r.json()),
  managers: () => fetch("/api/managers").then(r => r.json()),
  moveFolder: (id, folder) => fetch(`/api/mail/${id}/folder`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ folder }) }).then(r => r.json()),
  send: (body) => fetch("/api/mail/send", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) }).then(r => r.json()),
};

// ── Дрібні примітиви ───────────────────────────────────────────────────────────
function MailAvatar({ name, size = 36 }) {
  const initials = (name || "?").replace(/[«»"]/g, "").split(" ").filter(Boolean).map(s => s[0]).slice(0, 2).join("").toUpperCase();
  const palette = ["#6366F1", "#8B5CF6", "#3B82F6", "#10B981", "#F59E0B", "#F43F5E", "#0EA5E9"];
  let hash = 0; for (const c of (name || "")) hash = (hash * 31 + c.charCodeAt(0)) >>> 0;
  const bg = palette[hash % palette.length];
  return (
    <div style={{
      width: size, height: size, borderRadius: "50%", flexShrink: 0,
      background: `color-mix(in oklab, ${bg} 28%, var(--bg-raised))`, color: "#fff",
      display: "flex", alignItems: "center", justifyContent: "center",
      fontSize: size * 0.38, fontWeight: 600,
      boxShadow: `inset 0 0 0 1px color-mix(in oklab, ${bg} 50%, transparent)`,
    }}>{initials}</div>
  );
}

function MailStatusChip({ status, size = "md" }) {
  const s = MAIL_STATUS[status]; if (!s) return null;
  const sm = size === "sm";
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", gap: 5,
      height: sm ? 20 : 22, padding: sm ? "0 7px 0 6px" : "0 9px 0 7px", borderRadius: 999,
      background: s.soft, color: s.color, fontSize: sm ? 10.5 : 11, fontWeight: 600, whiteSpace: "nowrap",
    }}>
      <Icon name={s.icon} size={sm ? 11 : 12} />{s.label}
    </span>
  );
}

function MailOrderBadge({ id, onClick, size = "md" }) {
  const [h, setH] = useState(false);
  const sm = size === "sm";
  return (
    <span onClick={onClick ? (e) => { e.stopPropagation(); onClick(id); } : undefined}
      onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{
        display: "inline-flex", alignItems: "center", gap: 4,
        height: sm ? 18 : 20, padding: sm ? "0 6px" : "0 7px", borderRadius: 6,
        background: h ? "var(--accent-soft)" : "rgba(99,102,241,.10)",
        color: "var(--accent)", fontSize: sm ? 10.5 : 11.5, fontWeight: 600,
        fontFamily: "var(--font-mono)", cursor: onClick ? "pointer" : "default",
        border: "1px solid rgba(99,102,241,.22)", whiteSpace: "nowrap",
      }}>
      <Icon name="package" size={sm ? 11 : 12} />№{id}
    </span>
  );
}

function LabelDot({ color, size = 8 }) {
  return <span style={{ width: size, height: size, borderRadius: 2, background: color, flexShrink: 0, display: "inline-block" }} />;
}

function CategoryChip({ cat, size = "md" }) {
  const c = catMeta(cat); if (!c) return null;
  const sm = size === "sm";
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 4, height: sm ? 18 : 20, padding: sm ? "0 6px" : "0 8px", borderRadius: 6,
      background: `color-mix(in oklab, ${c.color} 15%, transparent)`, color: c.color, fontSize: sm ? 10.5 : 11, fontWeight: 600, whiteSpace: "nowrap" }}>
      <Icon name={c.icon} size={sm ? 11 : 12} />{c.label}
    </span>
  );
}

function AssigneeChip({ name, size = "md" }) {
  if (!name) return null;
  const sm = size === "sm";
  return (
    <span title={`Відповідальний: ${name}`} style={{ display: "inline-flex", alignItems: "center", gap: 4, height: sm ? 18 : 20, padding: sm ? "0 6px 0 4px" : "0 8px 0 5px", borderRadius: 999,
      background: "var(--bg-raised)", color: "var(--fg-secondary)", fontSize: sm ? 10.5 : 11, fontWeight: 600, whiteSpace: "nowrap", border: "1px solid var(--border-default)" }}>
      <Icon name="user-check" size={sm ? 11 : 12} />{name.split(" ")[0]}
    </span>
  );
}

// Випадайка вибору відповідального (десктоп). managers: [{name,...}]
function AssignMenu({ value, managers, onChange }) {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  useEffect(() => { const h = e => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); }; document.addEventListener("mousedown", h); return () => document.removeEventListener("mousedown", h); }, []);
  return (
    <div ref={ref} style={{ position: "relative" }}>
      <button onClick={() => setOpen(o => !o)} title="Відповідальний" style={{ display: "inline-flex", alignItems: "center", gap: 6, height: 34, padding: "0 10px",
        background: value ? "var(--bg-raised)" : "transparent", border: "1px solid " + (value ? "var(--border-default)" : "var(--border-default)"), borderRadius: 8, cursor: "pointer", fontFamily: "inherit", fontSize: 12.5, fontWeight: 600, color: value ? "var(--fg-primary)" : "var(--fg-secondary)" }}>
        <Icon name={value ? "user-check" : "user-plus"} size={14} />{value ? value.split(" ")[0] : "Менеджер"}
        <Icon name="chevron-down" size={14} style={{ opacity: .7 }} />
      </button>
      {open && (
        <div style={{ position: "absolute", top: 40, right: 0, width: 220, maxHeight: 280, overflowY: "auto", background: "var(--bg-raised)", border: "1px solid var(--border-default)", borderRadius: 10, boxShadow: "var(--shadow-2)", padding: 6, zIndex: 40, animation: "popIn 120ms ease" }} className="no-bar">
          <button onClick={() => { onChange(""); setOpen(false); }} style={{ display: "flex", alignItems: "center", gap: 8, width: "100%", height: 34, padding: "0 8px", border: 0, borderRadius: 7, background: !value ? "var(--bg-hover)" : "transparent", color: "var(--fg-muted)", fontSize: 13, cursor: "pointer", textAlign: "left", fontFamily: "inherit" }}>
            <Icon name="user-x" size={14} /><span style={{ flex: 1 }}>Без відповідального</span>{!value && <Icon name="check" size={14} color="var(--accent)" />}
          </button>
          {(managers || []).map(m => (
            <button key={m.username || m.name} onClick={() => { onChange(m.name); setOpen(false); }} style={{ display: "flex", alignItems: "center", gap: 8, width: "100%", height: 34, padding: "0 8px", border: 0, borderRadius: 7, background: value === m.name ? "var(--bg-hover)" : "transparent", color: "var(--fg-primary)", fontSize: 13, cursor: "pointer", textAlign: "left", fontFamily: "inherit" }}
              onMouseEnter={e => e.currentTarget.style.background = "var(--bg-hover)"} onMouseLeave={e => e.currentTarget.style.background = value === m.name ? "var(--bg-hover)" : "transparent"}>
              <MailAvatar name={m.name} size={20} /><span style={{ flex: 1 }}>{m.name}</span>{value === m.name && <Icon name="check" size={14} color="var(--accent)" />}
            </button>
          ))}
        </div>
      )}
    </div>
  );
}

// Мобільна шторка вибору відповідального
function AssignSheet({ current, managers, onPick, onClose }) {
  return (
    <div onClick={onClose} style={{ position: "absolute", inset: 0, zIndex: 70, background: "rgba(0,0,0,.5)", display: "flex", flexDirection: "column", justifyContent: "flex-end", animation: "fade 140ms ease" }}>
      <div onClick={e => e.stopPropagation()} style={{ background: "var(--bg-raised)", borderRadius: "18px 18px 0 0", padding: "8px 12px 22px", maxHeight: "70%", overflowY: "auto", animation: "msheetUp 200ms var(--ease)" }} className="no-bar">
        <div style={{ width: 36, height: 4, borderRadius: 2, background: "var(--border-strong)", margin: "8px auto 14px" }} />
        <div style={{ fontSize: 12, fontWeight: 600, color: "var(--fg-muted)", padding: "0 6px 8px", textTransform: "uppercase", letterSpacing: ".04em" }}>Відповідальний менеджер</div>
        <button onClick={() => onPick("")} style={{ display: "flex", alignItems: "center", gap: 11, width: "100%", height: 48, padding: "0 10px", border: 0, borderRadius: 11, background: !current ? "var(--bg-hover)" : "transparent", cursor: "pointer", fontFamily: "inherit", textAlign: "left", color: "var(--fg-muted)" }}>
          <Icon name="user-x" size={18} /><span style={{ flex: 1, fontSize: 15 }}>Без відповідального</span>{!current && <Icon name="check" size={18} color="var(--accent)" />}
        </button>
        {(managers || []).map(m => (
          <button key={m.username || m.name} onClick={() => onPick(m.name)} style={{ display: "flex", alignItems: "center", gap: 11, width: "100%", height: 50, padding: "0 10px", border: 0, borderRadius: 11, background: current === m.name ? "var(--bg-hover)" : "transparent", cursor: "pointer", fontFamily: "inherit", textAlign: "left" }}>
            <MailAvatar name={m.name} size={28} /><span style={{ flex: 1, fontSize: 15, color: "var(--fg-primary)", fontWeight: 500 }}>{m.name}</span>{current === m.name && <Icon name="check" size={18} color="var(--accent)" />}
          </button>
        ))}
      </div>
    </div>
  );
}

// Іконкова кнопка тулбарів
function MIconBtn({ name, title, onClick, size = 18, danger, active, style }) {
  const [h, setH] = useState(false);
  return (
    <button title={title} onClick={onClick} onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{
        width: 34, height: 34, border: 0, borderRadius: 8, cursor: "pointer",
        display: "flex", alignItems: "center", justifyContent: "center",
        background: h ? (danger ? "rgba(244,63,94,.12)" : "var(--bg-hover)") : (active ? "var(--accent-soft)" : "transparent"),
        color: danger ? (h ? "var(--danger)" : "var(--fg-secondary)") : (active ? "var(--accent)" : (h ? "var(--fg-primary)" : "var(--fg-secondary)")),
        transition: "all 120ms", ...style,
      }}>
      <Icon name={name} size={size} />
    </button>
  );
}

// ── Модалка-оболонка ───────────────────────────────────────────────────────────
function ModalShell({ children, onClose, width = 520, align = "center" }) {
  return (
    <div onClick={onClose} style={{
      position: "fixed", inset: 0, background: "rgba(0,0,0,.6)", zIndex: 100,
      display: "flex", alignItems: align === "center" ? "center" : "flex-start",
      justifyContent: "center", padding: align === "center" ? 24 : "64px 24px 24px",
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width, maxWidth: "100%", maxHeight: "calc(100vh - 48px)", background: "var(--bg-raised)",
        border: "1px solid var(--border-default)", borderRadius: 14, boxShadow: "var(--shadow-2)",
        display: "flex", flexDirection: "column", overflow: "hidden", animation: "popIn 160ms var(--ease)",
      }}>{children}</div>
    </div>
  );
}

function OrderResultRow({ order, onPick, badge }) {
  const [h, setH] = useState(false);
  return (
    <button onClick={() => onPick(order.order_id, order)} onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{
        display: "flex", alignItems: "center", gap: 12, width: "100%", padding: "10px 12px",
        border: 0, borderRadius: 10, cursor: "pointer", textAlign: "left", fontFamily: "inherit",
        background: h ? "var(--bg-hover)" : "transparent",
      }}>
      <span style={{ fontSize: 13, fontWeight: 700, color: "var(--accent)", fontFamily: "var(--font-mono)", width: 56, flexShrink: 0 }}>№{order.order_id}</span>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 13, fontWeight: 500, color: "var(--fg-primary)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{order.client || "—"}</div>
        <div style={{ fontSize: 11.5, color: "var(--fg-muted)" }}>{order.created || ""}{order.phone ? " · " + order.phone : ""}</div>
      </div>
      {badge && <span style={{ fontSize: 10.5, color: "var(--accent)", background: "var(--accent-soft)", padding: "2px 7px", borderRadius: 999, fontWeight: 600, flexShrink: 0 }}>{badge}</span>}
      <span style={{ fontSize: 13, fontWeight: 600, color: "var(--fg-primary)", fontFamily: "var(--font-mono)", flexShrink: 0 }}>{mmoney(order.total)}</span>
    </button>
  );
}

// ── Модалка прив'язки до замовлення ─────────────────────────────────────────────
function LinkOrderModal({ suggestions, onClose, onPick }) {
  const [q, setQ] = useState("");
  const [results, setResults] = useState([]);
  const [busy, setBusy] = useState(false);
  useEffect(() => {
    const s = q.trim();
    if (!s) { setResults([]); return; }
    let dead = false; setBusy(true);
    const t = setTimeout(async () => {
      try { const r = await MailAPI.searchOrders(s); if (!dead) setResults(r.ok ? r.orders : []); }
      catch { if (!dead) setResults([]); }
      finally { if (!dead) setBusy(false); }
    }, 280);
    return () => { dead = true; clearTimeout(t); };
  }, [q]);
  return (
    <ModalShell onClose={onClose} width={520} align="top">
      <div style={{ padding: "16px 18px", borderBottom: "1px solid var(--border-subtle)", display: "flex", alignItems: "center", gap: 10 }}>
        <Icon name="link" size={18} color="var(--accent)" />
        <h3 style={{ fontSize: 15, fontWeight: 600, color: "var(--fg-primary)", margin: 0, flex: 1 }}>Прив'язати до замовлення</h3>
        <MIconBtn name="x" title="Закрити" size={18} onClick={onClose} />
      </div>
      <div style={{ padding: 16, overflowY: "auto" }} className="no-bar">
        {suggestions && suggestions.length > 0 && !q && (
          <div style={{ marginBottom: 16 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 6, fontSize: 11, fontWeight: 600, letterSpacing: ".04em", textTransform: "uppercase", color: "var(--fg-muted)", marginBottom: 8 }}>
              <Icon name="sparkles" size={13} color="var(--accent)" />Знайдені збіги
            </div>
            <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
              {suggestions.map(s => <OrderResultRow key={s.order_id} order={s} onPick={onPick} badge={s.reason} />)}
            </div>
          </div>
        )}
        <div style={{ position: "relative", marginBottom: q ? 12 : 0 }}>
          <Icon name="search" size={15} style={{ position: "absolute", left: 11, top: "50%", transform: "translateY(-50%)", color: "var(--fg-muted)" }} />
          <input autoFocus value={q} onChange={e => setQ(e.target.value)} placeholder="№ замовлення, ім'я, телефон, email…"
            style={{ width: "100%", height: 40, boxSizing: "border-box", padding: "0 12px 0 36px", background: "var(--bg-base)", color: "var(--fg-primary)", border: "1px solid var(--border-default)", borderRadius: 10, fontSize: 13, outline: "none", fontFamily: "inherit" }} />
        </div>
        {q && (
          <div style={{ display: "flex", flexDirection: "column", gap: 2 }}>
            {busy && <div style={{ padding: "16px 0", textAlign: "center", color: "var(--fg-muted)", fontSize: 12.5 }}>Пошук…</div>}
            {!busy && results.length > 0 && results.map(o => <OrderResultRow key={o.order_id} order={o} onPick={onPick} />)}
            {!busy && results.length === 0 && <div style={{ padding: "24px 0", textAlign: "center", color: "var(--fg-muted)", fontSize: 12.5 }}>За запитом «{q}» замовлень не знайдено</div>}
          </div>
        )}
        {!q && (!suggestions || !suggestions.length) && (
          <div style={{ padding: "20px 0", textAlign: "center", color: "var(--fg-muted)", fontSize: 12.5 }}>Почніть вводити, щоб знайти замовлення</div>
        )}
      </div>
    </ModalShell>
  );
}

// ── Пікер документів (рахунки/видаткові з invoicesDb) ───────────────────────────
const DOC_KIND_LABEL = { invoice: "Рахунок", vydatkova: "Видаткова" };
function AttachDocPicker({ initialOrderId, initialOrder, onClose, onAttach }) {
  const [q, setQ] = useState("");
  const [orders, setOrders] = useState(initialOrder ? [initialOrder] : []);
  const [docs, setDocs] = useState({});        // orderId → invoices[]
  const [openId, setOpenId] = useState(initialOrderId || null);
  const [busy, setBusy] = useState(false);

  const loadDocs = useCallback(async (orderId) => {
    if (docs[orderId]) return;
    try { const r = await MailAPI.orderDocs(orderId); setDocs(d => ({ ...d, [orderId]: r.ok ? r.invoices : [] })); }
    catch { setDocs(d => ({ ...d, [orderId]: [] })); }
  }, [docs]);

  useEffect(() => { if (initialOrderId) loadDocs(initialOrderId); }, []);
  useEffect(() => {
    const s = q.trim(); if (!s) { setOrders(initialOrder ? [initialOrder] : []); return; }
    let dead = false; setBusy(true);
    const t = setTimeout(async () => {
      try { const r = await MailAPI.searchOrders(s); if (!dead) setOrders(r.ok ? r.orders : []); }
      catch { if (!dead) setOrders([]); }
      finally { if (!dead) setBusy(false); }
    }, 280);
    return () => { dead = true; clearTimeout(t); };
  }, [q]);

  const toggle = (id) => { const nx = openId === id ? null : id; setOpenId(nx); if (nx) loadDocs(nx); };

  return (
    <ModalShell onClose={onClose} width={520} align="top">
      <div style={{ padding: "16px 18px", borderBottom: "1px solid var(--border-subtle)", display: "flex", alignItems: "center", gap: 10 }}>
        <Icon name="file-plus-2" size={18} color="var(--accent)" />
        <h3 style={{ fontSize: 15, fontWeight: 600, color: "var(--fg-primary)", margin: 0, flex: 1 }}>Прикріпити документ</h3>
        <MIconBtn name="x" title="Закрити" size={18} onClick={onClose} />
      </div>
      <div style={{ padding: 16, overflowY: "auto" }} className="no-bar">
        <div style={{ position: "relative", marginBottom: 14 }}>
          <Icon name="search" size={15} style={{ position: "absolute", left: 11, top: "50%", transform: "translateY(-50%)", color: "var(--fg-muted)" }} />
          <input autoFocus value={q} onChange={e => setQ(e.target.value)} placeholder="Пошук: № замовлення, ім'я, телефон…"
            style={{ width: "100%", height: 40, boxSizing: "border-box", padding: "0 12px 0 36px", background: "var(--bg-base)", color: "var(--fg-primary)", border: "1px solid var(--border-default)", borderRadius: 10, fontSize: 13, outline: "none", fontFamily: "inherit" }} />
        </div>
        {initialOrderId && !q && <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: ".04em", textTransform: "uppercase", color: "var(--fg-muted)", marginBottom: 8 }}>Документи цього замовлення</div>}
        <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
          {busy && <div style={{ padding: "16px 0", textAlign: "center", color: "var(--fg-muted)", fontSize: 12.5 }}>Пошук…</div>}
          {orders.map(o => {
            const id = o.order_id; const expanded = openId === id; const list = docs[id];
            return (
              <div key={id} style={{ border: "1px solid var(--border-default)", borderRadius: 10, overflow: "hidden", background: "var(--bg-panel)" }}>
                <button onClick={() => toggle(id)} style={{ display: "flex", alignItems: "center", gap: 10, width: "100%", padding: "10px 12px", border: 0, background: "transparent", cursor: "pointer", textAlign: "left", fontFamily: "inherit" }}>
                  <Icon name={expanded ? "chevron-down" : "chevron-right"} size={15} color="var(--fg-muted)" />
                  <span style={{ fontSize: 13, fontWeight: 700, color: "var(--accent)", fontFamily: "var(--font-mono)" }}>№{id}</span>
                  <span style={{ flex: 1, fontSize: 12.5, color: "var(--fg-secondary)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{o.client || ""}</span>
                </button>
                {expanded && (
                  <div style={{ borderTop: "1px solid var(--border-subtle)", padding: 6, display: "flex", flexDirection: "column", gap: 2 }}>
                    {list == null && <div style={{ padding: "10px 8px", color: "var(--fg-muted)", fontSize: 12 }}>Завантаження…</div>}
                    {list && list.length === 0 && <div style={{ padding: "10px 8px", color: "var(--fg-muted)", fontSize: 12 }}>Немає документів</div>}
                    {list && list.map(inv => (inv.files || []).filter(f => f.alive).map(f => (
                      <button key={inv.id + "-" + f.id} onClick={() => onAttach({ invoiceId: inv.id, kind: f.kind, name: `${DOC_KIND_LABEL[f.kind] || "Документ"} №${inv.invoice_no}`, sub: mmoney(inv.total) })}
                        style={{ display: "flex", alignItems: "center", gap: 10, padding: "8px", border: 0, borderRadius: 8, background: "transparent", cursor: "pointer", textAlign: "left", fontFamily: "inherit", width: "100%" }}
                        onMouseEnter={e => e.currentTarget.style.background = "var(--bg-hover)"} onMouseLeave={e => e.currentTarget.style.background = "transparent"}>
                        <div style={{ width: 30, height: 30, borderRadius: 7, background: "rgba(244,63,94,.12)", color: "#F87171", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}><Icon name="file-text" size={15} /></div>
                        <div style={{ flex: 1, minWidth: 0 }}>
                          <div style={{ fontSize: 12.5, fontWeight: 500, color: "var(--fg-primary)" }}>{DOC_KIND_LABEL[f.kind] || "Документ"} №{inv.invoice_no}</div>
                          <div style={{ fontSize: 11, color: f.kind === "invoice" ? "var(--accent)" : "var(--fg-secondary)", fontWeight: 600 }}>{mmoney(inv.total)} <span style={{ color: "var(--fg-muted)", fontWeight: 400 }}>· {inv.doc_date || ""}</span></div>
                        </div>
                        <Icon name="plus" size={16} color="var(--fg-muted)" />
                      </button>
                    )))}
                    {list && list.length > 0 && list.every(inv => !(inv.files || []).some(f => f.alive)) && (
                      <div style={{ padding: "10px 8px", color: "var(--fg-muted)", fontSize: 12 }}>Файли рахунків відсутні або застаріли</div>
                    )}
                  </div>
                )}
              </div>
            );
          })}
          {!busy && orders.length === 0 && <div style={{ padding: "24px 0", textAlign: "center", color: "var(--fg-muted)", fontSize: 12.5 }}>{q ? "Документів не знайдено" : "Почніть вводити № замовлення або ім'я"}</div>}
        </div>
      </div>
    </ModalShell>
  );
}

// ── Композер (десктоп-модалка + мобільний повний екран) ─────────────────────────
function ComposerField({ label, value, onChange, placeholder, mono }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 12, height: 44, padding: "0 4px", borderBottom: "1px solid var(--border-subtle)" }}>
      <span style={{ width: 44, fontSize: 12.5, color: "var(--fg-muted)", flexShrink: 0 }}>{label}</span>
      <input value={value} onChange={e => onChange(e.target.value)} placeholder={placeholder}
        style={{ flex: 1, height: "100%", border: 0, background: "transparent", color: "var(--fg-primary)", fontSize: 13.5, outline: "none", fontFamily: mono ? "var(--font-mono)" : "inherit" }} />
    </div>
  );
}
function ToolbarBtn({ icon, title, onClick }) {
  const [h, setH] = useState(false);
  return (
    <button title={title} onMouseDown={e => { e.preventDefault(); onClick && onClick(); }} onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{ width: 32, height: 32, border: 0, borderRadius: 6, cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", background: h ? "var(--bg-hover)" : "transparent", color: "var(--fg-secondary)" }}>
      <Icon name={icon} size={16} />
    </button>
  );
}

// Пікер активної картки для оплати (шаблон «Реквізити»)
function CardPicker({ onClose, onPick }) {
  const [cards, setCards] = useState(null);
  useEffect(() => { fetch("/api/cards/active").then(r => r.json()).then(r => setCards(r.cards || [])).catch(() => setCards([])); }, []);
  return (
    <ModalShell onClose={onClose} width={460} align="top">
      <div style={{ padding: "16px 18px", borderBottom: "1px solid var(--border-subtle)", display: "flex", alignItems: "center", gap: 10 }}>
        <Icon name="credit-card" size={18} color="var(--accent)" />
        <h3 style={{ fontSize: 15, fontWeight: 600, color: "var(--fg-primary)", margin: 0, flex: 1 }}>Картка для оплати</h3>
        <MIconBtn name="x" title="Закрити" size={18} onClick={onClose} />
      </div>
      <div style={{ padding: 12, overflowY: "auto" }} className="no-bar">
        {cards == null && <div style={{ padding: "16px 0", textAlign: "center", color: "var(--fg-muted)", fontSize: 12.5 }}>Завантаження…</div>}
        {cards && cards.length === 0 && <div style={{ padding: "24px 12px", textAlign: "center", color: "var(--fg-muted)", fontSize: 12.5 }}>Немає активних карток. Додай у розділі «Картки».</div>}
        {cards && cards.map(c => (
          <button key={c.id} onClick={() => onPick(c)} style={{ display: "flex", alignItems: "center", gap: 12, width: "100%", padding: "11px 10px", border: 0, borderRadius: 10, background: "transparent", cursor: "pointer", textAlign: "left", fontFamily: "inherit" }}
            onMouseEnter={e => e.currentTarget.style.background = "var(--bg-hover)"} onMouseLeave={e => e.currentTarget.style.background = "transparent"}>
            {window.BankMonogram ? <BankMonogram bank={(c.bank || "").toLowerCase().includes("моно") ? "mono" : (c.bank || "").toLowerCase().includes("приват") ? "privat" : "privat"} size={34} /> : <Icon name="credit-card" size={20} />}
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 14, fontWeight: 600, color: "var(--fg-primary)", fontFamily: "var(--font-mono)" }}>{c.numberGrouped || c.number}</div>
              <div style={{ fontSize: 12, color: "var(--fg-muted)" }}>{c.bank}{c.holder ? " · " + c.holder : ""}</div>
            </div>
            <Icon name="arrow-right" size={16} color="var(--fg-muted)" />
          </button>
        ))}
      </div>
    </ModalShell>
  );
}

function MailComposer({ initial, isMobile, onClose, onSent, showToast }) {
  const [to, setTo] = useState(initial.to || "");
  const [subject, setSubject] = useState(initial.subject || "");
  const [order, setOrder] = useState(initial.order || null);  // {order_id,client,total,ttn}
  const [attachments, setAttachments] = useState(initial.attachments || []); // [{invoiceId,kind,name,sub}]
  const [showSig, setShowSig] = useState(true);
  const [showTemplates, setShowTemplates] = useState(!isMobile);
  const [tplSheet, setTplSheet] = useState(false);
  const [picker, setPicker] = useState(false);
  const [cardPicker, setCardPicker] = useState(false);
  const [linkOpen, setLinkOpen] = useState(false);
  const [sending, setSending] = useState(false);
  const bodyRef = useRef(null);

  useEffect(() => { if (bodyRef.current && initial.body != null && bodyRef.current.innerHTML === "") bodyRef.current.innerHTML = initial.body; }, []);

  const fmt = cmd => document.execCommand(cmd, false, null);

  // «Реквізити» → вставляємо реальну картку для оплати (з cardsDb)
  const insertRequisites = (card) => {
    const num = card.numberGrouped || card.number;
    const sum = order && order.total != null ? mmoney(order.total) : null;
    const lines = [
      "Доброго дня!", "",
      `Реквізити для оплати${order ? ` за замовленням №${order.order_id}` : ""}:`, "",
      `Картка: ${num}`,
      card.bank ? `Банк: ${card.bank}` : "",
      card.holder ? `Отримувач: ${card.holder}` : "",
      sum ? `Сума до сплати: ${sum}` : "",
      "", "Після оплати надішліть, будь ласка, скрін квитанції у відповідь.",
    ].filter(l => l !== "" || true);
    setSubject(`Реквізити для оплати${order ? ` за замовленням №${order.order_id}` : ""}`);
    if (bodyRef.current) bodyRef.current.innerHTML = lines.map(l => l ? `<div>${l}</div>` : "<div><br></div>").join("");
    setCardPicker(false); setTplSheet(false);
  };

  const applyTemplate = (t) => {
    if (t.key === "requisites") { setCardPicker(true); setTplSheet(false); return; } // вибір картки
    setSubject(fillTemplate(t.subject, order));
    if (bodyRef.current) bodyRef.current.innerHTML = fillTemplate(t.body, order).split("\n").map(l => l ? `<div>${l}</div>` : "<div><br></div>").join("");
    if (t.key === "invoice" && order) {
      // авто-додати рахунок замовлення
      MailAPI.orderDocs(order.order_id).then(r => {
        if (!r.ok) return;
        for (const inv of r.invoices) {
          const f = (inv.files || []).find(x => x.alive && x.kind === "invoice");
          if (f) { setAttachments(a => a.some(x => x.invoiceId === inv.id && x.kind === "invoice") ? a : [...a, { invoiceId: inv.id, kind: "invoice", name: `Рахунок №${inv.invoice_no}`, sub: mmoney(inv.total) }]); break; }
        }
      }).catch(() => {});
    }
    setTplSheet(false);
  };

  const doSend = async () => {
    if (!to.trim()) { showToast && showToast("Вкажіть отримувача", "error"); return; }
    setSending(true);
    try {
      let html = bodyRef.current ? bodyRef.current.innerHTML : "";
      if (showSig) html += signatureHtml();
      const text = bodyRef.current ? (bodyRef.current.innerText || "") : "";
      const r = await MailAPI.send({
        to: to.trim(), subject, text, html,
        orderId: order ? order.order_id : undefined,
        replyTo: initial.replyTo || undefined,
        attachInvoices: attachments.map(a => ({ invoiceId: a.invoiceId, kind: a.kind })),
      });
      if (!r.ok) throw new Error(r.error || "Помилка відправки");
      onSent && onSent();
    } catch (e) { showToast && showToast("❌ " + e.message, "error"); }
    finally { setSending(false); }
  };

  const orderChip = order ? (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 5, height: 26, padding: "0 8px 0 7px", borderRadius: 7, background: "var(--accent-soft)", color: "var(--accent)", fontSize: 12, fontWeight: 600, border: "1px solid rgba(99,102,241,.25)" }}>
      <Icon name="package" size={13} /><span style={{ fontFamily: "var(--font-mono)" }}>№{order.order_id}</span> · {(order.client || "").split(" ")[0]}
      <button onClick={() => setOrder(null)} style={{ border: 0, background: "transparent", color: "var(--accent)", cursor: "pointer", display: "flex", marginLeft: 2, padding: 0 }}><Icon name="x" size={12} /></button>
    </span>
  ) : (
    <button onClick={() => setLinkOpen(true)} style={{ display: "inline-flex", alignItems: "center", gap: 4, height: 26, padding: "0 8px", borderRadius: 7, background: "transparent", border: "1px dashed var(--border-strong)", color: "var(--fg-muted)", fontSize: 12, cursor: "pointer", fontFamily: "inherit" }}><Icon name="link" size={12} />Прив'язати замовлення</button>
  );

  const attachStrip = attachments.length > 0 && (
    <div style={{ padding: "10px 18px", borderTop: "1px solid var(--border-subtle)", display: "flex", flexWrap: "wrap", gap: 8 }}>
      {attachments.map((a, i) => (
        <div key={i} style={{ display: "flex", alignItems: "center", gap: 8, padding: "6px 8px", background: "var(--bg-panel)", border: "1px solid var(--border-default)", borderRadius: 8 }}>
          <div style={{ width: 26, height: 26, borderRadius: 6, background: "rgba(244,63,94,.12)", color: "#F87171", display: "flex", alignItems: "center", justifyContent: "center" }}><Icon name="file-text" size={14} /></div>
          <div><div style={{ fontSize: 12, fontWeight: 500, color: "var(--fg-primary)" }}>{a.name}</div><div style={{ fontSize: 10.5, color: "var(--fg-muted)", fontFamily: "var(--font-mono)" }}>{a.sub}</div></div>
          <button onClick={() => setAttachments(at => at.filter((_, j) => j !== i))} style={{ border: 0, background: "transparent", color: "var(--fg-muted)", cursor: "pointer", display: "flex", padding: 2 }}><Icon name="x" size={14} /></button>
        </div>
      ))}
    </div>
  );

  const editor = (
    <>
      <div style={{ padding: "0 18px" }}>
        <ComposerField label="Кому" value={to} onChange={setTo} placeholder="email клієнта" mono />
        <ComposerField label="Тема" value={subject} onChange={setSubject} placeholder="Тема листа" />
      </div>
      <div style={{ display: "flex", alignItems: "center", gap: 2, padding: "6px 14px", borderBottom: "1px solid var(--border-subtle)" }}>
        <ToolbarBtn icon="bold" title="Жирний" onClick={() => fmt("bold")} />
        <ToolbarBtn icon="italic" title="Курсив" onClick={() => fmt("italic")} />
        <ToolbarBtn icon="underline" title="Підкреслений" onClick={() => fmt("underline")} />
        <div style={{ width: 1, height: 18, background: "var(--border-default)", margin: "0 4px" }} />
        <ToolbarBtn icon="list" title="Список" onClick={() => fmt("insertUnorderedList")} />
        <ToolbarBtn icon="list-ordered" title="Нумерований" onClick={() => fmt("insertOrderedList")} />
        <ToolbarBtn icon="link" title="Посилання" onClick={() => { const u = prompt("URL:"); if (u) document.execCommand("createLink", false, u); }} />
        <div style={{ flex: 1 }} />
        <button onClick={() => isMobile ? setTplSheet(true) : setShowTemplates(s => !s)} style={{ display: "inline-flex", alignItems: "center", gap: 5, height: 28, padding: "0 9px", border: 0, borderRadius: 6, background: (!isMobile && showTemplates) ? "var(--accent-soft)" : "transparent", color: (!isMobile && showTemplates) ? "var(--accent)" : "var(--fg-secondary)", fontSize: 12, fontWeight: 500, cursor: "pointer", fontFamily: "inherit" }}>
          <Icon name="layout-template" size={14} />Шаблони
        </button>
      </div>
      <div style={{ flex: 1, overflowY: "auto", padding: "16px 18px" }} className="no-bar">
        <div ref={bodyRef} contentEditable suppressContentEditableWarning
          style={{ minHeight: 120, outline: "none", fontSize: 14, lineHeight: 1.6, color: "var(--fg-primary)", fontFamily: "inherit" }} />
        {showSig && (
          <div style={{ marginTop: 18, paddingTop: 12, borderTop: "1px dashed var(--border-default)", fontSize: 12.5, color: "var(--fg-muted)", lineHeight: 1.6 }}>
            <div style={{ fontWeight: 600, color: "var(--fg-secondary)" }}>DIGITALSHOP</div>
            <div>digital-shop.com.ua</div><div>{MAILBOX}</div>
          </div>
        )}
      </div>
      {attachStrip}
    </>
  );

  const templatesPanel = (
    <div style={{ width: 248, flexShrink: 0, borderLeft: "1px solid var(--border-subtle)", background: "var(--bg-panel)", display: "flex", flexDirection: "column" }}>
      <div style={{ padding: "12px 14px", borderBottom: "1px solid var(--border-subtle)", display: "flex", alignItems: "center", gap: 8 }}>
        <Icon name="layout-template" size={15} color="var(--fg-muted)" />
        <span style={{ fontSize: 12.5, fontWeight: 600, color: "var(--fg-secondary)" }}>Шаблони відповідей</span>
      </div>
      <div style={{ padding: 10, display: "flex", flexDirection: "column", gap: 8, overflowY: "auto" }} className="no-bar">
        {!order && <div style={{ fontSize: 11.5, color: "var(--fg-muted)", padding: "4px 6px 6px", lineHeight: 1.4 }}>Прив'яжіть замовлення — дані (№, сума, ТТН) підставляться автоматично.</div>}
        {MAIL_TEMPLATES.map(t => (
          <button key={t.key} onClick={() => applyTemplate(t)} style={{ display: "flex", alignItems: "flex-start", gap: 10, padding: 11, border: "1px solid var(--border-default)", borderRadius: 10, background: "var(--bg-raised)", cursor: "pointer", textAlign: "left", fontFamily: "inherit" }}
            onMouseEnter={e => e.currentTarget.style.borderColor = "var(--accent)"} onMouseLeave={e => e.currentTarget.style.borderColor = "var(--border-default)"}>
            <div style={{ width: 30, height: 30, borderRadius: 8, background: "var(--accent-soft)", color: "var(--accent)", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}><Icon name={t.icon} size={16} /></div>
            <div style={{ minWidth: 0 }}>
              <div style={{ fontSize: 13, fontWeight: 600, color: "var(--fg-primary)" }}>{t.title}</div>
              <div style={{ fontSize: 11.5, color: "var(--fg-muted)", lineHeight: 1.35, marginTop: 1 }}>{t.desc}</div>
            </div>
          </button>
        ))}
      </div>
    </div>
  );

  const modals = (
    <>
      {picker && <AttachDocPicker initialOrderId={order ? order.order_id : null} initialOrder={order ? { order_id: order.order_id, client: order.client } : null}
        onClose={() => setPicker(false)} onAttach={(d) => { setAttachments(a => a.some(x => x.invoiceId === d.invoiceId && x.kind === d.kind) ? a : [...a, d]); setPicker(false); }} />}
      {cardPicker && <CardPicker onClose={() => setCardPicker(false)} onPick={insertRequisites} />}
      {linkOpen && <LinkOrderModal suggestions={[]} onClose={() => setLinkOpen(false)} onPick={(id, o) => { setOrder({ order_id: id, client: o.client, total: o.total, ttn: o.ttn }); setLinkOpen(false); }} />}
      {tplSheet && (
        <div onClick={() => setTplSheet(false)} style={{ position: "absolute", inset: 0, zIndex: 90, background: "rgba(0,0,0,.5)", display: "flex", flexDirection: "column", justifyContent: "flex-end" }}>
          <div onClick={e => e.stopPropagation()} style={{ background: "var(--bg-raised)", borderRadius: "18px 18px 0 0", padding: "8px 12px 22px", animation: "msheetUp 200ms var(--ease)" }}>
            <div style={{ width: 36, height: 4, borderRadius: 2, background: "var(--border-strong)", margin: "8px auto 14px" }} />
            <div style={{ fontSize: 12, fontWeight: 600, color: "var(--fg-muted)", padding: "0 6px 8px", textTransform: "uppercase", letterSpacing: ".04em" }}>Шаблони відповідей</div>
            {!order && <div style={{ fontSize: 12.5, color: "var(--fg-muted)", padding: "0 6px 10px", lineHeight: 1.4 }}>Прив'яжіть замовлення — дані підставляться автоматично.</div>}
            {MAIL_TEMPLATES.map(t => (
              <button key={t.key} onClick={() => applyTemplate(t)} style={{ display: "flex", alignItems: "center", gap: 12, width: "100%", padding: 12, border: 0, borderRadius: 12, background: "transparent", cursor: "pointer", fontFamily: "inherit", textAlign: "left" }}>
                <div style={{ width: 38, height: 38, borderRadius: 9, background: "var(--accent-soft)", color: "var(--accent)", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}><Icon name={t.icon} size={18} /></div>
                <div><div style={{ fontSize: 14.5, fontWeight: 600, color: "var(--fg-primary)" }}>{t.title}</div><div style={{ fontSize: 12.5, color: "var(--fg-muted)" }}>{t.desc}</div></div>
              </button>
            ))}
          </div>
        </div>
      )}
    </>
  );

  // ── Мобільний: повний екран ──
  if (isMobile) {
    return (
      <div style={{ position: "fixed", inset: 0, zIndex: 200, background: "var(--bg-base)", display: "flex", flexDirection: "column" }}>
        <div style={{ flexShrink: 0, height: 52, display: "flex", alignItems: "center", padding: "0 6px 0 4px", gap: 4, borderBottom: "1px solid var(--border-subtle)", background: "var(--bg-panel)", paddingTop: "env(safe-area-inset-top, 0px)" }}>
          <button onClick={onClose} style={{ width: 40, height: 40, border: 0, background: "transparent", color: "var(--fg-secondary)", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }}><Icon name="x" size={22} /></button>
          <span style={{ flex: 1, fontSize: 15, fontWeight: 600, color: "var(--fg-primary)" }}>{initial.title || "Нове письмо"}</span>
          <Button size="md" leftIcon="send" onClick={doSend} disabled={sending}>{sending ? "…" : "Відправити"}</Button>
        </div>
        <div style={{ padding: "10px 16px", borderBottom: "1px solid var(--border-subtle)" }}>{orderChip}</div>
        <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>{editor}</div>
        <div style={{ flexShrink: 0, padding: "10px 14px", borderTop: "1px solid var(--border-subtle)", background: "var(--bg-panel)", display: "flex", alignItems: "center", gap: 6 }}>
          <button onClick={() => setPicker(true)} style={{ display: "inline-flex", alignItems: "center", gap: 6, height: 40, padding: "0 12px", border: "1px solid var(--border-default)", borderRadius: 10, background: "var(--bg-raised)", color: "var(--fg-primary)", fontSize: 13, fontWeight: 500, cursor: "pointer", fontFamily: "inherit" }}><Icon name="file-plus-2" size={17} />Документ</button>
          <button onClick={() => setShowSig(s => !s)} style={{ width: 40, height: 40, border: "1px solid var(--border-default)", borderRadius: 10, background: showSig ? "var(--accent-soft)" : "var(--bg-raised)", color: showSig ? "var(--accent)" : "var(--fg-muted)", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }}><Icon name="signature" size={17} /></button>
        </div>
        {modals}
      </div>
    );
  }

  // ── Десктоп: модалка ──
  return (
    <div style={{ position: "fixed", inset: 0, zIndex: 90, display: "flex", alignItems: "flex-end", justifyContent: "center", background: "rgba(0,0,0,.55)" }} onClick={onClose}>
      <div onClick={e => e.stopPropagation()} style={{ width: 940, maxWidth: "100%", height: "min(86vh, 760px)", background: "var(--bg-raised)", border: "1px solid var(--border-default)", borderRadius: "14px 14px 0 0", boxShadow: "var(--shadow-2)", display: "flex", flexDirection: "column", overflow: "hidden", animation: "sheetUp 200ms var(--ease)" }}>
        <div style={{ height: 50, flexShrink: 0, display: "flex", alignItems: "center", padding: "0 16px", gap: 10, borderBottom: "1px solid var(--border-subtle)", background: "var(--bg-panel)" }}>
          <Icon name="square-pen" size={17} color="var(--accent)" />
          <span style={{ fontSize: 14, fontWeight: 600, color: "var(--fg-primary)" }}>{initial.title || "Нове письмо"}</span>
          {orderChip}
          <div style={{ flex: 1 }} />
          <MIconBtn name="x" title="Закрити" size={18} onClick={onClose} />
        </div>
        <div style={{ flex: 1, display: "flex", minHeight: 0 }}>
          <div style={{ flex: 1, display: "flex", flexDirection: "column", minWidth: 0 }}>
            {editor}
            <div style={{ flexShrink: 0, padding: "12px 18px", borderTop: "1px solid var(--border-subtle)", display: "flex", alignItems: "center", gap: 10, background: "var(--bg-panel)" }}>
              <Button leftIcon="send" onClick={doSend} disabled={sending}>{sending ? "Відправляємо…" : "Відправити"}</Button>
              <Button variant="secondary" leftIcon="file-plus-2" onClick={() => setPicker(true)}>Прикріпити документ</Button>
              <div style={{ flex: 1 }} />
              <button onClick={() => setShowSig(s => !s)} title="Підпис" style={{ display: "inline-flex", alignItems: "center", gap: 5, height: 32, padding: "0 8px", border: 0, borderRadius: 6, background: "transparent", color: showSig ? "var(--accent)" : "var(--fg-muted)", fontSize: 12, cursor: "pointer", fontFamily: "inherit" }}><Icon name="signature" size={15} />Підпис</button>
            </div>
          </div>
          {showTemplates && templatesPanel}
        </div>
      </div>
      {modals}
    </div>
  );
}

// ── Десктоп: ліва панель папок ──────────────────────────────────────────────────
function FoldersPanel({ folder, category, onFolder, onCategory, onCompose, counts }) {
  const Item = ({ active, icon, iconColor, children, badge, onClick }) => {
    const [h, setH] = useState(false);
    return (
      <button onClick={onClick} onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
        style={{ display: "flex", alignItems: "center", gap: 10, width: "100%", height: 34, padding: "0 10px", border: 0, borderRadius: 8, background: active ? "var(--accent-soft)" : (h ? "var(--bg-hover)" : "transparent"), color: active ? "var(--accent)" : "var(--fg-secondary)", fontSize: 13, fontWeight: active ? 600 : 500, cursor: "pointer", textAlign: "left", fontFamily: "inherit" }}>
        <Icon name={icon} size={17} color={iconColor && !active ? iconColor : undefined} />
        <span style={{ flex: 1, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{children}</span>
        {badge ? <span style={{ minWidth: 18, height: 18, padding: "0 5px", borderRadius: 999, background: "var(--accent)", color: "#fff", fontSize: 11, fontWeight: 700, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "var(--font-mono)" }}>{badge}</span> : null}
      </button>
    );
  };
  return (
    <div style={{ width: 218, flexShrink: 0, background: "var(--bg-panel)", borderRight: "1px solid var(--border-subtle)", display: "flex", flexDirection: "column", height: "100%" }}>
      <div style={{ padding: 12, borderBottom: "1px solid var(--border-subtle)" }}>
        <Button leftIcon="square-pen" onClick={onCompose} style={{ width: "100%" }}>Нове письмо</Button>
      </div>
      <div style={{ padding: 8, flex: 1, overflowY: "auto" }} className="no-bar">
        <div style={{ display: "flex", flexDirection: "column", gap: 2 }}>
          {MAIL_FOLDERS.map(f => (
            <Item key={f.key} active={folder === f.key} icon={f.icon} badge={f.key === "inbox" ? (counts.unread || 0) : 0}
              onClick={() => onFolder(f.key)}>{f.label}</Item>
          ))}
        </div>
        <div style={{ padding: "16px 10px 6px", fontSize: 11, fontWeight: 600, letterSpacing: ".04em", textTransform: "uppercase", color: "var(--fg-muted)" }}>Категорії</div>
        <div style={{ display: "flex", flexDirection: "column", gap: 2 }}>
          {MAIL_CATEGORIES.map(c => (
            <Item key={c.key} active={category === c.key} icon={c.icon} iconColor={c.color}
              onClick={() => onCategory(category === c.key ? null : c.key)}>{c.label}</Item>
          ))}
        </div>
      </div>
      <div style={{ padding: "10px 14px", borderTop: "1px solid var(--border-subtle)", display: "flex", alignItems: "center", gap: 8 }}>
        <span style={{ width: 7, height: 7, borderRadius: "50%", background: "var(--success)", boxShadow: "0 0 0 3px rgba(16,185,129,.16)" }} />
        <span style={{ fontSize: 11.5, color: "var(--fg-muted)", fontFamily: "var(--font-mono)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{MAILBOX}</span>
      </div>
    </div>
  );
}

function StatusFilter({ value, onChange }) {
  const opts = [{ key: "all", label: "Усі" }, { key: "needs_reply", label: "Потрібна відповідь" }, { key: "in_progress", label: "В роботі" }, { key: "done", label: "Оброблено" }];
  return (
    <div style={{ display: "flex", gap: 2, background: "var(--bg-base)", border: "1px solid var(--border-default)", borderRadius: 8, padding: 2 }}>
      {opts.map(o => {
        const active = value === o.key;
        const c = o.key === "needs_reply" ? "var(--warning)" : o.key === "in_progress" ? "var(--info)" : o.key === "done" ? "var(--success)" : null;
        return (
          <button key={o.key} onClick={() => onChange(o.key)} style={{ height: 26, padding: "0 10px", border: 0, borderRadius: 6, cursor: "pointer", fontFamily: "inherit", display: "inline-flex", alignItems: "center", gap: 6, whiteSpace: "nowrap", background: active ? "var(--bg-raised)" : "transparent", color: active ? "var(--fg-primary)" : "var(--fg-muted)", fontSize: 12, fontWeight: active ? 600 : 500, boxShadow: active ? "var(--shadow-1)" : "none" }}>
            {c && <span style={{ width: 6, height: 6, borderRadius: "50%", background: c }} />}{o.label}
          </button>
        );
      })}
    </div>
  );
}

function MailRow({ mail, selected, onSelect, onOrder }) {
  const [h, setH] = useState(false);
  const who = mail.outgoing ? mail.to : mail.from;
  const hasChips = mail.status || mail.orderId || mail.hasAttach || mail.category || mail.assignedTo;
  return (
    <div onClick={() => onSelect(mail.id)} onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{ display: "flex", gap: 11, alignItems: "flex-start", padding: "12px 16px 13px", cursor: "pointer", position: "relative", borderBottom: "1px solid var(--border-subtle)", background: selected ? "var(--bg-active)" : (h ? "var(--bg-hover)" : (mail.unread ? "rgba(99,102,241,.045)" : "transparent")) }}>
      {selected && <span style={{ position: "absolute", left: 0, top: 0, bottom: 0, width: 2.5, background: "var(--accent)" }} />}
      <div style={{ position: "relative", flexShrink: 0, marginTop: 1 }}>
        <MailAvatar name={who.name} size={36} />
        {mail.unread && <span style={{ position: "absolute", top: -1, right: -1, width: 10, height: 10, borderRadius: "50%", background: "var(--accent)", border: "2px solid var(--bg-base)" }} />}
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 2 }}>
          <span style={{ flex: 1, minWidth: 0, fontSize: 13, fontWeight: mail.unread ? 700 : 600, color: mail.unread ? "var(--fg-primary)" : "var(--fg-secondary)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
            {mail.outgoing && <span style={{ color: "var(--fg-muted)", fontWeight: 500 }}>До: </span>}{who.name}
          </span>
          <span style={{ fontSize: 11, color: mail.unread ? "var(--accent)" : "var(--fg-muted)", fontFamily: "var(--font-mono)", flexShrink: 0, fontWeight: mail.unread ? 600 : 400 }}>{mail.dateLabel} · {mail.time}</span>
        </div>
        <div style={{ fontSize: 13, fontWeight: mail.unread ? 600 : 500, color: mail.unread ? "var(--fg-primary)" : "var(--fg-secondary)", marginBottom: 3, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{mail.subject}</div>
        <div style={{ fontSize: 12.5, color: "var(--fg-muted)", lineHeight: 1.4, marginBottom: hasChips ? 8 : 0, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{mail.preview}</div>
        {hasChips ? (
          <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
            {mail.category && <CategoryChip cat={mail.category} size="sm" />}
            {mail.status && <MailStatusChip status={mail.status} size="sm" />}
            {mail.orderId && <MailOrderBadge id={mail.orderId} size="sm" onClick={onOrder} />}
            {mail.assignedTo && <AssigneeChip name={mail.assignedTo} size="sm" />}
            {mail.hasAttach && <span style={{ display: "inline-flex", alignItems: "center", gap: 3, color: "var(--fg-muted)", fontSize: 11, fontFamily: "var(--font-mono)" }}><Icon name="paperclip" size={12} /></span>}
          </div>
        ) : null}
      </div>
    </div>
  );
}

function SkeletonRow() {
  const bar = (w, h = 10) => <div style={{ width: w, height: h, borderRadius: 5, background: "var(--bg-raised)", animation: "shimmer 1.3s ease-in-out infinite" }} />;
  return (
    <div style={{ display: "flex", gap: 11, padding: "12px 16px 14px", borderBottom: "1px solid var(--border-subtle)" }}>
      <div style={{ width: 36, height: 36, borderRadius: "50%", background: "var(--bg-raised)", animation: "shimmer 1.3s ease-in-out infinite", flexShrink: 0 }} />
      <div style={{ flex: 1 }}>
        <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 8 }}>{bar(120)}{bar(54)}</div>
        {bar(180, 11)}<div style={{ height: 6 }} />{bar("80%", 9)}
      </div>
    </div>
  );
}

function ListPlaceholder({ icon, title, sub, action }) {
  return (
    <div style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", padding: 32, textAlign: "center", gap: 4 }}>
      <div style={{ width: 52, height: 52, borderRadius: 14, background: "var(--bg-raised)", border: "1px solid var(--border-default)", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--fg-muted)", marginBottom: 8 }}><Icon name={icon} size={24} /></div>
      <div style={{ fontSize: 14, fontWeight: 600, color: "var(--fg-secondary)" }}>{title}</div>
      {sub && <div style={{ fontSize: 12.5, color: "var(--fg-muted)", maxWidth: 240 }}>{sub}</div>}
      {action && <div style={{ marginTop: 10 }}>{action}</div>}
    </div>
  );
}

function MailListPanel({ list, folder, category, selected, onSelect, status, onStatus, query, onQuery, loading, error, onOrder, onReload }) {
  const folderObj = MAIL_FOLDERS.find(f => f.key === folder);
  const catObj = category ? catMeta(category) : null;
  const title = (folderObj ? folderObj.label : "Вхідні") + (catObj ? " · " + catObj.label : "");
  let body;
  if (loading) body = <div>{Array.from({ length: 6 }).map((_, i) => <SkeletonRow key={i} />)}</div>;
  else if (error) body = <ListPlaceholder icon="cloud-off" title="Не вдалося завантажити" sub={error} action={<Button variant="secondary" size="sm" leftIcon="refresh-cw" onClick={onReload}>Повторити</Button>} />;
  else if (list.length === 0) body = query ? <ListPlaceholder icon="search-x" title="Нічого не знайдено" sub={`За запитом «${query}» листів немає.`} /> : <ListPlaceholder icon="inbox" title="Немає листів" sub="У цій папці поки порожньо." />;
  else body = <div>{list.map(m => <MailRow key={m.id} mail={m} selected={selected === m.id} onSelect={onSelect} onOrder={onOrder} />)}</div>;
  return (
    <div style={{ width: 384, flexShrink: 0, borderRight: "1px solid var(--border-subtle)", display: "flex", flexDirection: "column", height: "100%", background: "var(--bg-base)" }}>
      <div style={{ padding: "12px 16px", borderBottom: "1px solid var(--border-subtle)", display: "flex", flexDirection: "column", gap: 10 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <h2 style={{ fontSize: 15, fontWeight: 600, color: "var(--fg-primary)", margin: 0 }}>{title}</h2>
          {!loading && !error && list.length > 0 && <span style={{ fontSize: 12, color: "var(--fg-muted)", fontFamily: "var(--font-mono)" }}>{list.length}</span>}
          <div style={{ flex: 1 }} />
          <MIconBtn name="refresh-cw" title="Оновити" size={16} onClick={onReload} />
        </div>
        <div style={{ position: "relative" }}>
          <Icon name="search" size={15} style={{ position: "absolute", left: 11, top: "50%", transform: "translateY(-50%)", color: "var(--fg-muted)" }} />
          <input value={query} onChange={e => onQuery(e.target.value)} placeholder="Пошук за відправником, темою, текстом…"
            style={{ width: "100%", height: 34, boxSizing: "border-box", padding: "0 12px 0 34px", background: "var(--bg-panel)", color: "var(--fg-primary)", border: "1px solid var(--border-default)", borderRadius: 8, fontSize: 12.5, outline: "none", fontFamily: "inherit" }} />
          {query && <button onClick={() => onQuery("")} style={{ position: "absolute", right: 8, top: "50%", transform: "translateY(-50%)", width: 22, height: 22, border: 0, borderRadius: 6, background: "transparent", color: "var(--fg-muted)", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }}><Icon name="x" size={14} /></button>}
        </div>
        <div style={{ overflowX: "auto" }} className="no-bar"><StatusFilter value={status} onChange={onStatus} /></div>
      </div>
      <div style={{ flex: 1, overflowY: "auto", display: "flex", flexDirection: "column" }} className="no-bar">{body}</div>
    </div>
  );
}

// ── Десктоп: читання ───────────────────────────────────────────────────────────
function StatusMenu({ status, onChange }) {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  useEffect(() => { const h = e => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); }; document.addEventListener("mousedown", h); return () => document.removeEventListener("mousedown", h); }, []);
  const cur = MAIL_STATUS[status];
  return (
    <div ref={ref} style={{ position: "relative" }}>
      <button onClick={() => setOpen(o => !o)} style={{ display: "inline-flex", alignItems: "center", gap: 6, height: 34, padding: "0 10px", background: cur ? cur.soft : "var(--bg-raised)", border: cur ? "1px solid transparent" : "1px solid var(--border-default)", borderRadius: 8, cursor: "pointer", fontFamily: "inherit", fontSize: 12.5, fontWeight: 600, color: cur ? cur.color : "var(--fg-secondary)" }}>
        {cur ? <><Icon name={cur.icon} size={13} />{cur.label}</> : <><Icon name="circle-dashed" size={14} />Без статусу</>}
        <Icon name="chevron-down" size={14} style={{ opacity: .7 }} />
      </button>
      {open && (
        <div style={{ position: "absolute", top: 40, right: 0, width: 220, background: "var(--bg-raised)", border: "1px solid var(--border-default)", borderRadius: 10, boxShadow: "var(--shadow-2)", padding: 6, zIndex: 40, animation: "popIn 120ms ease" }}>
          {Object.entries(MAIL_STATUS).map(([k, s]) => (
            <button key={k} onClick={() => { onChange(k); setOpen(false); }} style={{ display: "flex", alignItems: "center", gap: 8, width: "100%", height: 34, padding: "0 8px", border: 0, borderRadius: 7, background: status === k ? "var(--bg-hover)" : "transparent", color: s.color, fontSize: 13, fontWeight: 500, cursor: "pointer", textAlign: "left", fontFamily: "inherit" }}
              onMouseEnter={e => e.currentTarget.style.background = "var(--bg-hover)"} onMouseLeave={e => e.currentTarget.style.background = status === k ? "var(--bg-hover)" : "transparent"}>
              <Icon name={s.icon} size={14} /><span style={{ flex: 1, color: "var(--fg-primary)" }}>{s.label}</span>
              {status === k && <Icon name="check" size={14} color="var(--accent)" />}
            </button>
          ))}
        </div>
      )}
    </div>
  );
}

// Відкрити/скачати вкладення: звичайний <a href> НЕ несе Authorization (токен додає
// лише пропатчений window.fetch у index.html) → тягнемо blob через fetch і відкриваємо його.
async function mailOpenAttachment(att, asDownload) {
  try {
    const r = await fetch("/api/mail/attachment/" + att.id);
    if (!r.ok) { let j = {}; try { j = await r.json(); } catch {} throw new Error(j.error || ("HTTP " + r.status)); }
    const blob = await r.blob();
    const u = URL.createObjectURL(blob);
    if (asDownload) {
      const a = document.createElement("a"); a.href = u; a.download = att.name || "file"; document.body.appendChild(a); a.click(); a.remove();
    } else {
      window.open(u, "_blank");
    }
    setTimeout(() => URL.revokeObjectURL(u), 60000);
  } catch (e) { window.alert("Не вдалося відкрити файл: " + e.message); }
}

function AttachChip({ att }) {
  const [h, setH] = useState(false);
  const kb = att.size ? Math.max(1, Math.round(att.size / 1024)) + " КБ" : "";
  const btn = { width: 30, height: 30, borderRadius: 8, display: "flex", alignItems: "center", justifyContent: "center", color: "var(--fg-secondary)", border: 0, background: "transparent", cursor: "pointer" };
  return (
    <div onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)} style={{ display: "flex", alignItems: "center", gap: 10, padding: "8px 12px 8px 10px", background: "var(--bg-raised)", border: "1px solid " + (h ? "var(--border-strong)" : "var(--border-default)"), borderRadius: 10, minWidth: 220 }}>
      <div style={{ width: 34, height: 34, borderRadius: 8, background: "rgba(244,63,94,.12)", color: "#F87171", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}><Icon name="file-text" size={18} /></div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 12.5, fontWeight: 600, color: "var(--fg-primary)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{att.name}</div>
        <div style={{ fontSize: 11, color: "var(--fg-muted)", fontFamily: "var(--font-mono)" }}>{kb}</div>
      </div>
      <div style={{ display: "flex", gap: 2 }}>
        <button onClick={() => mailOpenAttachment(att, false)} title="Перегляд" style={btn}><Icon name="eye" size={15} /></button>
        <button onClick={() => mailOpenAttachment(att, true)} title="Завантажити" style={btn}><Icon name="download" size={15} /></button>
      </div>
    </div>
  );
}

function LinkedOrderCard({ order, onOrder, onUnlink }) {
  const key = orderStatusKey(order.status);
  return (
    <div style={{ background: "var(--bg-panel)", border: "1px solid var(--border-default)", borderRadius: 12, padding: 14 }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 12 }}>
        <Icon name="package" size={15} color="var(--accent)" />
        <span style={{ fontSize: 11, fontWeight: 600, letterSpacing: ".04em", textTransform: "uppercase", color: "var(--fg-muted)" }}>Прив'язане замовлення</span>
        <div style={{ flex: 1 }} />
        <MIconBtn name="link-2-off" title="Відв'язати" size={14} onClick={onUnlink} style={{ width: 26, height: 26 }} />
      </div>
      <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 4 }}>
        <span style={{ fontSize: 17, fontWeight: 700, color: "var(--fg-primary)", fontFamily: "var(--font-mono)" }}>№{order.order_id}</span>
        <span style={{ fontSize: 17, fontWeight: 700, color: "var(--fg-primary)", fontFamily: "var(--font-mono)" }}>{mmoney(order.total)}</span>
      </div>
      <div style={{ fontSize: 13, color: "var(--fg-secondary)", marginBottom: 2 }}>{order.client}</div>
      {order.phone && <div style={{ fontSize: 12, color: "var(--fg-muted)", marginBottom: 4, fontFamily: "var(--font-mono)" }}>{order.phone}</div>}
      {order.ttn && <div style={{ fontSize: 12, color: "var(--fg-muted)", marginBottom: 10 }}>ТТН: <span style={{ fontFamily: "var(--font-mono)" }}>{order.ttn}</span></div>}
      <div style={{ display: "flex", alignItems: "center", gap: 10, justifyContent: "space-between", marginTop: 8 }}>
        <StatusChip status={key} />
        <span style={{ fontSize: 12, color: "var(--fg-muted)" }}>{order.created || ""}</span>
      </div>
    </div>
  );
}

function UnlinkedOrderCard({ suggestion, onOpenLink, onQuickLink }) {
  return (
    <div style={{ background: "var(--bg-panel)", border: "1px dashed var(--border-strong)", borderRadius: 12, padding: 14 }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: suggestion ? 12 : 10 }}>
        <Icon name="link" size={15} color="var(--fg-muted)" />
        <span style={{ fontSize: 11, fontWeight: 600, letterSpacing: ".04em", textTransform: "uppercase", color: "var(--fg-muted)" }}>Замовлення не прив'язане</span>
      </div>
      {suggestion && (
        <button onClick={() => onQuickLink(suggestion.order_id, suggestion)} style={{ display: "flex", alignItems: "center", gap: 10, width: "100%", textAlign: "left", padding: "10px 12px", marginBottom: 10, borderRadius: 10, cursor: "pointer", fontFamily: "inherit", background: "var(--accent-soft)", border: "1px solid rgba(99,102,241,.28)" }}>
          <Icon name="sparkles" size={16} color="var(--accent)" />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 12.5, fontWeight: 600, color: "var(--fg-primary)" }}><span style={{ fontFamily: "var(--font-mono)" }}>№{suggestion.order_id}</span> · {suggestion.client} · <span style={{ fontFamily: "var(--font-mono)" }}>{mmoney(suggestion.total)}</span></div>
            <div style={{ fontSize: 11.5, color: "var(--accent)", marginTop: 2 }}>{suggestion.reason}</div>
          </div>
          <span style={{ display: "inline-flex", alignItems: "center", gap: 4, fontSize: 12, fontWeight: 600, color: "var(--accent)", flexShrink: 0 }}>Прив'язати<Icon name="check" size={14} /></span>
        </button>
      )}
      <Button variant="secondary" size="sm" leftIcon="search" onClick={onOpenLink} style={{ width: "100%" }}>Знайти замовлення вручну</Button>
    </div>
  );
}

function ReaderEmpty() {
  return (
    <div style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 6, color: "var(--fg-muted)" }}>
      <div style={{ width: 64, height: 64, borderRadius: 16, background: "var(--bg-panel)", border: "1px solid var(--border-default)", display: "flex", alignItems: "center", justifyContent: "center", marginBottom: 8 }}><Icon name="mail-open" size={28} /></div>
      <div style={{ fontSize: 14, fontWeight: 600, color: "var(--fg-secondary)" }}>Оберіть лист</div>
      <div style={{ fontSize: 12.5 }}>Виберіть лист зі списку, щоб прочитати його тут.</div>
    </div>
  );
}

function MailBody({ email }) {
  if (email.body_html) return <div style={{ fontSize: 14, lineHeight: 1.65, color: "var(--fg-secondary)", wordBreak: "break-word" }} dangerouslySetInnerHTML={{ __html: email.body_html }} />;
  const paras = String(email.body_text || "").split(/\n{2,}/).filter(Boolean);
  return <div style={{ fontSize: 14, lineHeight: 1.65, color: "var(--fg-secondary)", whiteSpace: "pre-wrap" }}>{paras.length ? paras.map((p, i) => <p key={i} style={{ margin: "0 0 14px" }}>{p}</p>) : <span style={{ color: "var(--fg-muted)" }}>(порожній лист)</span>}</div>;
}

function MailReader({ data, loading, managers, onAssign, onReply, onForward, onArchive, onStatus, onOrder, onOpenLink, onQuickLink, onUnlink }) {
  if (loading) return <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", color: "var(--fg-muted)" }}><Icon name="loader" size={22} style={{ animation: "spin 1s linear infinite" }} /></div>;
  if (!data) return <ReaderEmpty />;
  const { email, attachments, order, suggestion } = data;
  const m = mapMailRow(email);
  const who = m.outgoing ? { name: email.to_addr || "", email: email.to_addr || "" } : m.from;
  return (
    <div style={{ flex: 1, minWidth: 0, display: "flex", flexDirection: "column", height: "100%", background: "var(--bg-base)" }}>
      <div style={{ height: 56, flexShrink: 0, display: "flex", alignItems: "center", padding: "0 16px", gap: 6, borderBottom: "1px solid var(--border-subtle)", background: "var(--bg-panel)" }}>
        <Button size="sm" leftIcon="reply" onClick={() => onReply(email, order)}>Відповісти</Button>
        <Button size="sm" variant="ghost" leftIcon="forward" onClick={() => onForward(email, order)}>Переслати</Button>
        <div style={{ flex: 1 }} />
        <AssignMenu value={email.assigned_to || ""} managers={managers} onChange={m2 => onAssign(email.id, m2)} />
        <StatusMenu status={m.status} onChange={s => onStatus(email.id, s)} />
        <div style={{ width: 1, height: 22, background: "var(--border-default)", margin: "0 4px" }} />
        <MIconBtn name="archive" title="Архівувати" onClick={() => onArchive(email.id)} />
      </div>
      <div style={{ flex: 1, overflowY: "auto" }} className="no-bar">
        <div style={{ maxWidth: 760, margin: "0 auto", padding: "24px 28px 40px" }}>
          <div style={{ display: "flex", alignItems: "flex-start", gap: 12, marginBottom: 18 }}>
            <h1 style={{ flex: 1, fontSize: 21, fontWeight: 600, color: "var(--fg-primary)", margin: 0, lineHeight: 1.3, letterSpacing: "-0.01em" }}>{m.subject}</h1>
            {m.status && <MailStatusChip status={m.status} />}
          </div>
          <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 20 }}>
            <MailAvatar name={who.name} size={40} />
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
                <span style={{ fontSize: 14, fontWeight: 600, color: "var(--fg-primary)" }}>{who.name || who.email}</span>
                <span style={{ fontSize: 12.5, color: "var(--fg-muted)", fontFamily: "var(--font-mono)" }}>&lt;{who.email}&gt;</span>
              </div>
              <div style={{ fontSize: 12, color: "var(--fg-muted)", marginTop: 1 }}>{m.outgoing ? `Від ${MAILBOX}` : `Кому: ${MAILBOX}`} · {m.dateFull}</div>
            </div>
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 264px", gap: 20, alignItems: "start" }}>
            <div style={{ minWidth: 0 }}>
              <MailBody email={email} />
              {attachments && attachments.length > 0 && (
                <div style={{ marginTop: 16 }}>
                  <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: ".04em", textTransform: "uppercase", color: "var(--fg-muted)", marginBottom: 10, display: "flex", alignItems: "center", gap: 6 }}><Icon name="paperclip" size={13} />Вкладення · {attachments.length}</div>
                  <div style={{ display: "flex", flexWrap: "wrap", gap: 10 }}>{attachments.map(a => <AttachChip key={a.id} att={a} />)}</div>
                </div>
              )}
            </div>
            <div style={{ position: "sticky", top: 0 }}>
              {order ? <LinkedOrderCard order={order} onOrder={onOrder} onUnlink={() => onUnlink(email.id)} />
                : <UnlinkedOrderCard suggestion={suggestion} onOpenLink={() => onOpenLink(email)} onQuickLink={(id, o) => onQuickLink(email.id, id, o)} />}
            </div>
          </div>
        </div>
      </div>
      <div style={{ flexShrink: 0, padding: "12px 16px", borderTop: "1px solid var(--border-subtle)", background: "var(--bg-panel)" }}>
        <button onClick={() => onReply(email, order)} style={{ display: "flex", alignItems: "center", gap: 10, width: "100%", height: 40, padding: "0 14px", background: "var(--bg-base)", border: "1px solid var(--border-default)", borderRadius: 10, color: "var(--fg-muted)", fontSize: 13, cursor: "text", fontFamily: "inherit", textAlign: "left" }}>
          <Icon name="reply" size={16} /><span style={{ flex: 1 }}>Відповісти {(who.name || who.email).split(" ")[0]}…</span>
        </button>
      </div>
    </div>
  );
}

// ── Мобільні підкомпоненти ──────────────────────────────────────────────────────
function groupByDate(emails) {
  const out = []; const idx = {};
  emails.forEach(m => { if (!(m.dateLabel in idx)) { idx[m.dateLabel] = out.length; out.push({ label: m.dateLabel, items: [] }); } out[idx[m.dateLabel]].items.push(m); });
  return out;
}
function MRow({ mail, onOpen, last }) {
  const who = mail.outgoing ? mail.to : mail.from;
  const hasChips = mail.status || mail.orderId || mail.hasAttach || mail.category || mail.assignedTo;
  return (
    <button onClick={() => onOpen(mail.id)} style={{ display: "flex", gap: 12, alignItems: "flex-start", width: "100%", textAlign: "left", border: 0, cursor: "pointer", fontFamily: "inherit", padding: "13px 14px", background: mail.unread ? "var(--bg-raised)" : "transparent", borderBottom: last ? "none" : "1px solid var(--border-subtle)" }}>
      <div style={{ position: "relative", flexShrink: 0, marginTop: 1 }}>
        <MailAvatar name={who.name} size={44} />
        {mail.unread && <span style={{ position: "absolute", top: -1, right: -1, width: 12, height: 12, borderRadius: "50%", background: "var(--accent)", border: "2.5px solid var(--bg-raised)" }} />}
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 2 }}>
          <span style={{ flex: 1, minWidth: 0, fontSize: 14.5, fontWeight: mail.unread ? 700 : 600, color: mail.unread ? "var(--fg-primary)" : "var(--fg-secondary)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{mail.outgoing ? "До: " : ""}{who.name}</span>
          <span style={{ fontSize: 11.5, color: mail.unread ? "var(--accent)" : "var(--fg-muted)", fontFamily: "var(--font-mono)", flexShrink: 0, fontWeight: mail.unread ? 600 : 400 }}>{mail.time}</span>
        </div>
        <div style={{ fontSize: 13.5, fontWeight: mail.unread ? 600 : 500, color: mail.unread ? "var(--fg-primary)" : "var(--fg-secondary)", marginBottom: 3, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{mail.subject}</div>
        <div style={{ fontSize: 12.5, color: "var(--fg-muted)", lineHeight: 1.45, marginBottom: hasChips ? 9 : 0, display: "-webkit-box", WebkitLineClamp: 1, WebkitBoxOrient: "vertical", overflow: "hidden" }}>{mail.preview}</div>
        {hasChips ? (
          <div style={{ display: "flex", alignItems: "center", gap: 7, flexWrap: "wrap" }}>
            {mail.category && <CategoryChip cat={mail.category} size="sm" />}
            {mail.status && <MailStatusChip status={mail.status} size="sm" />}
            {mail.orderId && <MailOrderBadge id={mail.orderId} size="sm" />}
            {mail.assignedTo && <AssigneeChip name={mail.assignedTo} size="sm" />}
            {mail.hasAttach && <span style={{ display: "inline-flex", alignItems: "center", color: "var(--fg-muted)" }}><Icon name="paperclip" size={13} /></span>}
          </div>
        ) : null}
      </div>
    </button>
  );
}
function MSkeleton({ last }) {
  const bar = (w, h = 11) => <div style={{ width: w, height: h, borderRadius: 5, background: "var(--bg-base)", animation: "shimmer 1.3s ease-in-out infinite" }} />;
  return <div style={{ display: "flex", gap: 12, padding: "14px 14px", borderBottom: last ? "none" : "1px solid var(--border-subtle)" }}>
    <div style={{ width: 44, height: 44, borderRadius: "50%", background: "var(--bg-base)", animation: "shimmer 1.3s ease-in-out infinite", flexShrink: 0 }} />
    <div style={{ flex: 1 }}><div style={{ display: "flex", justifyContent: "space-between", marginBottom: 9 }}>{bar(120)}{bar(38)}</div>{bar(190, 11)}<div style={{ height: 7 }} />{bar("80%", 10)}</div>
  </div>;
}
function MPlaceholder({ icon, title, sub, action }) {
  return <div style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", padding: 32, textAlign: "center", gap: 5 }}>
    <div style={{ width: 60, height: 60, borderRadius: 16, background: "var(--bg-raised)", border: "1px solid var(--border-default)", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--fg-muted)", marginBottom: 8 }}><Icon name={icon} size={28} /></div>
    <div style={{ fontSize: 15, fontWeight: 600, color: "var(--fg-secondary)" }}>{title}</div>
    {sub && <div style={{ fontSize: 13, color: "var(--fg-muted)", maxWidth: 230, lineHeight: 1.45 }}>{sub}</div>}
    {action && <div style={{ marginTop: 12 }}>{action}</div>}
  </div>;
}
function FolderSheet({ folder, category, onPick, onClose, counts }) {
  return (
    <div onClick={onClose} style={{ position: "absolute", inset: 0, zIndex: 60, background: "rgba(0,0,0,.5)", display: "flex", flexDirection: "column", justifyContent: "flex-end", animation: "fade 140ms ease" }}>
      <div onClick={e => e.stopPropagation()} style={{ background: "var(--bg-raised)", borderRadius: "18px 18px 0 0", padding: "8px 12px 20px", animation: "msheetUp 200ms var(--ease)" }}>
        <div style={{ width: 36, height: 4, borderRadius: 2, background: "var(--border-strong)", margin: "8px auto 12px" }} />
        {MAIL_FOLDERS.map(f => (
          <button key={f.key} onClick={() => onPick(f.key, null)} style={{ display: "flex", alignItems: "center", gap: 12, width: "100%", height: 48, padding: "0 10px", border: 0, borderRadius: 10, background: folder === f.key && !category ? "var(--accent-soft)" : "transparent", color: folder === f.key && !category ? "var(--accent)" : "var(--fg-primary)", fontSize: 15, fontWeight: 500, cursor: "pointer", fontFamily: "inherit", textAlign: "left" }}>
            <Icon name={f.icon} size={20} /><span style={{ flex: 1 }}>{f.label}</span>
            {f.key === "inbox" && counts.unread ? <span style={{ minWidth: 20, height: 20, padding: "0 6px", borderRadius: 999, background: "var(--accent)", color: "#fff", fontSize: 12, fontWeight: 700, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "var(--font-mono)" }}>{counts.unread}</span> : null}
          </button>
        ))}
        <div style={{ height: 1, background: "var(--border-subtle)", margin: "8px 6px" }} />
        <div style={{ fontSize: 11, fontWeight: 600, color: "var(--fg-muted)", padding: "2px 10px 6px", textTransform: "uppercase", letterSpacing: ".04em" }}>Категорії</div>
        {MAIL_CATEGORIES.map(c => (
          <button key={c.key} onClick={() => onPick("inbox", c.key)} style={{ display: "flex", alignItems: "center", gap: 12, width: "100%", height: 44, padding: "0 12px", border: 0, borderRadius: 10, background: category === c.key ? "var(--accent-soft)" : "transparent", color: category === c.key ? "var(--accent)" : "var(--fg-primary)", fontSize: 14, cursor: "pointer", fontFamily: "inherit", textAlign: "left" }}>
            <Icon name={c.icon} size={18} color={category === c.key ? undefined : c.color} /><span style={{ flex: 1 }}>{c.label}</span>
          </button>
        ))}
      </div>
    </div>
  );
}
function StatusSheet({ current, onPick, onClose }) {
  return <div onClick={onClose} style={{ position: "absolute", inset: 0, zIndex: 70, background: "rgba(0,0,0,.5)", display: "flex", flexDirection: "column", justifyContent: "flex-end", animation: "fade 140ms ease" }}>
    <div onClick={e => e.stopPropagation()} style={{ background: "var(--bg-raised)", borderRadius: "18px 18px 0 0", padding: "8px 12px 22px", animation: "msheetUp 200ms var(--ease)" }}>
      <div style={{ width: 36, height: 4, borderRadius: 2, background: "var(--border-strong)", margin: "8px auto 14px" }} />
      <div style={{ fontSize: 12, fontWeight: 600, color: "var(--fg-muted)", padding: "0 6px 8px", textTransform: "uppercase", letterSpacing: ".04em" }}>Статус листа</div>
      {Object.entries(MAIL_STATUS).map(([k, s]) => <button key={k} onClick={() => onPick(k)} style={{ display: "flex", alignItems: "center", gap: 11, width: "100%", height: 50, padding: "0 10px", border: 0, borderRadius: 11, background: current === k ? "var(--bg-hover)" : "transparent", cursor: "pointer", fontFamily: "inherit", textAlign: "left" }}>
        <span style={{ width: 30, height: 30, borderRadius: 8, background: s.soft, color: s.color, display: "flex", alignItems: "center", justifyContent: "center" }}><Icon name={s.icon} size={16} /></span>
        <span style={{ flex: 1, fontSize: 15, color: "var(--fg-primary)", fontWeight: 500 }}>{s.label}</span>
        {current === k && <Icon name="check" size={18} color="var(--accent)" />}
      </button>)}
    </div>
  </div>;
}
function MListScreen({ list, folder, category, status, onStatus, query, onQuery, loading, error, onOpen, onCompose, onFolderSheet, onReload, onExit, counts }) {
  const folderObj = MAIL_FOLDERS.find(f => f.key === folder);
  const catObj = category ? catMeta(category) : null;
  const title = catObj ? catObj.label : (folderObj ? folderObj.label : "Вхідні");
  const chips = [{ k: "all", t: "Усі" }, { k: "needs_reply", t: "Відповідь" }, { k: "in_progress", t: "В роботі" }, { k: "done", t: "Оброблено" }];
  const card = (children) => <div style={{ background: "var(--bg-panel)", border: "1px solid var(--border-subtle)", borderRadius: 16, overflow: "hidden" }}>{children}</div>;
  let body;
  if (loading) body = <div style={{ padding: "14px 14px 24px" }}>{card(Array.from({ length: 6 }).map((_, i) => <MSkeleton key={i} last={i === 5} />))}</div>;
  else if (error) body = <MPlaceholder icon="cloud-off" title="Немає зв'язку" sub={error} action={<Button variant="secondary" size="md" leftIcon="refresh-cw" onClick={onReload}>Повторити</Button>} />;
  else if (list.length === 0) body = query ? <MPlaceholder icon="search-x" title="Нічого не знайдено" sub={`За запитом «${query}» листів немає.`} /> : <MPlaceholder icon="inbox" title="Немає листів" sub="У цій папці поки порожньо." />;
  else body = <div style={{ padding: "6px 14px 24px", display: "flex", flexDirection: "column", gap: 16 }}>{groupByDate(list).map(g => (
    <div key={g.label}><div style={{ fontSize: 11.5, fontWeight: 600, color: "var(--fg-muted)", textTransform: "uppercase", letterSpacing: ".05em", padding: "0 6px 8px" }}>{g.label}</div>{card(g.items.map((m, i) => <MRow key={m.id} mail={m} onOpen={onOpen} last={i === g.items.length - 1} />))}</div>
  ))}</div>;
  return (
    <div style={{ display: "flex", flexDirection: "column", height: "100%", background: "var(--bg-base)" }}>
      <div style={{ flexShrink: 0, padding: "calc(6px + env(safe-area-inset-top, 0px)) 16px 10px", background: "var(--bg-base)" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 10 }}>
          {onExit && <button onClick={onExit} title="Назад" style={{ width: 32, height: 32, border: 0, background: "transparent", color: "var(--fg-secondary)", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, marginLeft: -6 }}><Icon name="arrow-left" size={22} /></button>}
          <button onClick={onFolderSheet} style={{ display: "inline-flex", alignItems: "center", gap: 8, border: 0, background: "transparent", color: "var(--fg-primary)", cursor: "pointer", fontFamily: "inherit", padding: 0 }}>
            <span style={{ fontSize: 19, fontWeight: 700, letterSpacing: "-0.02em" }}>{title}</span>
            <span style={{ width: 22, height: 22, borderRadius: "50%", background: "var(--bg-raised)", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--fg-secondary)" }}><Icon name="chevron-down" size={15} /></span>
          </button>
          {counts.unread > 0 && <span style={{ height: 22, padding: "0 9px", borderRadius: 999, background: "var(--accent-soft)", color: "var(--accent)", fontSize: 12, fontWeight: 700, display: "inline-flex", alignItems: "center", fontFamily: "var(--font-mono)" }}>{counts.unread} нових</span>}
          <div style={{ flex: 1 }} />
          <MIconBtn name="refresh-cw" title="Оновити" size={18} onClick={onReload} />
        </div>
        <div style={{ position: "relative", marginBottom: 12 }}>
          <Icon name="search" size={17} style={{ position: "absolute", left: 13, top: "50%", transform: "translateY(-50%)", color: "var(--fg-muted)" }} />
          <input value={query} onChange={e => onQuery(e.target.value)} placeholder="Пошук пошти…" style={{ width: "100%", height: 44, boxSizing: "border-box", padding: "0 14px 0 40px", background: "var(--bg-panel)", color: "var(--fg-primary)", border: "1px solid var(--border-subtle)", borderRadius: 14, fontSize: 14.5, outline: "none", fontFamily: "inherit" }} />
        </div>
        <div style={{ display: "flex", gap: 7, overflowX: "auto", margin: "0 -16px", padding: "0 16px" }} className="no-bar">
          {chips.map(c => { const active = status === c.k; const col = c.k === "needs_reply" ? "var(--warning)" : c.k === "in_progress" ? "var(--info)" : c.k === "done" ? "var(--success)" : null;
            return <button key={c.k} onClick={() => onStatus(c.k)} style={{ flexShrink: 0, height: 34, padding: "0 14px", borderRadius: 999, cursor: "pointer", fontFamily: "inherit", display: "inline-flex", alignItems: "center", gap: 6, border: active ? "1px solid var(--accent)" : "1px solid var(--border-default)", background: active ? "var(--accent)" : "var(--bg-panel)", color: active ? "#fff" : "var(--fg-secondary)", fontSize: 13, fontWeight: active ? 600 : 500 }}>
              {col && <span style={{ width: 6, height: 6, borderRadius: "50%", background: active ? "#fff" : col }} />}{c.t}
            </button>; })}
        </div>
      </div>
      <div style={{ flex: 1, overflowY: "auto", display: "flex", flexDirection: "column" }} className="no-bar">{body}</div>
      <button onClick={onCompose} style={{ position: "absolute", right: 18, bottom: 22, width: 56, height: 56, borderRadius: 18, border: 0, background: "var(--accent)", color: "#fff", boxShadow: "0 8px 24px rgba(99,102,241,.45)", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 20 }}><Icon name="square-pen" size={24} /></button>
    </div>
  );
}
function MReadScreen({ data, loading, onBack, onReply, onStatusSheet, onAssignSheet, onLink, onArchive, onUnlink, onQuickLink }) {
  if (loading || !data) return <div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
    <div style={{ flexShrink: 0, minHeight: 52, display: "flex", alignItems: "center", padding: "0 8px 0 4px", paddingTop: "env(safe-area-inset-top, 0px)", borderBottom: "1px solid var(--border-subtle)", background: "var(--bg-panel)" }}><button onClick={onBack} style={{ width: 40, height: 40, border: 0, background: "transparent", color: "var(--fg-secondary)", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }}><Icon name="chevron-left" size={24} /></button></div>
    <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", color: "var(--fg-muted)" }}><Icon name="loader" size={22} style={{ animation: "spin 1s linear infinite" }} /></div>
  </div>;
  const { email, attachments, order, suggestion } = data;
  const m = mapMailRow(email);
  const who = m.outgoing ? { name: email.to_addr || "", email: email.to_addr || "" } : m.from;
  return (
    <div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
      <div style={{ flexShrink: 0, minHeight: 52, display: "flex", alignItems: "center", padding: "0 8px 0 4px", paddingTop: "env(safe-area-inset-top, 0px)", gap: 4, borderBottom: "1px solid var(--border-subtle)", background: "var(--bg-panel)" }}>
        <button onClick={onBack} style={{ width: 40, height: 40, border: 0, background: "transparent", color: "var(--fg-secondary)", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }}><Icon name="chevron-left" size={24} /></button>
        <span style={{ flex: 1, fontSize: 13, color: "var(--fg-muted)" }}>{MAIL_FOLDERS.find(f => f.key === email.folder)?.label || "Вхідні"}</span>
        <button onClick={() => onArchive(email.id)} style={{ width: 40, height: 40, border: 0, background: "transparent", color: "var(--fg-secondary)", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }}><Icon name="archive" size={19} /></button>
      </div>
      <div style={{ flex: 1, overflowY: "auto", padding: "18px 18px 24px" }} className="no-bar">
        <div style={{ marginBottom: 14 }}><h1 style={{ fontSize: 19, fontWeight: 600, color: "var(--fg-primary)", margin: 0, lineHeight: 1.3 }}>{m.subject}</h1></div>
        {(m.status || m.category || m.assignedTo) && (
          <div style={{ marginBottom: 14, display: "flex", gap: 7, flexWrap: "wrap" }}>
            {m.category && <CategoryChip cat={m.category} />}
            {m.status && <MailStatusChip status={m.status} />}
            {m.assignedTo && <AssigneeChip name={m.assignedTo} />}
          </div>
        )}
        <div style={{ display: "flex", alignItems: "center", gap: 11, marginBottom: 18 }}>
          <MailAvatar name={who.name} size={42} />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 14.5, fontWeight: 600, color: "var(--fg-primary)" }}>{who.name || who.email}</div>
            <div style={{ fontSize: 12, color: "var(--fg-muted)", fontFamily: "var(--font-mono)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{who.email}</div>
            <div style={{ fontSize: 11.5, color: "var(--fg-muted)", marginTop: 1 }}>{m.dateFull}</div>
          </div>
        </div>
        {order ? (
          <div style={{ background: "var(--bg-panel)", border: "1px solid var(--border-default)", borderRadius: 12, padding: 14, marginBottom: 18 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 7, marginBottom: 10 }}><Icon name="package" size={14} color="var(--accent)" /><span style={{ fontSize: 10.5, fontWeight: 600, letterSpacing: ".04em", textTransform: "uppercase", color: "var(--fg-muted)", flex: 1 }}>Замовлення</span><button onClick={() => onUnlink(email.id)} style={{ border: 0, background: "transparent", color: "var(--fg-muted)", cursor: "pointer", display: "flex" }}><Icon name="link-2-off" size={15} /></button></div>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 3 }}><span style={{ fontSize: 16, fontWeight: 700, fontFamily: "var(--font-mono)", color: "var(--fg-primary)" }}>№{order.order_id}</span><span style={{ fontSize: 16, fontWeight: 700, fontFamily: "var(--font-mono)", color: "var(--fg-primary)" }}>{mmoney(order.total)}</span></div>
            <div style={{ fontSize: 13, color: "var(--fg-secondary)", marginBottom: 10 }}>{order.client}</div>
            <StatusChip status={orderStatusKey(order.status)} />
          </div>
        ) : (
          <div style={{ background: "var(--bg-panel)", border: "1px dashed var(--border-strong)", borderRadius: 12, padding: 14, marginBottom: 18 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 7, marginBottom: suggestion ? 10 : 0 }}><Icon name="link" size={14} color="var(--fg-muted)" /><span style={{ fontSize: 10.5, fontWeight: 600, letterSpacing: ".04em", textTransform: "uppercase", color: "var(--fg-muted)", flex: 1 }}>Не прив'язане</span><button onClick={() => onLink(email)} style={{ border: 0, background: "transparent", color: "var(--accent)", cursor: "pointer", display: "flex", fontSize: 12.5, fontWeight: 600, fontFamily: "inherit", alignItems: "center", gap: 3 }}><Icon name="search" size={14} />Знайти</button></div>
            {suggestion && <button onClick={() => onQuickLink(email.id, suggestion.order_id, suggestion)} style={{ display: "flex", alignItems: "center", gap: 9, width: "100%", textAlign: "left", padding: "10px 12px", borderRadius: 10, cursor: "pointer", fontFamily: "inherit", background: "var(--accent-soft)", border: "1px solid rgba(99,102,241,.28)" }}><Icon name="sparkles" size={16} color="var(--accent)" /><div style={{ flex: 1, minWidth: 0 }}><div style={{ fontSize: 13, fontWeight: 600, color: "var(--fg-primary)" }}><span style={{ fontFamily: "var(--font-mono)" }}>№{suggestion.order_id}</span> · {suggestion.client}</div><div style={{ fontSize: 11.5, color: "var(--accent)", marginTop: 1 }}>{suggestion.reason}</div></div><Icon name="check" size={16} color="var(--accent)" /></button>}
          </div>
        )}
        <MailBody email={email} />
        {attachments && attachments.length > 0 && (
          <div style={{ marginTop: 16 }}>
            <div style={{ fontSize: 10.5, fontWeight: 600, letterSpacing: ".04em", textTransform: "uppercase", color: "var(--fg-muted)", marginBottom: 9, display: "flex", alignItems: "center", gap: 6 }}><Icon name="paperclip" size={13} />Вкладення</div>
            <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>{attachments.map(a => {
              const kb = a.size ? Math.max(1, Math.round(a.size / 1024)) + " КБ" : "";
              return <button key={a.id} onClick={() => mailOpenAttachment(a, false)} style={{ display: "flex", alignItems: "center", gap: 11, padding: "10px 12px", background: "var(--bg-raised)", border: "1px solid var(--border-default)", borderRadius: 10, color: "inherit", width: "100%", textAlign: "left", cursor: "pointer", fontFamily: "inherit" }}>
                <div style={{ width: 38, height: 38, borderRadius: 9, background: "rgba(244,63,94,.12)", color: "#F87171", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}><Icon name="file-text" size={19} /></div>
                <div style={{ flex: 1, minWidth: 0 }}><div style={{ fontSize: 13.5, fontWeight: 600, color: "var(--fg-primary)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{a.name}</div><div style={{ fontSize: 11.5, color: "var(--fg-muted)", fontFamily: "var(--font-mono)" }}>{kb}</div></div>
                <Icon name="download" size={17} color="var(--fg-secondary)" />
              </button>;
            })}</div>
          </div>
        )}
      </div>
      <div style={{ flexShrink: 0, padding: "10px 14px", borderTop: "1px solid var(--border-subtle)", background: "var(--bg-panel)", display: "flex", gap: 8 }}>
        <Button size="lg" leftIcon="reply" onClick={() => onReply(email, order)} style={{ flex: 1 }}>Відповісти</Button>
        <Button size="lg" variant="secondary" leftIcon={MAIL_STATUS[m.status]?.icon || "circle-dashed"} onClick={() => onStatusSheet(email)} style={{ paddingLeft: 14, paddingRight: 14 }}>Статус</Button>
        <Button size="lg" variant="secondary" onClick={() => onAssignSheet(email)} style={{ width: 48, paddingLeft: 0, paddingRight: 0 }}><Icon name={email.assigned_to ? "user-check" : "user-plus"} size={18} /></Button>
      </div>
    </div>
  );
}

// ── Головний компонент ──────────────────────────────────────────────────────────
function Mail({ isMobile, showToast, onExit }) {
  const [folder, setFolder] = useState("inbox");
  const [category, setCategory] = useState(null);
  const [status, setStatus] = useState("all");
  const [query, setQuery] = useState("");
  const [debQuery, setDebQuery] = useState("");
  const [list, setList] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [counts, setCounts] = useState({ unread: 0, needsReply: 0 });
  const [managers, setManagers] = useState([]);
  const [selectedId, setSelectedId] = useState(null);
  const [reader, setReader] = useState(null);       // {email, attachments, order, suggestion}
  const [readerLoading, setReaderLoading] = useState(false);
  const [screen, setScreen] = useState("list");     // mobile: list | read
  const [composer, setComposer] = useState(null);
  const [linkFor, setLinkFor] = useState(null);     // {emailId, suggestions}
  const [folderSheet, setFolderSheet] = useState(false);
  const [statusSheetFor, setStatusSheetFor] = useState(null);
  const [assignSheetFor, setAssignSheetFor] = useState(null);

  const toast = (m, t) => showToast ? showToast(m, t) : null;

  // Список менеджерів для призначення (один раз)
  useEffect(() => { MailAPI.managers().then(r => { if (r && r.ok) setManagers(r.managers || []); }).catch(() => {}); }, []);

  // debounce пошуку
  useEffect(() => { const t = setTimeout(() => setDebQuery(query), 320); return () => clearTimeout(t); }, [query]);

  const load = useCallback(async () => {
    setLoading(true); setError(null);
    try {
      const params = { folder };
      if (category) params.category = category;
      if (status !== "all") params.status = status;
      if (debQuery.trim()) params.search = debQuery.trim();
      const r = await MailAPI.list(params);
      if (!r.ok) throw new Error(r.error || "Помилка завантаження");
      setList((r.emails || []).map(mapMailRow));
      if (r.counts) setCounts(r.counts);
      if (window._setMailUnread) window._setMailUnread(r.counts ? r.counts.unread : 0);
    } catch (e) { setError(e.message); setList([]); }
    finally { setLoading(false); }
  }, [folder, category, status, debQuery]);

  useEffect(() => { load(); }, [load]);

  // Кнопка «Оновити» — примусовий збір з IMAP, далі перечитати список
  const syncNow = useCallback(async () => {
    setLoading(true);
    try { const r = await MailAPI.sync(); if (r && r.ok && r.ingested) toast(`Завантажено листів: ${r.ingested}`); }
    catch (e) { toast("❌ " + e.message, "error"); }
    await load();
  }, [load]);

  // Живе оновлення списку при новому/відправленому листі (WS-подія з App.jsx)
  useEffect(() => { window._mailOnPush = () => load(); return () => { delete window._mailOnPush; }; }, [load]);

  // Відкриття композера ззовні (кнопка «Пошта» в картці замовлення).
  // Якщо вкладку щойно змонтували — підхоплюємо «відкладений» prefill.
  useEffect(() => {
    window._mailCompose = (p) => {
      window._mailPendingCompose = null;
      if (isMobile) setScreen("list");
      // attachments — попередньо прикріплені документи (кнопка «На email» з картки РАХУНКУ):
      // [{invoiceId, kind, name, sub}] — той самий формат, що дає AttachDocPicker
      setComposer({ title: "Нове письмо", to: (p && p.to) || "", subject: (p && p.subject) || "", order: (p && p.order) || null, body: (p && p.body) || "", attachments: (p && p.attachments) || [] });
    };
    if (window._mailPendingCompose) window._mailCompose(window._mailPendingCompose);
    return () => { delete window._mailCompose; };
  }, [isMobile]);

  const openMail = async (id) => {
    setSelectedId(id);
    if (isMobile) setScreen("read");
    setReader(null); setReaderLoading(true);
    setList(l => l.map(m => m.id === id ? { ...m, unread: false } : m));
    try {
      const r = await MailAPI.full(id);
      if (!r.ok) throw new Error(r.error || "Не вдалося відкрити лист");
      let suggestion = null;
      if (!r.order) { try { const sg = await MailAPI.suggestions(id); if (sg.ok && sg.suggestions[0]) suggestion = sg.suggestions[0]; } catch {} }
      setReader({ email: r.email, attachments: r.attachments || [], order: r.order || null, suggestion });
      MailAPI.counts().then(c => { if (c.ok) { setCounts(c); if (window._setMailUnread) window._setMailUnread(c.unread); } }).catch(() => {});
    } catch (e) { toast("❌ " + e.message, "error"); setReader(null); }
    finally { setReaderLoading(false); }
  };

  const changeStatus = async (id, st) => {
    try {
      await MailAPI.setStatus(id, st);
      setReader(r => r && r.email.id === id ? { ...r, email: { ...r.email, status: st } } : r);
      setList(l => l.map(m => m.id === id ? { ...m, status: st } : m));
      toast(`Статус → «${MAIL_STATUS[st].label}»`);
      setStatusSheetFor(null);
    } catch (e) { toast("❌ " + e.message, "error"); }
  };

  const archive = async (id) => {
    try {
      await MailAPI.moveFolder(id, "archive");
      setList(l => l.filter(m => m.id !== id));
      setSelectedId(null); setReader(null);
      if (isMobile) setScreen("list");
      toast("Лист переміщено в архів");
    } catch (e) { toast("❌ " + e.message, "error"); }
  };

  const linkOrder = async (emailId, orderId, orderObj) => {
    try {
      await MailAPI.link(emailId, orderId);
      const order = orderObj ? { order_id: orderId, client: orderObj.client, total: orderObj.total, status: orderObj.status, created: orderObj.created, phone: orderObj.phone, ttn: orderObj.ttn } : { order_id: orderId };
      setReader(r => r && r.email.id === emailId ? { ...r, order, suggestion: null, email: { ...r.email, order_id: orderId } } : r);
      setList(l => l.map(m => m.id === emailId ? { ...m, orderId } : m));
      setLinkFor(null);
      toast(`Прив'язано до замовлення №${orderId}`);
    } catch (e) { toast("❌ " + e.message, "error"); }
  };
  const unlink = async (emailId) => {
    try {
      await MailAPI.link(emailId, null);
      setReader(r => r && r.email.id === emailId ? { ...r, order: null, email: { ...r.email, order_id: null } } : r);
      setList(l => l.map(m => m.id === emailId ? { ...m, orderId: null } : m));
      toast("Замовлення відв'язано");
    } catch (e) { toast("❌ " + e.message, "error"); }
  };

  const doAssign = async (emailId, manager) => {
    try {
      await MailAPI.assign(emailId, manager);
      setReader(r => r && r.email.id === emailId ? { ...r, email: { ...r.email, assigned_to: manager } } : r);
      setList(l => l.map(m => m.id === emailId ? { ...m, assignedTo: manager } : m));
      setAssignSheetFor(null);
      toast(manager ? `Призначено: ${manager}` : "Відповідального знято");
    } catch (e) { toast("❌ " + e.message, "error"); }
  };

  const openLink = (email) => setLinkFor({ emailId: email.id, suggestions: reader && reader.suggestion ? [reader.suggestion] : [] });

  const reply = (email, order) => {
    const who = email.direction === "out" ? { email: email.to_addr } : { name: email.from_name, email: email.from_addr };
    setComposer({ title: "Відповідь", to: who.email || "", subject: "Re: " + String(email.subject || "").replace(/^Re:\s*/i, ""), replyTo: email.id, order: order || null, body: "" });
  };
  const forward = (email, order) => {
    const orig = email.body_html || String(email.body_text || "").split("\n").map(l => `<div>${l || "<br>"}</div>`).join("");
    setComposer({ title: "Переслати", to: "", subject: "Fwd: " + String(email.subject || ""), order: order || null, body: `<div><br></div><div style="color:#6B7280">— Початкове повідомлення —</div>${orig}` });
  };
  const compose = () => setComposer({ title: "Нове письмо", to: "", subject: "", body: "" });

  const onSent = () => {
    setComposer(null);
    toast("Лист відправлено");
    load();
    if (reader) openMail(reader.email.id);
  };

  const openOrder = (id) => { if (window._crmNavigate) { window._crmNavigate("orders"); if (window._ordersOpenById) window._ordersOpenById(id); } };

  // ── Мобільний ──
  if (isMobile) {
    return (
      <div style={{ position: "relative", height: "100%", display: "flex", flexDirection: "column", overflow: "hidden" }}>
        <div style={{ flex: 1, minHeight: 0, position: "relative" }}>
          {screen === "list"
            ? <MListScreen list={list} folder={folder} category={category} status={status} onStatus={setStatus} query={query} onQuery={setQuery} loading={loading} error={error} counts={counts}
                onOpen={openMail} onCompose={compose} onFolderSheet={() => setFolderSheet(true)} onReload={syncNow} onExit={onExit} />
            : <MReadScreen data={reader} loading={readerLoading} onBack={() => setScreen("list")} onReply={reply} onArchive={archive}
                onStatusSheet={(email) => setStatusSheetFor(email)} onAssignSheet={(email) => setAssignSheetFor(email)} onLink={openLink} onUnlink={unlink} onQuickLink={linkOrder} />}
          {folderSheet && <FolderSheet folder={folder} category={category} counts={counts} onClose={() => setFolderSheet(false)} onPick={(f, c) => { setFolder(f); setCategory(c); setFolderSheet(false); }} />}
          {statusSheetFor && <StatusSheet current={statusSheetFor.status} onClose={() => setStatusSheetFor(null)} onPick={(st) => changeStatus(statusSheetFor.id, st)} />}
          {assignSheetFor && <AssignSheet current={assignSheetFor.assigned_to || ""} managers={managers} onClose={() => setAssignSheetFor(null)} onPick={(mgr) => doAssign(assignSheetFor.id, mgr)} />}
          {linkFor && <LinkOrderModal suggestions={linkFor.suggestions} onClose={() => setLinkFor(null)} onPick={(id, o) => linkOrder(linkFor.emailId, id, o)} />}
          {composer && <MailComposer initial={composer} isMobile onClose={() => setComposer(null)} onSent={onSent} showToast={showToast} />}
        </div>
      </div>
    );
  }

  // ── Десктоп: 3 панелі ──
  return (
    <div style={{ flex: 1, display: "flex", minHeight: 0, height: "100%" }}>
      <FoldersPanel folder={folder} category={category} counts={counts} onCompose={compose}
        onFolder={(f) => { setFolder(f); setSelectedId(null); setReader(null); }} onCategory={setCategory} />
      <MailListPanel list={list} folder={folder} category={category} selected={selectedId} onSelect={openMail}
        status={status} onStatus={setStatus} query={query} onQuery={setQuery} loading={loading} error={error} onOrder={openOrder} onReload={syncNow} />
      <MailReader data={reader} loading={readerLoading} managers={managers} onAssign={doAssign} onReply={reply} onForward={forward} onArchive={archive}
        onStatus={changeStatus} onOrder={openOrder} onOpenLink={openLink} onQuickLink={linkOrder} onUnlink={unlink} />
      {composer && <MailComposer initial={composer} onClose={() => setComposer(null)} onSent={onSent} showToast={showToast} />}
      {linkFor && <LinkOrderModal suggestions={linkFor.suggestions} onClose={() => setLinkFor(null)} onPick={(id, o) => linkOrder(linkFor.emailId, id, o)} />}
    </div>
  );
}

window.Mail = Mail;
