/**
 * ComposeEmailModal
 * A full-featured email compose modal using Quill.js (loaded from CDN).
 * Features: To / CC / Subject, WYSIWYG rich body, Ctrl+V image paste, file attachments.
 *
 * Props:
 *   open         – boolean
 *   onClose      – () => void
 *   defaultTo    – string  (pre-fill To field)
 *   defaultSubject – string
 *   customerId   – string | null  (linked customer, optional)
 *   onSent       – (entry) => void  (called after successful send)
 */
import { useState, useEffect, useRef, useCallback } from "react";
import api from "../../api/client";

// ── Quill loader ──────────────────────────────────────────────────────────────
let _quillReady = false;
let _quillCallbacks = [];

function loadQuill(cb) {
  if (_quillReady) { cb(); return; }
  _quillCallbacks.push(cb);
  if (document.getElementById("__quill_css__")) return; // already loading

  // CSS
  const link = document.createElement("link");
  link.id = "__quill_css__";
  link.rel = "stylesheet";
  link.href = "https://cdn.quilljs.com/1.3.7/quill.snow.css";
  document.head.appendChild(link);

  // JS
  const script = document.createElement("script");
  script.id = "__quill_js__";
  script.src = "https://cdn.quilljs.com/1.3.7/quill.min.js";
  script.onload = () => {
    _quillReady = true;
    _quillCallbacks.forEach((fn) => fn());
    _quillCallbacks = [];
  };
  document.head.appendChild(script);
}

// ── Attachment item ───────────────────────────────────────────────────────────
function AttachmentPill({ name, size, onRemove }) {
  const kb = size ? ` (${Math.ceil(size / 1024)} KB)` : "";
  return (
    <div
      className="flex items-center gap-1.5 px-2 py-1 rounded-full text-xs"
      style={{ backgroundColor: "var(--bg-card-hover)", color: "var(--text-secondary)", border: "1px solid var(--border-secondary)" }}
    >
      <span className="truncate" style={{ maxWidth: 160 }}>{name}{kb}</span>
      <button
        type="button"
        onClick={onRemove}
        className="flex-shrink-0 cursor-pointer hover:opacity-70"
        style={{ color: "var(--danger)", background: "none", border: "none", padding: 0, lineHeight: 1 }}
      >
        ×
      </button>
    </div>
  );
}

// ── Email chip input ──────────────────────────────────────────────────────────
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

function EmailChipInput({ list, setList, inputVal, setInputVal, placeholder }) {
  const commit = (raw) => {
    const parts = raw.split(",").map(s => s.trim()).filter(Boolean);
    const valid = parts.filter(p => EMAIL_RE.test(p));
    if (valid.length) setList(prev => [...prev, ...valid.filter(e => !prev.includes(e))]);
    setInputVal("");
  };

  const onKeyDown = (e) => {
    if (e.key === "Enter" || e.key === ",") {
      e.preventDefault();
      commit(inputVal);
    } else if (e.key === "Backspace" && !inputVal && list.length > 0) {
      setList(prev => prev.slice(0, -1));
    }
  };

  const chipStyle = {
    display: "inline-flex", alignItems: "center", gap: 4,
    padding: "2px 8px", borderRadius: 999, fontSize: 12,
    backgroundColor: "var(--bg-card-hover)",
    border: "1px solid var(--border-secondary)",
    color: "var(--text-secondary)",
    flexShrink: 0,
    maxWidth: 220,
  };
  const xStyle = {
    background: "none", border: "none", padding: 0, lineHeight: 1,
    cursor: "pointer", color: "var(--text-muted)", fontSize: 14,
    flexShrink: 0,
  };

  return (
    <div
      style={{
        display: "flex", flexWrap: "wrap", alignItems: "center", gap: 4,
        minHeight: 34,
        backgroundColor: "var(--bg-input)",
        border: "1px solid var(--border-primary)",
        borderRadius: 6, padding: "4px 8px",
        cursor: "text",
      }}
      onClick={(e) => e.currentTarget.querySelector("input")?.focus()}
    >
      {list.map((email) => (
        <span key={email} style={chipStyle} title={email}>
          <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{email}</span>
          <button type="button" style={xStyle} onClick={() => setList(prev => prev.filter(e => e !== email))}>×</button>
        </span>
      ))}
      <input
        type="text"
        value={inputVal}
        onChange={(e) => setInputVal(e.target.value)}
        onKeyDown={onKeyDown}
        onBlur={() => inputVal.trim() && commit(inputVal)}
        placeholder={list.length === 0 ? placeholder : ""}
        style={{
          flex: "1 1 120px", minWidth: 80, border: "none", outline: "none",
          background: "transparent", color: "var(--text-primary)", fontSize: 13, padding: "1px 2px",
        }}
      />
    </div>
  );
}

// ── Main component ────────────────────────────────────────────────────────────
export default function ComposeEmailModal({
  open,
  onClose,
  defaultTo = "",
  defaultSubject = "",
  defaultFromAccount = "",
  requireFromAccount = true,
  defaultServerAttachments = [],
  customerId = null,
  onSent,
}) {
  const [toList, setToList] = useState(defaultTo ? [defaultTo] : []);
  const [toInput, setToInput] = useState("");
  const [ccList, setCcList] = useState([]);
  const [ccInput, setCcInput] = useState("");
  const [subject, setSubject] = useState(defaultSubject);
  const [fromAccount, setFromAccount] = useState(defaultFromAccount || "");
  const [mailAccounts, setMailAccounts] = useState([]);
  const [attachments, setAttachments] = useState([]); // { file: File, name: string, size?: number }[]
  const [sending, setSending] = useState(false);
  const [error, setError] = useState("");
  const [quillLoaded, setQuillLoaded] = useState(_quillReady);
  const [showServerFiles, setShowServerFiles] = useState(false);
  const [serverFiles, setServerFiles] = useState([]);
  const [serverFilesLoading, setServerFilesLoading] = useState(false);
  const [serverFileSearch, setServerFileSearch] = useState("");
  const [serverFileType, setServerFileType] = useState("all");
  const [previewFile, setPreviewFile] = useState(null); // { path, filename, mime_type }
  const [editorPreviewDark, setEditorPreviewDark] = useState(true);

  const editorRef = useRef(null);
  const quillRef = useRef(null);
  const fileInputRef = useRef(null);

  // Reset fields when opened
  useEffect(() => {
    if (open) {
      setToList(defaultTo ? [defaultTo] : []);
      setToInput("");
      setCcList([]);
      setCcInput("");
      setSubject(defaultSubject);
      setFromAccount(defaultFromAccount || "");
      setAttachments([]);
      setError("");
      setEditorPreviewDark(true);
    }
  }, [open, defaultTo, defaultSubject, defaultFromAccount]);

  useEffect(() => {
    if (!open) return;
    let cancelled = false;
    api.get("/crm/comms/email/accounts")
      .then((data) => {
        if (cancelled) return;
        const accounts = data.accounts || [];
        setMailAccounts(accounts);
        if (!defaultFromAccount && accounts.length === 1) {
          setFromAccount(accounts[0].key);
        }
      })
      .catch(() => {
        if (!cancelled) setMailAccounts([]);
      });
    return () => { cancelled = true; };
  }, [open, defaultFromAccount]);

  // Load Quill
  useEffect(() => {
    if (!open) return;
    loadQuill(() => setQuillLoaded(true));
  }, [open]);

  // ESC to close
  useEffect(() => {
    if (!open) return;
    const handler = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", handler);
    return () => window.removeEventListener("keydown", handler);
  }, [open, onClose]);

  // Init Quill editor
  useEffect(() => {
    if (!open || !quillLoaded || !editorRef.current) return;
    if (quillRef.current) return; // already initialized

    const quill = new window.Quill(editorRef.current, {
      theme: "snow",
      placeholder: "Write your message...",
      modules: {
        toolbar: [
          [{ size: ["small", false, "large", "huge"] }],
          ["bold", "italic", "underline", "strike"],
          [{ color: [] }, { background: [] }],
          [{ align: [] }],
          [{ list: "ordered" }, { list: "bullet" }, { indent: "-1" }, { indent: "+1" }],
          ["code-block", "blockquote", "link", "image"],
          ["clean"],
        ],
        clipboard: { matchVisual: false },
      },
    });
    quillRef.current = quill;

    // Force single-row toolbar via JS (defeats Quill's float-based layout)
    const container = editorRef.current;
    const toolbar = container.querySelector(".ql-toolbar");
    const qlContainer = container.querySelector(".ql-container");
    if (toolbar && qlContainer) {
      // Make editorRef a flex column
      container.style.cssText += ";display:flex!important;flex-direction:column!important;";
      // Toolbar: single flex row
      toolbar.style.cssText += ";display:flex!important;flex-wrap:nowrap!important;align-items:center!important;flex-shrink:0!important;overflow:visible!important;padding:3px 8px!important;";
      // Kill floats on every .ql-formats, button, .ql-picker
      toolbar.querySelectorAll(".ql-formats").forEach(el => {
        el.style.cssText += ";float:none!important;display:inline-flex!important;flex-wrap:nowrap!important;align-items:center!important;flex-shrink:0!important;";
      });
      toolbar.querySelectorAll("button").forEach(el => {
        el.style.cssText += ";float:none!important;display:inline-flex!important;align-items:center!important;justify-content:center!important;width:24px!important;height:24px!important;";
      });
      toolbar.querySelectorAll(".ql-picker").forEach(el => {
        el.style.cssText += ";float:none!important;display:inline-flex!important;align-items:center!important;flex-shrink:0!important;height:24px!important;overflow:visible!important;";
      });
      // Editor container fills remaining space
      qlContainer.style.cssText += ";flex:1!important;min-height:0!important;overflow:hidden!important;";
      qlContainer.querySelector(".ql-editor").style.cssText += ";height:100%!important;overflow-y:auto!important;";
    }

    // Keep color picker icons in sync with currently selected text/highlight colors.
    const syncPickerIndicators = () => {
      if (!toolbar) return;
      const formats = quill.getFormat();
      const textColor = typeof formats.color === "string" ? formats.color : "";
      const highlightColor = typeof formats.background === "string" ? formats.background : "";
      toolbar.style.setProperty("--ql-current-color", textColor || "var(--text-secondary)");
      toolbar.style.setProperty("--ql-current-bg", highlightColor || "var(--bg-input)");
      toolbar.classList.toggle("ql-has-bg-color", Boolean(highlightColor));

      const colorLabel =
        toolbar.querySelector(".ql-picker.ql-color-picker.ql-color .ql-picker-label") ||
        toolbar.querySelector(".ql-picker.ql-color .ql-picker-label");
      const bgLabel =
        toolbar.querySelector(".ql-picker.ql-color-picker.ql-background .ql-picker-label") ||
        toolbar.querySelector(".ql-picker.ql-background .ql-picker-label");

      if (colorLabel) {
        colorLabel.style.boxShadow = `inset 0 -3px 0 ${textColor || "var(--text-secondary)"}`;
        colorLabel.querySelectorAll(".ql-stroke, .ql-stroke-miter").forEach((el) => {
          el.style.setProperty("stroke", textColor || "var(--text-secondary)", "important");
        });
        colorLabel.querySelectorAll(".ql-fill, .ql-color-label").forEach((el) => {
          el.style.setProperty("fill", textColor || "var(--text-secondary)", "important");
        });

        let swatch = colorLabel.querySelector(".compose-picker-swatch");
        if (!swatch) {
          swatch = document.createElement("span");
          swatch.className = "compose-picker-swatch";
          swatch.style.cssText = "position:absolute;right:2px;top:2px;width:7px;height:7px;border-radius:999px;border:1px solid rgba(255,255,255,0.35);pointer-events:none;";
          colorLabel.appendChild(swatch);
        }
        swatch.style.background = textColor || "var(--text-secondary)";
      }
      if (bgLabel) {
        bgLabel.style.boxShadow = highlightColor
          ? `inset 0 -7px 0 ${highlightColor}`
          : "inset 0 -7px 0 transparent";
        bgLabel.style.borderBottom = "1px solid var(--border-secondary)";
        bgLabel.querySelectorAll(".ql-fill, .ql-color-label").forEach((el) => {
          el.style.setProperty("fill", "var(--text-secondary)", "important");
        });

        let swatch = bgLabel.querySelector(".compose-picker-swatch");
        if (!swatch) {
          swatch = document.createElement("span");
          swatch.className = "compose-picker-swatch";
          swatch.style.cssText = "position:absolute;right:2px;top:2px;width:7px;height:7px;border-radius:999px;border:1px solid rgba(255,255,255,0.35);pointer-events:none;";
          bgLabel.appendChild(swatch);
        }
        swatch.style.background = highlightColor || "transparent";
        swatch.style.borderColor = highlightColor ? "rgba(255,255,255,0.35)" : "var(--border-secondary)";
      }
    };
    quill.on("selection-change", syncPickerIndicators);
    quill.on("text-change", syncPickerIndicators);
    quill.on("editor-change", syncPickerIndicators);
    syncPickerIndicators();

    // Handle Ctrl+V image paste
    quill.root.addEventListener("paste", (e) => {
      const items = (e.clipboardData || e.originalEvent?.clipboardData)?.items;
      if (!items) return;
      for (const item of items) {
        if (item.type.startsWith("image/")) {
          e.preventDefault();
          const blob = item.getAsFile();
          const reader = new FileReader();
          reader.onload = (ev) => {
            const range = quill.getSelection(true);
            quill.insertEmbed(range.index, "image", ev.target.result);
          };
          reader.readAsDataURL(blob);
          break;
        }
      }
    });

    return () => {
      quill.off("selection-change", syncPickerIndicators);
      quill.off("text-change", syncPickerIndicators);
      quill.off("editor-change", syncPickerIndicators);
      quillRef.current = null;
    };
  }, [open, quillLoaded]);

  const getContent = useCallback(() => {
    const q = quillRef.current;
    if (!q) return { html: "", text: "" };
    const html = q.root.innerHTML;
    const text = q.getText().trim();
    return { html, text };
  }, []);

  const handleFileAdd = (files) => {
    const newFiles = Array.from(files).map((f) => ({ file: f, name: f.name }));
    setAttachments((prev) => [...prev, ...newFiles]);
  };

  useEffect(() => {
    if (!open || !defaultServerAttachments?.length) return;
    let cancelled = false;
    (async () => {
      for (const f of defaultServerAttachments) {
        try {
          const token = localStorage.getItem("access_token");
          const resp = await fetch(`/api/crm/nextcloud/file?path=${encodeURIComponent(f.path)}&token=${encodeURIComponent(token)}`);
          if (!resp.ok) continue;
          const blob = await resp.blob();
          if (cancelled) return;
          const file = new File([blob], f.filename, { type: f.mime_type || "application/octet-stream" });
          setAttachments((prev) => {
            if (prev.some((a) => a.name === f.filename)) return prev;
            return [...prev, { file, name: f.filename }];
          });
        } catch {
          // ignore pre-attachment failures
        }
      }
    })();
    return () => { cancelled = true; };
  }, [open, defaultServerAttachments]);

  // Open server file picker and load files for this customer
  const openServerFiles = async () => {
    setShowServerFiles(true);
    setServerFileSearch("");
    setServerFileType("all");
    if (serverFiles.length > 0) return; // already loaded
    setServerFilesLoading(true);
    try {
      const token = localStorage.getItem("access_token");
      const resp = await fetch(`/api/crm/nextcloud/browse-all?customer_id=${customerId}`, {
        headers: { Authorization: `Bearer ${token}` },
      });
      if (!resp.ok) throw new Error("Failed to load files");
      const data = await resp.json();
      setServerFiles((data.items || []).filter((f) => !f.is_dir));
    } catch {
      setServerFiles([]);
    } finally {
      setServerFilesLoading(false);
    }
  };

  // Attach a server file by downloading it as a Blob and adding to attachments
  const attachServerFile = async (f) => {
    try {
      const token = localStorage.getItem("access_token");
      const resp = await fetch(`/api/crm/nextcloud/file?path=${encodeURIComponent(f.path)}&token=${encodeURIComponent(token)}`);
      if (!resp.ok) throw new Error("Download failed");
      const blob = await resp.blob();
      const file = new File([blob], f.filename, { type: f.mime_type || "application/octet-stream" });
      setAttachments((prev) => [...prev, { file, name: f.filename }]);
    } catch (err) {
      setError(`Could not attach ${f.filename}: ${err.message}`);
    }
    setShowServerFiles(false);
  };

  // Determine file type category for filter
  function getFileCategory(f) {
    const mime = f.mime_type || "";
    const sub = f.subfolder || "";
    if (sub === "quotations") return "quotation";
    if (mime === "application/pdf" || sub.includes("invoic") || sub.includes("document")) return "document";
    if (mime.startsWith("image/") || mime.startsWith("video/") || mime.startsWith("audio/") || sub.includes("media")) return "media";
    return "document";
  }

  const handleSend = async () => {
    const { html, text } = getContent();
    // Commit any pending input in the TO/CC fields before validating
    const finalToList = [...toList];
    if (toInput.trim()) {
      toInput.split(",").map(s => s.trim()).filter(s => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s)).forEach(e => { if (!finalToList.includes(e)) finalToList.push(e); });
    }
    const finalCcList = [...ccList];
    if (ccInput.trim()) {
      ccInput.split(",").map(s => s.trim()).filter(s => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s)).forEach(e => { if (!finalCcList.includes(e)) finalCcList.push(e); });
    }
    const totalAttachMB = attachments.reduce((s, a) => s + (a.file?.size ?? 0), 0) / (1024 * 1024);
    const ATTACH_LIMIT_MB = 25;
    if (requireFromAccount && !fromAccount) { setError("Please select a sender account."); return; }
    if (finalToList.length === 0) { setError("Please enter a recipient email address."); return; }
    if (!subject.trim()) { setError("Please enter a subject."); return; }
    if (!text && !html.replace(/<[^>]*>/g, "").trim()) { setError("Please write a message."); return; }
    if (totalAttachMB > ATTACH_LIMIT_MB) { setError(`Attachments exceed the ${ATTACH_LIMIT_MB} MB limit (${totalAttachMB.toFixed(1)} MB total).`); return; }
    setError("");
    setSending(true);
    try {
      const token = localStorage.getItem("access_token");

      const fd = new FormData();
      if (customerId) fd.append("customer_id", customerId);
      if (fromAccount) fd.append("from_account", fromAccount);
      fd.append("to", finalToList[0]);
      fd.append("subject", subject.trim());
      fd.append("body", text);
      fd.append("body_html", html);
      fd.append("cc", JSON.stringify(finalCcList));
      for (const { file } of attachments) {
        fd.append("files", file, file.name);
      }

      const resp = await fetch("/api/crm/comms/email/send", {
        method: "POST",
        headers: { Authorization: `Bearer ${token}` },
        body: fd,
      });
      if (!resp.ok) {
        const err = await resp.json().catch(() => ({}));
        throw new Error(err.detail || `Server error ${resp.status}`);
      }
      const data = await resp.json();
      if (onSent) onSent(data.entry || data);
      onClose();
    } catch (err) {
      setError(err.message || "Failed to send email.");
    } finally {
      setSending(false);
    }
  };

  if (!open) return null;

  const inputStyle = {
    backgroundColor: "var(--bg-input)",
    borderColor: "var(--border-primary)",
    color: "var(--text-primary)",
    border: "1px solid",
    borderRadius: 6,
    padding: "7px 10px",
    fontSize: 13,
    width: "100%",
    outline: "none",
  };

  return (
    <div
      style={{
        position: "fixed", inset: 0, zIndex: 1000,
        backgroundColor: "rgba(0,0,0,0.55)",
        display: "flex", alignItems: "center", justifyContent: "center",
        padding: 80,
      }}
    >
      <div
        style={{
          backgroundColor: "var(--bg-card)",
          border: "1px solid var(--border-primary)",
          borderRadius: 12,
          width: "100%",
          height: "100%",
          display: "flex",
          flexDirection: "column",
          overflow: "hidden",
          boxShadow: "0 20px 60px rgba(0,0,0,0.4)",
        }}
      >
        {/* Header */}
        <div
          className="flex items-center justify-between px-5 py-4"
          style={{ borderBottom: "1px solid var(--border-primary)" }}
        >
          <h2 className="text-base font-semibold" style={{ color: "var(--text-heading)" }}>
            New Email
          </h2>
          <button
            type="button"
            onClick={onClose}
            className="cursor-pointer hover:opacity-70"
            style={{ color: "var(--text-muted)", background: "none", border: "none", fontSize: 20, lineHeight: 1 }}
          >
            ×
          </button>
        </div>

        {/* Fields */}
        <div className="px-5 py-4" style={{ borderBottom: "1px solid var(--border-secondary)" }}>
          <div style={{ display: "grid", gridTemplateColumns: "200px 1fr 1fr", gap: 10, marginBottom: 10 }}>
            <div>
              <label className="text-xs font-medium block mb-1" style={{ color: "var(--text-secondary)" }}>Send As</label>
              <select
                className="compose-email-input"
                style={inputStyle}
                value={fromAccount}
                onChange={(e) => setFromAccount(e.target.value)}
              >
                <option value="">Select sender...</option>
                {mailAccounts.filter((a) => a.allow_send).map((a) => (
                  <option key={a.key} value={a.key}>{a.label} ({a.email})</option>
                ))}
              </select>
            </div>
            <div>
              <label className="text-xs font-medium block mb-1" style={{ color: "var(--text-secondary)" }}>To</label>
              <EmailChipInput
                list={toList} setList={setToList}
                inputVal={toInput} setInputVal={setToInput}
                placeholder="recipient@example.com"
              />
            </div>
            <div>
              <label className="text-xs font-medium block mb-1" style={{ color: "var(--text-secondary)" }}>CC</label>
              <EmailChipInput
                list={ccList} setList={setCcList}
                inputVal={ccInput} setInputVal={setCcInput}
                placeholder="cc@example.com"
              />
            </div>
          </div>
          <div>
            <label className="text-xs font-medium block mb-1" style={{ color: "var(--text-secondary)" }}>Subject</label>
            <input
              className="compose-email-input"
              style={inputStyle}
              value={subject}
              onChange={(e) => setSubject(e.target.value)}
              placeholder="Email subject"
            />
          </div>
        </div>

        {/* Quill Editor — Quill injects toolbar+editor into editorRef */}
        <div className="quill-compose-wrapper" style={{ display: "flex", flexDirection: "column", flex: 1, minHeight: 0, position: "relative" }}>
          <div style={{ position: "absolute", top: 8, right: 12, zIndex: 20 }}>
            <button
              type="button"
              onClick={() => setEditorPreviewDark((v) => !v)}
              title={editorPreviewDark ? "Switch to light preview" : "Switch to dark preview"}
              style={{
                padding: "4px 10px", fontSize: 11, borderRadius: 6, cursor: "pointer",
                border: "1px solid rgba(128,128,128,0.4)",
                backgroundColor: editorPreviewDark ? "rgba(0,0,0,0.55)" : "rgba(255,255,255,0.7)",
                color: editorPreviewDark ? "#e0e0e0" : "#333",
                backdropFilter: "blur(4px)",
              }}
            >
              {editorPreviewDark ? "☀ Light" : "🌙 Dark"}
            </button>
          </div>
          {quillLoaded ? (
            <div ref={editorRef} style={{ flex: 1, minHeight: 0 }} />
          ) : (
            <div className="flex items-center justify-center py-12" style={{ color: "var(--text-muted)" }}>
              Loading editor...
            </div>
          )}
        </div>

        {/* Attachments */}
        {attachments.length > 0 && (
          <div className="px-5 py-3 flex flex-wrap gap-2" style={{ borderTop: "1px solid var(--border-secondary)" }}>
            {attachments.map((a, i) => (
              <AttachmentPill
                key={i}
                name={a.name}
                size={a.file.size}
                onRemove={() => setAttachments((prev) => prev.filter((_, j) => j !== i))}
              />
            ))}
          </div>
        )}

        {/* Footer */}
        <div
          className="flex items-center justify-between px-5 py-4"
          style={{ borderTop: "1px solid var(--border-primary)" }}
        >
          <div className="flex items-center gap-3">
            {customerId && (
              <button
                type="button"
                onClick={openServerFiles}
                className="px-3 py-1.5 text-sm rounded-md cursor-pointer hover:opacity-80"
                style={{ border: "1px solid var(--border-primary)", color: "var(--text-secondary)", backgroundColor: "var(--bg-card)" }}
              >
                🗂 Attach from Server
              </button>
            )}
            <button
              type="button"
              onClick={() => fileInputRef.current?.click()}
              className="px-3 py-1.5 text-sm rounded-md cursor-pointer hover:opacity-80"
              style={{ border: "1px solid var(--border-primary)", color: "var(--text-secondary)", backgroundColor: "var(--bg-card)" }}
            >
              📎 Attach
            </button>
            <input
              ref={fileInputRef}
              type="file"
              multiple
              style={{ display: "none" }}
              onChange={(e) => handleFileAdd(e.target.files)}
            />
            <button
              type="button"
              onClick={() => {
                const sig = localStorage.getItem("mail_signature") || "";
                if (!sig.trim() || sig === "<p><br></p>") return;
                const q = quillRef.current;
                if (!q) return;
                const current = q.root.innerHTML;
                q.clipboard.dangerouslyPasteHTML(current + '<p><br></p><hr/><div class="mail-sig">' + sig + "</div>");
              }}
              className="px-3 py-1.5 text-sm rounded-md cursor-pointer hover:opacity-80"
              style={{ border: "1px solid var(--border-primary)", color: "var(--text-secondary)", backgroundColor: "var(--bg-card)" }}
              title="Append signature to message"
            >
              ✍ Add Signature
            </button>
            {(() => {
              const ATTACH_LIMIT_MB = 25;
              const totalMB = attachments.reduce((s, a) => s + (a.file?.size ?? 0), 0) / (1024 * 1024);
              if (attachments.length === 0) return null;
              const color = totalMB > 25 ? "var(--danger)" : totalMB > 20 ? "var(--danger)" : totalMB > 15 ? "#f59e0b" : "var(--text-muted)";
              const fontWeight = totalMB > ATTACH_LIMIT_MB ? 700 : 400;
              return (
                <span style={{ fontSize: 12, color, fontWeight }}>
                  {totalMB.toFixed(1)}/{ATTACH_LIMIT_MB} MB attached
                  {totalMB > ATTACH_LIMIT_MB && " — too large"}
                </span>
              );
            })()}
            <span className="text-xs" style={{ color: "var(--text-muted)" }}>
              Tip: Paste images directly with Ctrl+V
            </span>
          </div>
          <div className="flex items-center gap-3">
            {error && (
              <span className="text-xs" style={{ color: "var(--danger-text)" }}>{error}</span>
            )}
            <button
              type="button"
              onClick={onClose}
              className="px-3 py-1.5 text-sm rounded-md cursor-pointer hover:opacity-80"
              style={{ border: "1px solid var(--border-primary)", color: "var(--text-secondary)", backgroundColor: "var(--bg-card)" }}
            >
              Cancel
            </button>
            <button
              type="button"
              onClick={handleSend}
              disabled={sending}
              className="px-4 py-1.5 text-sm rounded-md cursor-pointer hover:opacity-90"
              style={{
                backgroundColor: "var(--btn-primary)",
                color: "var(--text-white)",
                opacity: sending ? 0.7 : 1,
              }}
            >
              {sending ? "Sending..." : "Send"}
            </button>
          </div>
        </div>
      </div>

      {/* Server File Picker Modal */}
      {showServerFiles && (
        <div
          style={{
            position: "fixed", inset: 0, zIndex: 1100,
            backgroundColor: "rgba(0,0,0,0.6)",
            display: "flex", alignItems: "center", justifyContent: "center",
          }}
          onClick={() => setShowServerFiles(false)}
        >
          <div
            style={{
              backgroundColor: "var(--bg-card)",
              border: "1px solid var(--border-primary)",
              borderRadius: 12,
              width: 540,
              maxHeight: "70vh",
              display: "flex",
              flexDirection: "column",
              overflow: "hidden",
              boxShadow: "0 16px 48px rgba(0,0,0,0.5)",
            }}
            onClick={(e) => e.stopPropagation()}
          >
            {/* Header */}
            <div className="flex items-center justify-between px-5 py-4" style={{ borderBottom: "1px solid var(--border-primary)", flexShrink: 0 }}>
              <h3 className="text-sm font-semibold" style={{ color: "var(--text-heading)" }}>Attach File from Server</h3>
              <button type="button" onClick={() => setShowServerFiles(false)} style={{ color: "var(--text-muted)", background: "none", border: "none", fontSize: 20, cursor: "pointer", lineHeight: 1 }}>×</button>
            </div>

            {/* Search + Type filter */}
            <div className="px-4 py-3 flex gap-2" style={{ borderBottom: "1px solid var(--border-secondary)", flexShrink: 0 }}>
              <input
                type="text"
                placeholder="Search by filename..."
                value={serverFileSearch}
                onChange={(e) => setServerFileSearch(e.target.value)}
                autoFocus
                className="flex-1 px-3 py-1.5 text-sm rounded border"
                style={{ backgroundColor: "var(--bg-input)", borderColor: "var(--border-primary)", color: "var(--text-primary)" }}
              />
              <select
                value={serverFileType}
                onChange={(e) => setServerFileType(e.target.value)}
                className="px-3 py-1.5 text-sm rounded border"
                style={{ backgroundColor: "var(--bg-input)", borderColor: "var(--border-primary)", color: "var(--text-primary)" }}
              >
                <option value="all">All types</option>
                <option value="document">Documents</option>
                <option value="quotation">Quotations</option>
                <option value="media">Media</option>
              </select>
            </div>

            {/* File list */}
            <div style={{ overflowY: "auto", flex: 1 }}>
              {serverFilesLoading && (
                <div className="text-center py-8 text-sm" style={{ color: "var(--text-muted)" }}>Loading files...</div>
              )}
              {!serverFilesLoading && serverFiles.length === 0 && (
                <div className="text-center py-8 text-sm" style={{ color: "var(--text-muted)" }}>No files found for this customer.</div>
              )}
              {!serverFilesLoading && (() => {
                const token = localStorage.getItem("access_token");
                const filtered = serverFiles.filter((f) => {
                  const matchSearch = !serverFileSearch.trim() || f.filename.toLowerCase().includes(serverFileSearch.toLowerCase());
                  const matchType = serverFileType === "all" || getFileCategory(f) === serverFileType;
                  return matchSearch && matchType && !f.is_dir;
                });
                if (filtered.length === 0 && serverFiles.length > 0) {
                  return <div className="text-center py-8 text-sm" style={{ color: "var(--text-muted)" }}>No files match your search.</div>;
                }
                return filtered.map((f) => {
                  const alreadyAttached = attachments.some((a) => a.name === f.filename);
                  const cat = getFileCategory(f);
                  const catColors = {
                    quotation: { bg: "#1a2d1e", color: "#6aab7a" },
                    document: { bg: "#1e1a2d", color: "#a78bfa" },
                    media: { bg: "#2d2a1a", color: "#c9a84c" },
                  };
                  const c = catColors[cat] || catColors.document;
                  const kb = f.size > 0 ? `${(f.size / 1024).toFixed(0)} KB` : "";
                  const isImage = (f.mime_type || "").startsWith("image/");
                  const thumbUrl = `/api/crm/nextcloud/file?path=${encodeURIComponent(f.path)}&token=${encodeURIComponent(token)}`;

                  // Thumbnail / icon
                  const thumb = isImage ? (
                    <img
                      src={thumbUrl}
                      alt=""
                      onClick={(e) => { e.stopPropagation(); setPreviewFile(f); }}
                      style={{ width: 40, height: 40, objectFit: "cover", borderRadius: 5, flexShrink: 0, cursor: "zoom-in", border: "1px solid var(--border-secondary)" }}
                    />
                  ) : (
                    <div
                      onClick={(e) => { e.stopPropagation(); setPreviewFile(f); }}
                      style={{ width: 40, height: 40, borderRadius: 5, flexShrink: 0, backgroundColor: c.bg, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 20, cursor: "zoom-in", border: "1px solid var(--border-secondary)" }}
                    >
                      {cat === "quotation" ? "🧾" : cat === "media" ? "🎵" : "📄"}
                    </div>
                  );

                  return (
                    <div
                      key={f.path}
                      onClick={() => !alreadyAttached && attachServerFile(f)}
                      style={{
                        display: "flex", alignItems: "center", gap: 12,
                        padding: "8px 16px",
                        borderBottom: "1px solid var(--border-secondary)",
                        cursor: alreadyAttached ? "default" : "pointer",
                        opacity: alreadyAttached ? 0.5 : 1,
                      }}
                      onMouseEnter={(e) => { if (!alreadyAttached) e.currentTarget.style.backgroundColor = "var(--bg-card-hover)"; }}
                      onMouseLeave={(e) => { e.currentTarget.style.backgroundColor = ""; }}
                    >
                      {thumb}
                      <span className="flex-1 text-sm truncate" style={{ color: "var(--text-primary)" }}>{f.filename}</span>
                      <span className="text-xs flex-shrink-0" style={{ color: "var(--text-muted)" }}>{kb}</span>
                      {alreadyAttached
                        ? <span className="text-xs flex-shrink-0" style={{ color: "var(--accent)" }}>Attached</span>
                        : <span style={{ fontSize: 11, padding: "2px 7px", borderRadius: 10, backgroundColor: c.bg, color: c.color, fontWeight: 500, flexShrink: 0, whiteSpace: "nowrap" }}>{cat}</span>
                      }
                    </div>
                  );
                });
              })()}
            </div>
          </div>
        </div>
      )}

      {/* File preview modal */}
      {previewFile && (() => {
        const token = localStorage.getItem("access_token");
        const fileUrl = `/api/crm/nextcloud/file?path=${encodeURIComponent(previewFile.path)}&token=${encodeURIComponent(token)}`;
        const mime = previewFile.mime_type || "";
        const isImage = mime.startsWith("image/");
        const isPdf = mime === "application/pdf";
        return (
          <div
            style={{ position: "fixed", inset: 0, zIndex: 1200, backgroundColor: "rgba(0,0,0,0.8)", display: "flex", alignItems: "center", justifyContent: "center", padding: 40 }}
            onClick={() => setPreviewFile(null)}
          >
            <div
              style={{ position: "relative", maxWidth: "90vw", maxHeight: "85vh", display: "flex", flexDirection: "column", borderRadius: 10, overflow: "hidden", backgroundColor: "var(--bg-card)", boxShadow: "0 20px 60px rgba(0,0,0,0.6)" }}
              onClick={(e) => e.stopPropagation()}
            >
              {/* Preview header */}
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "10px 16px", borderBottom: "1px solid var(--border-primary)", flexShrink: 0 }}>
                <span className="text-sm font-medium truncate" style={{ color: "var(--text-heading)", maxWidth: 400 }}>{previewFile.filename}</span>
                <div style={{ display: "flex", gap: 8, marginLeft: 16, flexShrink: 0 }}>
                  <a href={fileUrl} download={previewFile.filename} style={{ fontSize: 12, color: "var(--accent)", textDecoration: "none" }}>Download</a>
                  <button onClick={() => setPreviewFile(null)} style={{ background: "none", border: "none", cursor: "pointer", color: "var(--text-muted)", fontSize: 20, lineHeight: 1 }}>×</button>
                </div>
              </div>
              {/* Preview body */}
              <div style={{ flex: 1, minHeight: 0, overflow: "auto", display: "flex", alignItems: "center", justifyContent: "center", padding: 16, backgroundColor: "var(--bg-primary)" }}>
                {isImage && <img src={fileUrl} alt={previewFile.filename} style={{ maxWidth: "80vw", maxHeight: "70vh", objectFit: "contain", borderRadius: 6 }} />}
                {isPdf && <iframe src={fileUrl} title={previewFile.filename} style={{ width: "75vw", height: "70vh", border: "none", borderRadius: 6 }} />}
                {!isImage && !isPdf && (
                  <div style={{ textAlign: "center", color: "var(--text-muted)" }}>
                    <div style={{ fontSize: 48, marginBottom: 12 }}>📄</div>
                    <div className="text-sm">{previewFile.filename}</div>
                    <a href={fileUrl} download={previewFile.filename} className="text-sm" style={{ color: "var(--accent)", marginTop: 8, display: "inline-block" }}>Download to view</a>
                  </div>
                )}
              </div>
            </div>
          </div>
        );
      })()}

      {/* Quill snow theme overrides — layout handled via JS, only cosmetics here */}
      <style>{`
        .quill-compose-wrapper .ql-toolbar.ql-snow::after { display: none !important; }
        .quill-compose-wrapper .ql-toolbar.ql-snow {
          background: var(--bg-card-hover) !important;
          border-top: none !important;
          border-left: none !important;
          border-right: none !important;
          border-bottom: 1px solid var(--border-secondary) !important;
          position: relative !important;
          z-index: 3 !important;
          overflow: visible !important;
        }
        .quill-compose-wrapper .ql-toolbar .ql-formats {
          gap: 1px !important;
          margin: 0 10px 0 0 !important;
          padding: 0 10px 0 0 !important;
          border-right: 1px solid #4b5563 !important;
          position: relative !important;
        }
        .quill-compose-wrapper .ql-toolbar .ql-formats:last-child {
          border-right: none !important;
          padding-right: 0 !important;
          margin-right: 0 !important;
        }
        .quill-compose-wrapper .ql-toolbar .ql-picker,
        .quill-compose-wrapper .ql-toolbar .ql-picker-label,
        .quill-compose-wrapper .ql-toolbar .ql-picker-item {
          color: var(--text-secondary) !important;
        }
        .quill-compose-wrapper .ql-toolbar .ql-picker-label {
          position: relative !important;
        }
        .quill-compose-wrapper .ql-toolbar .ql-picker.ql-size .ql-picker-label::before {
          color: var(--text-secondary) !important;
        }
        .quill-compose-wrapper .ql-toolbar button:hover,
        .quill-compose-wrapper .ql-toolbar button.ql-active { background: var(--bg-primary) !important; }
        .quill-compose-wrapper .ql-toolbar .ql-picker.ql-color .ql-picker-label .ql-stroke,
        .quill-compose-wrapper .ql-toolbar .ql-picker.ql-color .ql-picker-label .ql-fill {
          stroke: var(--ql-current-color, var(--text-secondary)) !important;
          fill: var(--ql-current-color, var(--text-secondary)) !important;
        }
        .quill-compose-wrapper .ql-toolbar .ql-picker.ql-background .ql-picker-label .ql-fill {
          fill: var(--text-secondary) !important;
        }
        .quill-compose-wrapper .ql-toolbar .ql-picker.ql-background .ql-picker-label .ql-stroke {
          stroke: var(--border-secondary) !important;
        }
        /* Dropdowns: keep anchored to picker and above editor scroll area */
        .quill-compose-wrapper .ql-toolbar .ql-picker {
          position: relative !important;
        }
        .quill-compose-wrapper .ql-picker-options {
          position: absolute !important;
          z-index: 40 !important;
          background: var(--bg-card) !important;
          border: 1px solid var(--border-primary) !important;
          box-shadow: 0 8px 24px rgba(0,0,0,0.45) !important;
          border-radius: 6px !important;
          max-height: 220px !important;
          overflow-y: auto !important;
        }
        .quill-compose-wrapper .ql-stroke { stroke: var(--text-secondary) !important; }
        .quill-compose-wrapper .ql-toolbar button:hover .ql-stroke,
        .quill-compose-wrapper .ql-toolbar button.ql-active .ql-stroke { stroke: var(--accent) !important; }
        .quill-compose-wrapper .ql-fill { fill: var(--text-secondary) !important; }
        .quill-compose-wrapper .ql-toolbar button:hover .ql-fill,
        .quill-compose-wrapper .ql-toolbar button.ql-active .ql-fill { fill: var(--accent) !important; }
        .quill-compose-wrapper .ql-toolbar .ql-picker.ql-color .ql-picker-label:hover .ql-stroke,
        .quill-compose-wrapper .ql-toolbar .ql-picker.ql-color.ql-expanded .ql-picker-label .ql-stroke,
        .quill-compose-wrapper .ql-toolbar .ql-picker.ql-color .ql-picker-label:hover .ql-fill,
        .quill-compose-wrapper .ql-toolbar .ql-picker.ql-color.ql-expanded .ql-picker-label .ql-fill {
          stroke: var(--ql-current-color, var(--text-secondary)) !important;
          fill: var(--ql-current-color, var(--text-secondary)) !important;
        }
        .quill-compose-wrapper .ql-toolbar .ql-picker.ql-background .ql-picker-label:hover .ql-fill,
        .quill-compose-wrapper .ql-toolbar .ql-picker.ql-background.ql-expanded .ql-picker-label .ql-fill {
          fill: var(--text-secondary) !important;
        }
        .quill-compose-wrapper .ql-container.ql-snow {
          border-left: none !important;
          border-right: none !important;
          border-bottom: none !important;
          font-size: 14px !important;
        }
        .quill-compose-wrapper .ql-editor {
          color: ${editorPreviewDark ? "var(--text-primary)" : "#1a1a1a"} !important;
          background: ${editorPreviewDark ? "var(--bg-input)" : "#ffffff"} !important;
        }
        .quill-compose-wrapper .ql-editor.ql-blank::before {
          color: ${editorPreviewDark ? "var(--text-muted)" : "#6b7280"} !important;
          font-style: normal !important;
        }
        .quill-compose-wrapper .ql-editor blockquote {
          border-left: 3px solid ${editorPreviewDark ? "var(--border-primary)" : "#d1d5db"} !important;
          color: ${editorPreviewDark ? "var(--text-secondary)" : "#6b7280"} !important;
          padding-left: 12px !important;
        }
        .compose-email-input {
          border: 1px solid var(--border-primary) !important;
          box-shadow: none !important;
          background-color: var(--bg-input) !important;
          color: var(--text-primary) !important;
        }
        .compose-email-input:focus {
          border-color: var(--border-primary) !important;
          box-shadow: none !important;
          outline: none !important;
        }
        .compose-email-input:-webkit-autofill,
        .compose-email-input:-webkit-autofill:hover,
        .compose-email-input:-webkit-autofill:focus {
          -webkit-box-shadow: 0 0 0 1000px var(--bg-input) inset !important;
          -webkit-text-fill-color: var(--text-primary) !important;
          border: 1px solid var(--border-primary) !important;
          transition: background-color 9999s ease-out 0s;
        }
      `}</style>
    </div>
  );
}
