"use client"

import {
  useState,
  useRef,
  useEffect,
  useLayoutEffect,
  useCallback,
  useMemo,
  lazy,
  Suspense,
} from "react"
import { useIsXs } from "@/hooks/use-xs"
import { readCoarsePointerMatches } from "@/hooks/use-touch-nav"
import { Sheet, SheetContent, SheetTitle } from "@/components/ui/sheet"
import { useEditor, EditorContent } from "@tiptap/react"
import { Editor, Node as TipTapNode, mergeAttributes, type Extensions } from "@tiptap/core"
import StarterKit from "@tiptap/starter-kit"
import Underline from "@tiptap/extension-underline"
import Link from "@tiptap/extension-link"
import TextAlign from "@tiptap/extension-text-align"
import { TextStyle, FontFamily, FontSize, BackgroundColor } from "@tiptap/extension-text-style"
import Color from "@tiptap/extension-color"
import {
  Maximize2,
  Minimize2,
  X,
  ChevronDown,
  Paperclip,
  Link as LinkIcon,
  Smile,
  HardDrive,
  Image as ImageIcon,
  Lock,
  PenTool,
  MoreVertical,
  Trash2,
  Bold,
  Italic,
  Underline as UnderlineIcon,
  AlignLeft,
  AlignCenter,
  AlignRight,
  AlignJustify,
  List,
  ListOrdered,
  Undo,
  Redo,
  Type,
  Clock,
  Indent,
  Outdent,
  RemoveFormatting,
  Palette,
  ALargeSmall,
  CaseSensitive,
  Reply,
  ReplyAll,
  Forward,
  SquareArrowOutUpRight,
  Pencil,
  Send,
} from "lucide-react"
import {
  type ComposeState,
  type Contact,
  cloneComposeForPendingSend,
  DEFAULT_IDENTITIES,
  MOCK_CONTACTS,
  SIGNATURES,
  useComposeActions,
  useComposeWindows,
} from "@/lib/compose-context"
import { useScheduledMail } from "@/lib/scheduled-mail-context"
import type { ScheduleSendPayload } from "@/lib/api/scheduled-mail"
import type { Email } from "@/lib/email-data"
import {
  buildThreadComposePreset,
  collectThreadParticipants,
} from "@/lib/thread-compose-preset"
import { toast } from "sonner"
import { showPendingSendToast } from "@/lib/pending-send-toast"
import { cn, getNextLocalWallClockDate } from "@/lib/utils"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuSub,
  DropdownMenuSubContent,
  DropdownMenuSubTrigger,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover"
import data from "@emoji-mart/data"

const LazyPicker = lazy(() => import("@emoji-mart/react"))

function EmojiPicker({ onSelect }: { onSelect: (emoji: { native: string }) => void }) {
  return (
    <Suspense fallback={<div className="flex h-[435px] w-[352px] items-center justify-center text-sm text-[#5f6368]">Chargement…</div>}>
      <LazyPicker
        data={data}
        onEmojiSelect={onSelect}
        locale="fr"
        theme="light"
        previewPosition="none"
        skinTonePosition="search"
        set="native"
      />
    </Suspense>
  )
}

const SignatureBlock = TipTapNode.create({
  name: "signatureBlock",
  group: "block",
  content: "block+",
  defining: true,
  isolating: true,

  parseHTML() {
    return [{ tag: 'div[id="ultimail-signature"]' }]
  },

  renderHTML({ HTMLAttributes }) {
    return ["div", mergeAttributes(HTMLAttributes, { id: "ultimail-signature" }), 0]
  },
})

const SIG_REGEX = /<div id="ultimail-signature">[\s\S]*<\/div>/

function stripSignature(html: string) {
  return html.replace(SIG_REGEX, "")
}

function insertSignatureHtml(html: string, sigId: string | null) {
  const sig = sigId ? SIGNATURES.find((s) => s.id === sigId) : null
  const clean = stripSignature(html)
  if (!sig) return clean
  return clean + `<div id="ultimail-signature"><p>--</p>${sig.html}</div>`
}

/** Menus/popovers Radix default z-50 ; compose sheet content uses z-61+. */
const COMPOSE_PORTAL_Z = "z-[100]"

const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/

function RecipientField({
  label,
  contacts,
  onChange,
  placeholder,
  onActivate,
  autoFocus,
  onAutoFocusDone,
}: {
  label: string
  contacts: Contact[]
  onChange: (contacts: Contact[]) => void
  placeholder?: string
  onActivate?: () => void
  autoFocus?: boolean
  onAutoFocusDone?: () => void
}) {
  const [inputValue, setInputValue] = useState("")
  const [showSuggestions, setShowSuggestions] = useState(false)
  const [selectedSuggestionIdx, setSelectedSuggestionIdx] = useState(0)
  const inputRef = useRef<HTMLInputElement>(null)
  const containerRef = useRef<HTMLDivElement>(null)

  const suggestions = useMemo(() => {
    if (!inputValue.trim()) return []
    const q = inputValue.toLowerCase()
    return MOCK_CONTACTS.filter(
      (c) =>
        !contacts.some((existing) => existing.email === c.email) &&
        (c.name.toLowerCase().includes(q) || c.email.toLowerCase().includes(q))
    ).slice(0, 6)
  }, [inputValue, contacts])

  useEffect(() => {
    setSelectedSuggestionIdx(0)
  }, [suggestions.length])

  useEffect(() => {
    if (!autoFocus) return
    const id = window.requestAnimationFrame(() => {
      inputRef.current?.focus()
      onAutoFocusDone?.()
    })
    return () => window.cancelAnimationFrame(id)
  }, [autoFocus, onAutoFocusDone])

  const addContact = useCallback(
    (contact: Contact) => {
      if (!contacts.some((c) => c.email === contact.email)) {
        onChange([...contacts, contact])
      }
      setInputValue("")
      setShowSuggestions(false)
    },
    [contacts, onChange]
  )

  const tryAddRawEmail = useCallback(
    (raw: string) => {
      const trimmed = raw.trim().replace(/,$/, "")
      if (!trimmed) return
      const matchedContact = MOCK_CONTACTS.find(
        (c) => c.email.toLowerCase() === trimmed.toLowerCase()
      )
      if (matchedContact) {
        addContact(matchedContact)
      } else if (EMAIL_REGEX.test(trimmed)) {
        addContact({ name: trimmed, email: trimmed })
      }
    },
    [addContact]
  )

  const removeContact = useCallback(
    (email: string) => {
      onChange(contacts.filter((c) => c.email !== email))
    },
    [contacts, onChange]
  )

  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (
      (e.key === "Enter" || e.key === "Tab" || e.key === "," || e.key === " ") &&
      inputValue.trim()
    ) {
      e.preventDefault()
      if (showSuggestions && suggestions.length > 0) {
        addContact(suggestions[selectedSuggestionIdx])
      } else {
        tryAddRawEmail(inputValue)
      }
      return
    }
    if (e.key === "Backspace" && !inputValue && contacts.length > 0) {
      onChange(contacts.slice(0, -1))
      return
    }
    if (showSuggestions && suggestions.length > 0) {
      if (e.key === "ArrowDown") {
        e.preventDefault()
        setSelectedSuggestionIdx((i) =>
          i < suggestions.length - 1 ? i + 1 : 0
        )
      } else if (e.key === "ArrowUp") {
        e.preventDefault()
        setSelectedSuggestionIdx((i) =>
          i > 0 ? i - 1 : suggestions.length - 1
        )
      }
    }
    if (e.key === "Escape") {
      setShowSuggestions(false)
    }
  }

  const getInitials = (name: string) => {
    const parts = name.split(" ").filter(Boolean)
    return parts.length >= 2
      ? (parts[0][0] + parts[parts.length - 1][0]).toUpperCase()
      : (parts[0]?.[0] ?? "").toUpperCase()
  }

  const pillColors = [
    "bg-blue-600",
    "bg-purple-600",
    "bg-emerald-600",
    "bg-amber-600",
    "bg-rose-600",
    "bg-teal-600",
    "bg-indigo-600",
  ]

  const getColor = (email: string) => {
    let hash = 0
    for (let i = 0; i < email.length; i++) {
      hash = email.charCodeAt(i) + ((hash << 5) - hash)
    }
    return pillColors[Math.abs(hash) % pillColors.length]
  }

  return (
    <div className="relative" ref={containerRef}>
      <div
        className="flex min-h-[32px] cursor-text flex-wrap items-center gap-1 px-3 py-1"
        onClick={() => {
          inputRef.current?.focus()
          onActivate?.()
        }}
      >
        <span className="shrink-0 text-sm text-[#5f6368] select-none">{label}</span>
        {contacts.map((c) => (
          <span
            key={c.email}
            className="inline-flex items-center gap-1 rounded-full bg-[#e8eaed] py-0.5 pl-0.5 pr-2 text-sm text-[#3c4043] hover:bg-[#d2d5d9] transition-colors"
          >
            <span
              className={cn(
                "flex h-6 w-6 items-center justify-center rounded-full text-[10px] font-bold text-white",
                getColor(c.email)
              )}
            >
              {getInitials(c.name)}
            </span>
            <span className="max-w-[150px] truncate text-sm">
              {c.name === c.email ? c.email : c.name}
            </span>
            <button
              type="button"
              onClick={() => removeContact(c.email)}
              className="ml-0.5 flex h-4 w-4 items-center justify-center rounded-full hover:bg-black/10"
            >
              <X className="h-3 w-3" />
            </button>
          </span>
        ))}
        <input
          ref={inputRef}
          type="text"
          value={inputValue}
          onChange={(e) => {
            setInputValue(e.target.value)
            setShowSuggestions(true)
          }}
          onKeyDown={handleKeyDown}
          onFocus={() => {
            setShowSuggestions(true)
            onActivate?.()
          }}
          onBlur={() => {
            setTimeout(() => {
              setShowSuggestions(false)
              if (inputValue.trim()) tryAddRawEmail(inputValue)
            }, 200)
          }}
          placeholder={contacts.length === 0 ? placeholder : undefined}
          className="min-w-[120px] flex-1 border-none bg-transparent py-1 text-sm text-[#202124] outline-none placeholder:text-[#80868b]"
        />
      </div>
      {showSuggestions && suggestions.length > 0 && (
        <div className="absolute left-0 right-0 top-full z-50 mt-1 max-h-[240px] overflow-y-auto rounded-lg border border-[#dadce0] bg-white py-1 shadow-lg">
          {suggestions.map((s, idx) => (
            <button
              key={s.email}
              type="button"
              onMouseDown={(e) => {
                e.preventDefault()
                addContact(s)
              }}
              className={cn(
                "flex w-full items-center gap-3 px-3 py-2 text-left text-sm transition-colors",
                idx === selectedSuggestionIdx
                  ? "bg-[#e8f0fe]"
                  : "hover:bg-[#f1f3f4]"
              )}
            >
              <span
                className={cn(
                  "flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-xs font-bold text-white",
                  getColor(s.email)
                )}
              >
                {getInitials(s.name)}
              </span>
              <div className="min-w-0 flex-1">
                <div className="truncate font-medium text-[#202124]">{s.name}</div>
                <div className="truncate text-xs text-[#5f6368]">{s.email}</div>
              </div>
            </button>
          ))}
        </div>
      )}
    </div>
  )
}

function AlignmentDropdown({
  editor,
  btnClass,
  activeClass,
}: {
  editor: NonNullable<ReturnType<typeof useEditor>>
  btnClass: string
  activeClass: string
}) {
  const currentIcon = editor.isActive({ textAlign: "center" })
    ? AlignCenter
    : editor.isActive({ textAlign: "right" })
      ? AlignRight
      : editor.isActive({ textAlign: "justify" })
        ? AlignJustify
        : AlignLeft
  const CurrentIcon = currentIcon

  return (
    <DropdownMenu>
      <DropdownMenuTrigger asChild>
        <button
          type="button"
          className={cn(btnClass, "w-auto gap-0.5 px-1")}
          title="Alignement"
        >
          <CurrentIcon className="h-4 w-4" />
          <ChevronDown className="h-3 w-3" />
        </button>
      </DropdownMenuTrigger>
      <DropdownMenuContent
        align="start"
        className={cn("min-w-[160px]", COMPOSE_PORTAL_Z)}
      >
        <DropdownMenuItem
          onSelect={() => editor.chain().focus().setTextAlign("left").run()}
          className={cn(editor.isActive({ textAlign: "left" }) && "bg-[#e8eaed]")}
        >
          <AlignLeft className="h-4 w-4" /> Aligner à gauche
        </DropdownMenuItem>
        <DropdownMenuItem
          onSelect={() => editor.chain().focus().setTextAlign("center").run()}
          className={cn(editor.isActive({ textAlign: "center" }) && "bg-[#e8eaed]")}
        >
          <AlignCenter className="h-4 w-4" /> Centrer
        </DropdownMenuItem>
        <DropdownMenuItem
          onSelect={() => editor.chain().focus().setTextAlign("right").run()}
          className={cn(editor.isActive({ textAlign: "right" }) && "bg-[#e8eaed]")}
        >
          <AlignRight className="h-4 w-4" /> Aligner à droite
        </DropdownMenuItem>
        <DropdownMenuItem
          onSelect={() => editor.chain().focus().setTextAlign("justify").run()}
          className={cn(editor.isActive({ textAlign: "justify" }) && "bg-[#e8eaed]")}
        >
          <AlignJustify className="h-4 w-4" /> Justifier
        </DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

const FONT_FAMILIES = [
  { label: "Sans Serif", value: "sans-serif" },
  { label: "Serif", value: "serif" },
  { label: "Monospace", value: "monospace" },
  { label: "Cursive", value: "cursive" },
  { label: "Comic Sans MS", value: "Comic Sans MS, cursive" },
  { label: "Garamond", value: "Garamond, serif" },
  { label: "Georgia", value: "Georgia, serif" },
  { label: "Impact", value: "Impact, sans-serif" },
  { label: "Tahoma", value: "Tahoma, sans-serif" },
  { label: "Trebuchet MS", value: "Trebuchet MS, sans-serif" },
  { label: "Verdana", value: "Verdana, sans-serif" },
]

const FONT_SIZES = [
  { label: "Très petit", value: "10px" },
  { label: "Petit", value: "13px" },
  { label: "Normal", value: "" },
  { label: "Grand", value: "18px" },
  { label: "Très grand", value: "24px" },
  { label: "Énorme", value: "32px" },
]

const TEXT_COLORS = [
  "#000000", "#434343", "#666666", "#999999", "#cccccc", "#efefef", "#f3f3f3", "#ffffff",
  "#fb4934", "#fe8019", "#fabd2f", "#b8bb26", "#8ec07c", "#83a598", "#d3869b", "#ebdbb2",
  "#cc241d", "#d65d0e", "#d79921", "#98971a", "#689d6a", "#458588", "#b16286", "#a89984",
  "#9d0006", "#af3a03", "#b57614", "#79740e", "#427b58", "#076678", "#8f3f71", "#7c6f64",
]

function FontDropdown({
  editor,
  btnClass,
}: {
  editor: NonNullable<ReturnType<typeof useEditor>>
  btnClass: string
}) {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger asChild>
        <button type="button" className={cn(btnClass, "w-auto gap-0.5 px-1")} title="Police">
          <CaseSensitive className="h-4 w-4" />
          <ChevronDown className="h-3 w-3" />
        </button>
      </DropdownMenuTrigger>
      <DropdownMenuContent
        align="start"
        className={cn("max-h-[280px] min-w-[180px] overflow-y-auto", COMPOSE_PORTAL_Z)}
      >
        {FONT_FAMILIES.map((f) => (
          <DropdownMenuItem
            key={f.value}
            onSelect={() => editor.chain().focus().setMark("textStyle", { fontFamily: f.value }).run()}
            style={{ fontFamily: f.value }}
            className={cn(
              editor.isActive("textStyle", { fontFamily: f.value }) && "bg-[#e8eaed]"
            )}
          >
            {f.label}
          </DropdownMenuItem>
        ))}
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

function FontSizeDropdown({
  editor,
  btnClass,
}: {
  editor: NonNullable<ReturnType<typeof useEditor>>
  btnClass: string
}) {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger asChild>
        <button type="button" className={cn(btnClass, "w-auto gap-0.5 px-1")} title="Taille du texte">
          <ALargeSmall className="h-4 w-4" />
          <ChevronDown className="h-3 w-3" />
        </button>
      </DropdownMenuTrigger>
      <DropdownMenuContent
        align="start"
        className={cn("min-w-[140px]", COMPOSE_PORTAL_Z)}
      >
        {FONT_SIZES.map((s) => (
          <DropdownMenuItem
            key={s.label}
            onSelect={() => {
              if (s.value) {
                editor.chain().focus().setMark("textStyle", { fontSize: s.value }).run()
              } else {
                editor.chain().focus().setMark("textStyle", { fontSize: null }).removeEmptyTextStyle().run()
              }
            }}
            style={s.value ? { fontSize: s.value } : undefined}
            className={cn(
              s.value && editor.isActive("textStyle", { fontSize: s.value }) && "bg-[#e8eaed]"
            )}
          >
            {s.label}
          </DropdownMenuItem>
        ))}
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

function ColorDropdown({
  editor,
  btnClass,
}: {
  editor: NonNullable<ReturnType<typeof useEditor>>
  btnClass: string
}) {
  const [tab, setTab] = useState<"text" | "bg">("text")

  return (
    <DropdownMenu>
      <DropdownMenuTrigger asChild>
        <button type="button" className={cn(btnClass, "w-auto gap-0.5 px-1")} title="Couleur du texte">
          <Palette className="h-4 w-4" />
          <ChevronDown className="h-3 w-3" />
        </button>
      </DropdownMenuTrigger>
      <DropdownMenuContent
        align="start"
        className={cn("w-[268px] p-2", COMPOSE_PORTAL_Z)}
        onCloseAutoFocus={(e) => e.preventDefault()}
      >
        <div className="mb-2 flex gap-1 border-b border-[#eef0f2] pb-2">
          <button
            type="button"
            className={cn(
              "flex-1 rounded px-2 py-1 text-xs font-medium transition-colors",
              tab === "text" ? "bg-[#e8eaed] text-[#202124]" : "text-[#5f6368] hover:bg-[#f1f3f4]"
            )}
            onClick={() => setTab("text")}
          >
            Couleur du texte
          </button>
          <button
            type="button"
            className={cn(
              "flex-1 rounded px-2 py-1 text-xs font-medium transition-colors",
              tab === "bg" ? "bg-[#e8eaed] text-[#202124]" : "text-[#5f6368] hover:bg-[#f1f3f4]"
            )}
            onClick={() => setTab("bg")}
          >
            Couleur de fond
          </button>
        </div>
        <div className="grid grid-cols-8 gap-1">
          {TEXT_COLORS.map((color) => (
            <button
              key={`${tab}-${color}`}
              type="button"
              className="h-6 w-6 rounded border border-[#dadce0] hover:scale-110 transition-transform"
              style={{ backgroundColor: color }}
              title={color}
              onClick={() => {
                if (tab === "text") {
                  editor.chain().focus().setColor(color).run()
                } else {
                  editor.chain().focus().setMark("textStyle", { backgroundColor: color }).run()
                }
              }}
            />
          ))}
        </div>
        <button
          type="button"
          className="mt-2 w-full rounded px-2 py-1 text-xs text-[#5f6368] hover:bg-[#f1f3f4] transition-colors"
          onClick={() => {
            if (tab === "text") {
              editor.chain().focus().unsetColor().run()
            } else {
              editor.chain().focus().setMark("textStyle", { backgroundColor: null }).removeEmptyTextStyle().run()
            }
          }}
        >
          Réinitialiser
        </button>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

function FormattingToolbar({
  editor,
}: {
  editor: Editor | null
}) {
  if (!editor) return null

  const btnClass =
    "flex h-7 w-7 items-center justify-center rounded hover:bg-[#f1f3f4] text-[#5f6368] transition-colors disabled:opacity-40"
  const activeClass = "bg-[#e8eaed] text-[#202124]"
  const sep = <span className="mx-0.5 h-5 w-px bg-[#dadce0]" aria-hidden />

  return (
    <div className="flex flex-wrap items-center border-t border-[#eef0f2] bg-[#f8f9fa] px-1 py-1">
      {/* Undo / Redo */}
      <button
        type="button"
        className={btnClass}
        onClick={() => editor.chain().focus().undo().run()}
        disabled={!editor.can().undo()}
        title="Annuler"
      >
        <Undo className="h-4 w-4" />
      </button>
      <button
        type="button"
        className={btnClass}
        onClick={() => editor.chain().focus().redo().run()}
        disabled={!editor.can().redo()}
        title="Rétablir"
      >
        <Redo className="h-4 w-4" />
      </button>

      {sep}

      {/* Font */}
      <FontDropdown editor={editor} btnClass={btnClass} />

      {sep}

      {/* Font size */}
      <FontSizeDropdown editor={editor} btnClass={btnClass} />

      {sep}

      {/* Bold, Italic, Underline, Colors */}
      <button
        type="button"
        className={cn(btnClass, editor.isActive("bold") && activeClass)}
        onClick={() => editor.chain().focus().toggleMark("bold").run()}
        title="Gras"
      >
        <Bold className="h-4 w-4" />
      </button>
      <button
        type="button"
        className={cn(btnClass, editor.isActive("italic") && activeClass)}
        onClick={() => editor.chain().focus().toggleMark("italic").run()}
        title="Italique"
      >
        <Italic className="h-4 w-4" />
      </button>
      <button
        type="button"
        className={cn(btnClass, editor.isActive("underline") && activeClass)}
        onClick={() => editor.chain().focus().toggleUnderline().run()}
        title="Souligné"
      >
        <UnderlineIcon className="h-4 w-4" />
      </button>
      <ColorDropdown editor={editor} btnClass={btnClass} />

      {sep}

      {/* Alignment dropdown, lists, indent/outdent, remove formatting */}
      <AlignmentDropdown editor={editor} btnClass={btnClass} activeClass={activeClass} />
      <button
        type="button"
        className={cn(btnClass, editor.isActive("orderedList") && activeClass)}
        onClick={() => editor.chain().focus().toggleOrderedList().run()}
        title="Liste numérotée"
      >
        <ListOrdered className="h-4 w-4" />
      </button>
      <button
        type="button"
        className={cn(btnClass, editor.isActive("bulletList") && activeClass)}
        onClick={() => editor.chain().focus().toggleBulletList().run()}
        title="Liste à puces"
      >
        <List className="h-4 w-4" />
      </button>
      <button
        type="button"
        className={btnClass}
        onClick={() => {
          try { editor.chain().focus().liftListItem("listItem").run() } catch { /* not in list */ }
        }}
        title="Désindenter"
      >
        <Outdent className="h-4 w-4" />
      </button>
      <button
        type="button"
        className={btnClass}
        onClick={() => {
          try { editor.chain().focus().sinkListItem("listItem").run() } catch { /* not in list */ }
        }}
        title="Indenter"
      >
        <Indent className="h-4 w-4" />
      </button>
      <button
        type="button"
        className={btnClass}
        onClick={() => editor.chain().focus().clearNodes().unsetAllMarks().run()}
        title="Supprimer la mise en forme"
      >
        <RemoveFormatting className="h-4 w-4" />
      </button>
    </div>
  )
}

function EmojiButton({
  editor,
}: {
  editor: Editor | null
}) {
  const [open, setOpen] = useState(false)

  const handleSelect = useCallback(
    (emoji: { native: string }) => {
      editor?.chain().focus().insertContent(emoji.native).run()
      setOpen(false)
    },
    [editor]
  )

  if (!editor) return null

  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <button
          type="button"
          className="flex h-8 w-8 items-center justify-center rounded-full text-[#5f6368] hover:bg-[#f1f3f4] transition-colors"
          title="Insérer un emoji"
        >
          <Smile className="h-[18px] w-[18px]" />
        </button>
      </PopoverTrigger>
      <PopoverContent
        align="start"
        side="top"
        className={cn("w-auto border-0 p-0 shadow-xl", COMPOSE_PORTAL_Z)}
        onOpenAutoFocus={(e) => e.preventDefault()}
      >
        <EmojiPicker onSelect={handleSelect} />
      </PopoverContent>
    </Popover>
  )
}

function LinkButton({
  editor,
}: {
  editor: Editor | null
}) {
  const [open, setOpen] = useState(false)
  const [url, setUrl] = useState("")
  const [text, setText] = useState("")

  if (!editor) return null

  const isLinkActive = editor.isActive("link")

  const handleToggle = () => {
    if (isLinkActive) {
      editor.chain().focus().extendMarkRange("link").unsetLink().run()
      return
    }
    setOpen(true)
  }

  const handleOpen = (isOpen: boolean) => {
    if (isOpen) {
      const { from, to, empty } = editor.state.selection
      if (isLinkActive) {
        const attrs = editor.getAttributes("link")
        setUrl(attrs.href || "")
        const selectedText = editor.state.doc.textBetween(from, to, " ")
        setText(selectedText)
      } else if (!empty) {
        const selectedText = editor.state.doc.textBetween(from, to, " ")
        setText(selectedText)
        setUrl("")
      } else {
        setText("")
        setUrl("")
      }
    }
    setOpen(isOpen)
  }

  const handleInsert = () => {
    if (!url.trim()) return
    const href = url.match(/^https?:\/\//) ? url : `https://${url}`

    const { empty } = editor.state.selection

    if (empty && !isLinkActive) {
      const displayText = text.trim() || href
      editor
        .chain()
        .focus()
        .insertContent(`<a href="${href}">${displayText}</a>`)
        .run()
    } else {
      if (text.trim() && text.trim() !== editor.state.doc.textBetween(
        editor.state.selection.from,
        editor.state.selection.to,
        " "
      )) {
        editor
          .chain()
          .focus()
          .deleteSelection()
          .insertContent(`<a href="${href}">${text.trim()}</a>`)
          .run()
      } else {
        editor
          .chain()
          .focus()
          .extendMarkRange("link")
          .setLink({ href })
          .run()
      }
    }

    setOpen(false)
    setUrl("")
    setText("")
  }

  const handleRemoveLink = () => {
    editor.chain().focus().extendMarkRange("link").unsetLink().run()
    setOpen(false)
    setUrl("")
    setText("")
  }

  return (
    <Popover open={open} onOpenChange={handleOpen}>
      <PopoverTrigger asChild>
        <button
          type="button"
          onClick={(e) => {
            if (isLinkActive) {
              e.preventDefault()
              handleToggle()
            }
          }}
          className={cn(
            "flex h-8 w-8 items-center justify-center rounded-full text-[#5f6368] hover:bg-[#f1f3f4] transition-colors",
            isLinkActive && "bg-[#e8eaed] text-[#202124]"
          )}
          title={isLinkActive ? "Supprimer le lien" : "Insérer un lien"}
        >
          <LinkIcon className="h-[18px] w-[18px]" />
        </button>
      </PopoverTrigger>
      <PopoverContent
        align="start"
        side="top"
        className={cn("w-[340px] p-3", COMPOSE_PORTAL_Z)}
        onOpenAutoFocus={(e) => e.preventDefault()}
      >
        <div className="flex flex-col gap-2.5">
          <div className="text-sm font-medium text-[#202124]">
            {isLinkActive ? "Modifier le lien" : "Insérer un lien"}
          </div>
          <div className="flex flex-col gap-1.5">
            <label className="text-xs text-[#5f6368]">Texte à afficher</label>
            <input
              type="text"
              value={text}
              onChange={(e) => setText(e.target.value)}
              placeholder="Texte du lien"
              className="h-8 rounded border border-[#dadce0] bg-white px-2 text-sm text-[#202124] outline-none focus:border-[#1a73e8] focus:ring-1 focus:ring-[#1a73e8]"
            />
          </div>
          <div className="flex flex-col gap-1.5">
            <label className="text-xs text-[#5f6368]">URL</label>
            <input
              type="text"
              value={url}
              onChange={(e) => setUrl(e.target.value)}
              placeholder="https://example.com"
              onKeyDown={(e) => {
                if (e.key === "Enter") {
                  e.preventDefault()
                  handleInsert()
                }
              }}
              className="h-8 rounded border border-[#dadce0] bg-white px-2 text-sm text-[#202124] outline-none focus:border-[#1a73e8] focus:ring-1 focus:ring-[#1a73e8]"
              autoFocus
            />
          </div>
          <div className="flex items-center justify-between pt-1">
            {isLinkActive ? (
              <button
                type="button"
                onClick={handleRemoveLink}
                className="text-sm text-[#d93025] hover:text-[#b3261e] transition-colors"
              >
                Supprimer le lien
              </button>
            ) : (
              <span />
            )}
            <div className="flex gap-2">
              <button
                type="button"
                onClick={() => setOpen(false)}
                className="rounded px-3 py-1.5 text-sm text-[#5f6368] hover:bg-[#f1f3f4] transition-colors"
              >
                Annuler
              </button>
              <button
                type="button"
                onClick={handleInsert}
                disabled={!url.trim()}
                className="rounded bg-[#0b57d0] px-3 py-1.5 text-sm font-medium text-white hover:bg-[#0842a0] disabled:opacity-50 transition-colors"
              >
                {isLinkActive ? "Modifier" : "Insérer"}
              </button>
            </div>
          </div>
        </div>
      </PopoverContent>
    </Popover>
  )
}

function SignatureButton({
  editor,
  compose,
}: {
  editor: Editor | null
  compose: ComposeState
}) {
  const { updateCompose } = useComposeActions()

  const replaceSignature = useCallback(
    (sigId: string | null) => {
      if (!editor) return
      const newHtml = insertSignatureHtml(editor.getHTML(), sigId)
      editor.commands.setContent(newHtml)
      updateCompose(compose.id, { bodyHtml: newHtml, signatureId: sigId })
    },
    [editor, compose.id, updateCompose]
  )

  const toggleAutoInsert = useCallback(() => {
    const newVal = !compose.autoInsertSignature
    updateCompose(compose.id, { autoInsertSignature: newVal })
    if (!newVal) {
      replaceSignature(null)
    } else {
      const sigId = compose.from.defaultSignatureId
      if (sigId) replaceSignature(sigId)
    }
  }, [compose.autoInsertSignature, compose.from.defaultSignatureId, compose.id, updateCompose, replaceSignature])

  if (!editor) return null

  return (
    <DropdownMenu modal={false}>
      <DropdownMenuTrigger asChild>
        <button
          type="button"
          className="flex h-8 w-8 items-center justify-center rounded-full text-[#5f6368] hover:bg-[#f1f3f4] transition-colors"
          title="Insérer une signature"
        >
          <PenTool className="h-[18px] w-[18px]" />
        </button>
      </DropdownMenuTrigger>
      <DropdownMenuContent
        align="start"
        side="top"
        className={cn("min-w-[220px]", COMPOSE_PORTAL_Z)}
      >
        <DropdownMenuItem
          onSelect={(e) => {
            e.preventDefault()
            toggleAutoInsert()
          }}
          className="gap-2"
        >
          <span className="flex h-4 w-4 items-center justify-center">
            {compose.autoInsertSignature && <span className="text-xs">✓</span>}
          </span>
          Insérer automatiquement
        </DropdownMenuItem>
        <DropdownMenuSeparator />
        <DropdownMenuItem
          onSelect={() => replaceSignature(null)}
          className={cn("gap-2", !compose.signatureId && "bg-[#e8eaed]")}
        >
          <span className="flex h-4 w-4 items-center justify-center">
            {!compose.signatureId && <span className="text-xs">✓</span>}
          </span>
          Aucune signature
        </DropdownMenuItem>
        {SIGNATURES.map((sig) => (
          <DropdownMenuItem
            key={sig.id}
            onSelect={() => replaceSignature(sig.id)}
            className={cn("gap-2", compose.signatureId === sig.id && "bg-[#e8eaed]")}
          >
            <span className="flex h-4 w-4 items-center justify-center">
              {compose.signatureId === sig.id && <span className="text-xs">✓</span>}
            </span>
            {sig.name}
          </DropdownMenuItem>
        ))}
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

interface ComposeRecipientFieldsProps {
  compose: ComposeState
  isInline: boolean
  showFromField: boolean
  updateCompose: (id: string, patch: Partial<ComposeState>) => void
  handleIdentityChange: (identity: (typeof DEFAULT_IDENTITIES)[number]) => void
  clearFocusToMount: () => void
  subjectInputRef: React.RefObject<HTMLInputElement | null>
  onRecipientsActivate: () => void
}

function ComposeRecipientFields({
  compose,
  isInline,
  showFromField,
  updateCompose,
  handleIdentityChange,
  clearFocusToMount,
  subjectInputRef,
  onRecipientsActivate,
}: ComposeRecipientFieldsProps) {
  const dockNewMessageTabOrder =
    !isInline && !compose.threadEmailId && !compose.threadKind
  const forwardDockSkipSubjectTab =
    !isInline && compose.threadKind === "forward"

  return (
    <>
      {showFromField && (
        <div className="flex min-w-0 items-center gap-2 overflow-hidden px-3 py-1.5">
          <span className="shrink-0 text-sm text-[#5f6368]">De</span>
          <DropdownMenu modal={false}>
            <DropdownMenuTrigger asChild>
              <button
                type="button"
                className="flex min-w-0 items-center gap-1 rounded px-1 py-0.5 text-sm text-[#202124] hover:bg-[#f1f3f4]"
              >
                <span className="min-w-0 truncate font-medium">{compose.from.name}</span>
                <span className="min-w-0 shrink truncate text-[#5f6368]">
                  &lt;{compose.from.email}&gt;
                </span>
                <ChevronDown className="h-3 w-3 shrink-0 text-[#5f6368]" />
              </button>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="start" className={cn("min-w-[300px]", COMPOSE_PORTAL_Z)}>
              {DEFAULT_IDENTITIES.map((id) => (
                <DropdownMenuItem
                  key={id.email}
                  onSelect={() => handleIdentityChange(id)}
                >
                  <div className="flex flex-col">
                    <span className="font-medium">{id.name}</span>
                    <span className="text-xs text-[#5f6368]">
                      {id.email}
                    </span>
                  </div>
                </DropdownMenuItem>
              ))}
            </DropdownMenuContent>
          </DropdownMenu>
        </div>
      )}
      {showFromField && !isInline && (
        <div className="ml-3 border-b border-[#eef0f2]" />
      )}

      <div className="relative flex items-start">
        <div className="min-w-0 flex-1">
          <RecipientField
            label={showFromField || compose.to.length > 0 ? "À" : "Destinataires"}
            contacts={compose.to}
            onChange={(to) => updateCompose(compose.id, { to })}
            onActivate={onRecipientsActivate}
            autoFocus={Boolean(compose.focusToOnMount)}
            onAutoFocusDone={clearFocusToMount}
          />
        </div>
        {showFromField && (!compose.showCc || !compose.showBcc) && (
          <div className="flex shrink-0 items-center gap-1 px-2 py-1.5">
            {!compose.showCc && (
              <button
                type="button"
                tabIndex={dockNewMessageTabOrder ? -1 : undefined}
                onClick={() => updateCompose(compose.id, { showCc: true })}
                className="text-sm text-[#5f6368] hover:text-[#202124] hover:underline"
              >
                Cc
              </button>
            )}
            {!compose.showBcc && (
              <button
                type="button"
                tabIndex={dockNewMessageTabOrder ? -1 : undefined}
                onClick={() => updateCompose(compose.id, { showBcc: true })}
                className="text-sm text-[#5f6368] hover:text-[#202124] hover:underline"
              >
                Cci
              </button>
            )}
          </div>
        )}
      </div>
      {!isInline && <div className="ml-3 border-b border-[#eef0f2]" />}

      {compose.showCc && (
        <>
          <RecipientField
            label="Cc"
            contacts={compose.cc}
            onChange={(cc) => updateCompose(compose.id, { cc })}
          />
          {!isInline && <div className="ml-3 border-b border-[#eef0f2]" />}
        </>
      )}

      {compose.showBcc && (
        <>
          <RecipientField
            label="Cci"
            contacts={compose.bcc}
            onChange={(bcc) => updateCompose(compose.id, { bcc })}
          />
          {!isInline && <div className="ml-3 border-b border-[#eef0f2]" />}
        </>
      )}

      {!isInline && (
        <>
          <input
            ref={subjectInputRef}
            type="text"
            value={compose.subject}
            onChange={(e) =>
              updateCompose(compose.id, { subject: e.target.value })
            }
            placeholder="Objet"
            tabIndex={forwardDockSkipSubjectTab ? -1 : undefined}
            className="h-8 w-full border-none bg-transparent px-3 text-sm text-[#202124] outline-none placeholder:text-[#80868b]"
          />
          <div className="ml-3 border-b border-[#eef0f2]" />
        </>
      )}
    </>
  )
}

export function ComposeWindow({
  compose,
  threadSourceEmail = null,
  isXsSheet = false,
  bindXsSheetClose,
}: {
  compose: ComposeState
  /** Fil courant : nécessaire pour le menu Répondre / Transférer en inline */
  threadSourceEmail?: Email | null
  /** Plein écran dans une bottom sheet (xs) — pas de file ni réduction */
  isXsSheet?: boolean
  bindXsSheetClose?: (fn: (() => void) | null) => void
}) {
  const {
    closeCompose,
    updateCompose,
    applyComposePreset,
    toggleMinimize,
    toggleMaximize,
    restoreComposeFromSnapshot,
  } = useComposeActions()
  const { scheduleSend, requestUpdateScheduledSend, requestSendScheduledNow } =
    useScheduledMail()
  const isInline = compose.placement === "inline"
  const isEditingScheduled = compose.editingScheduledId != null
  const [showFormatting, setShowFormatting] = useState(false)
  const [recipientsFocused, setRecipientsFocused] = useState(false)
  const [sendMenuOpen, setSendMenuOpen] = useState(false)
  const [isDragOver, setIsDragOver] = useState(false)
  const fieldsRef = useRef<HTMLDivElement>(null)
  const inlineRecipientShellRef = useRef<HTMLDivElement>(null)
  const subjectInputRef = useRef<HTMLInputElement>(null)
  const fileInputRef = useRef<HTMLInputElement>(null)
  const imageInputRef = useRef<HTMLInputElement>(null)

  const snapBodyCaretToStartOnHeaderTab =
    !isInline &&
    !compose.threadEmailId &&
    !compose.threadKind &&
    !compose.editingScheduledId

  const editor = useEditor({
    immediatelyRender: false,
    extensions: [
      StarterKit,
      Underline,
      Link.configure({ openOnClick: false }),
      TextStyle,
      Color,
      BackgroundColor,
      FontFamily,
      FontSize,
      TextAlign.configure({ types: ["heading", "paragraph"], alignments: ["left", "center", "right", "justify"] }),
      SignatureBlock,
    ] as Extensions,
    content: compose.bodyHtml,
    onUpdate: ({ editor: ed }) => {
      updateCompose(compose.id, { bodyHtml: ed.getHTML() })
    },
    onFocus: ({ editor: ed, event }) => {
      if (!snapBodyCaretToStartOnHeaderTab) return
      const rt = event.relatedTarget as Node | null
      if (!rt || !fieldsRef.current?.contains(rt)) return
      window.requestAnimationFrame(() => {
        if (!ed.view.hasFocus()) return
        try {
          ed.chain().setTextSelection(1).run()
        } catch {
          /* empty doc edge */
        }
      })
    },
    editorProps: {
      attributes: {
        class: cn(
          "prose prose-sm max-w-none px-3 py-2 text-sm text-[#202124] outline-none focus:outline-none",
          isInline
            ? "min-h-[200px]"
            : isXsSheet
              ? "min-h-[min(36vh,280px)]"
              : "min-h-[150px]"
        ),
      },
    },
  })

  const titleText = compose.subject || "Nouveau message"
  const bodyWithoutSig = stripSignature(compose.bodyHtml)
    .replace(/<p><\/p>/g, "")
    .trim()
  const hasContent =
    compose.subject.trim() !== "" ||
    compose.to.length > 0 ||
    compose.cc.length > 0 ||
    compose.bcc.length > 0 ||
    compose.attachments.length > 0 ||
    bodyWithoutSig !== ""

  const handleIdentityChange = useCallback(
    (identity: (typeof DEFAULT_IDENTITIES)[number]) => {
      if (compose.autoInsertSignature && editor) {
        const sigId = identity.defaultSignatureId
        const newHtml = insertSignatureHtml(editor.getHTML(), sigId)
        editor.commands.setContent(newHtml)
        updateCompose(compose.id, { from: identity, bodyHtml: newHtml, signatureId: sigId })
      } else {
        updateCompose(compose.id, { from: identity })
      }
    },
    [compose.id, compose.autoInsertSignature, editor, updateCompose]
  )

  const handleClose = () => {
    const threadInlineDiscard =
      isInline && compose.threadEmailId
        ? ({ discardThreadReplyDraft: true } as const)
        : undefined
    if (!hasContent) {
      closeCompose(compose.id, threadInlineDiscard)
    } else {
      updateCompose(compose.id, { savedAt: Date.now() })
      closeCompose(compose.id, threadInlineDiscard)
    }
  }

  const handleCloseRef = useRef(handleClose)
  handleCloseRef.current = handleClose

  useLayoutEffect(() => {
    if (!isXsSheet || !bindXsSheetClose) return
    bindXsSheetClose(() => {
      handleCloseRef.current()
    })
    return () => bindXsSheetClose(null)
  }, [isXsSheet, bindXsSheetClose, compose.id])

  const htmlToPreviewText = useCallback((html: string) => {
    return html
      .replace(/<style[^>]*>[\s\S]*?<\/style>/gi, " ")
      .replace(/<[^>]+>/g, " ")
      .replace(/\s+/g, " ")
      .trim()
  }, [])

  const handleSend = useCallback(() => {
    if (compose.to.length === 0) return
    const bodyHtml = editor?.getHTML() ?? compose.bodyHtml
    const snapshot = cloneComposeForPendingSend({ ...compose, bodyHtml })
    closeCompose(compose.id, { sent: true })
    showPendingSendToast({
      onCommit: async () => {},
      onCancel: () => restoreComposeFromSnapshot(snapshot),
    })
  }, [
    closeCompose,
    compose,
    editor,
    restoreComposeFromSnapshot,
  ])

  const submitScheduledSendAt = useCallback(
    async (sendAt: Date) => {
      if (isEditingScheduled) return
      if (compose.to.length === 0) return
      setSendMenuOpen(false)
      const bodyHtml = editor?.getHTML() ?? compose.bodyHtml
      await scheduleSend({
        sendAtIso: sendAt.toISOString(),
        to: compose.to.map((c) => ({ name: c.name, email: c.email })),
        subject: compose.subject,
        previewText: htmlToPreviewText(bodyHtml).slice(0, 500),
        bodyHtml,
      })
      const whenLabel = sendAt.toLocaleString("fr-FR", {
        dateStyle: "medium",
        timeStyle: "short",
      })
      toast.message(`Ce mail sera envoyé le ${whenLabel}`)
      closeCompose(compose.id, { sent: true })
    },
    [
      isEditingScheduled,
      compose.bodyHtml,
      compose.id,
      compose.subject,
      compose.to,
      closeCompose,
      editor,
      htmlToPreviewText,
      scheduleSend,
    ]
  )

  const buildSchedulePayload = useCallback(
    (sendAtIso: string): ScheduleSendPayload | null => {
      if (compose.to.length === 0) return null
      const bodyHtml = editor?.getHTML() ?? compose.bodyHtml
      return {
        sendAtIso,
        to: compose.to.map((c) => ({ name: c.name, email: c.email })),
        subject: compose.subject,
        previewText: htmlToPreviewText(bodyHtml).slice(0, 500),
        bodyHtml,
      }
    },
    [compose.to, compose.subject, compose.bodyHtml, editor, htmlToPreviewText]
  )

  const saveScheduledEdit = useCallback(async () => {
    const id = compose.editingScheduledId
    if (!id) return
    const iso =
      compose.scheduledSendAtIso ?? new Date().toISOString()
    const payload = buildSchedulePayload(iso)
    if (!payload) return
    await requestUpdateScheduledSend(id, payload)
    toast.message("Modifications enregistrées")
    closeCompose(compose.id)
  }, [
    buildSchedulePayload,
    closeCompose,
    compose.editingScheduledId,
    compose.id,
    compose.scheduledSendAtIso,
    requestUpdateScheduledSend,
  ])

  const sendScheduledFromEditNow = useCallback(async () => {
    const id = compose.editingScheduledId
    if (!id) return
    setSendMenuOpen(false)
    const bodyHtml = editor?.getHTML() ?? compose.bodyHtml
    const snapshot = cloneComposeForPendingSend({ ...compose, bodyHtml })
    closeCompose(compose.id, { sent: true })
    showPendingSendToast({
      onCommit: async () => {
        const schedId = snapshot.editingScheduledId
        if (!schedId || snapshot.to.length === 0) return
        const iso = snapshot.scheduledSendAtIso ?? new Date().toISOString()
        const body = snapshot.bodyHtml
        const payload = {
          sendAtIso: iso,
          to: snapshot.to.map((c) => ({ name: c.name, email: c.email })),
          subject: snapshot.subject,
          previewText: htmlToPreviewText(body).slice(0, 500),
          bodyHtml: body,
        }
        await requestUpdateScheduledSend(schedId, payload)
        await requestSendScheduledNow(schedId)
      },
      onCancel: () => restoreComposeFromSnapshot(snapshot),
    })
  }, [
    closeCompose,
    compose,
    editor,
    htmlToPreviewText,
    requestSendScheduledNow,
    requestUpdateScheduledSend,
    restoreComposeFromSnapshot,
  ])

  const applyScheduledPlanAt = useCallback(
    async (sendAt: Date) => {
      const id = compose.editingScheduledId
      if (!id) return
      setSendMenuOpen(false)
      const iso = sendAt.toISOString()
      const payload = buildSchedulePayload(iso)
      if (!payload) return
      await requestUpdateScheduledSend(id, payload)
      updateCompose(compose.id, { scheduledSendAtIso: iso })
      const whenLabel = sendAt.toLocaleString("fr-FR", {
        dateStyle: "medium",
        timeStyle: "short",
      })
      toast.message(`Envoi planifié le ${whenLabel}`)
    },
    [
      buildSchedulePayload,
      compose.editingScheduledId,
      compose.id,
      requestUpdateScheduledSend,
      updateCompose,
    ]
  )

  const addFiles = useCallback((files: FileList | File[]) => {
    const newAttachments = Array.from(files).map((file) => ({
      id: `att-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
      file,
      name: file.name,
      size: file.size,
      type: file.type,
    }))
    updateCompose(compose.id, {
      attachments: [...compose.attachments, ...newAttachments],
    })
  }, [compose.id, compose.attachments, updateCompose])

  const removeAttachment = useCallback((attId: string) => {
    updateCompose(compose.id, {
      attachments: compose.attachments.filter((a) => a.id !== attId),
    })
  }, [compose.id, compose.attachments, updateCompose])

  const handleDrop = useCallback((e: React.DragEvent) => {
    e.preventDefault()
    e.stopPropagation()
    setIsDragOver(false)
    if (e.dataTransfer.files.length > 0) {
      addFiles(e.dataTransfer.files)
    }
  }, [addFiles])

  const handleDragOver = useCallback((e: React.DragEvent) => {
    e.preventDefault()
    e.stopPropagation()
    setIsDragOver(true)
  }, [])

  const handleDragLeave = useCallback((e: React.DragEvent) => {
    e.preventDefault()
    e.stopPropagation()
    if (e.currentTarget === e.target || !e.currentTarget.contains(e.relatedTarget as Node)) {
      setIsDragOver(false)
    }
  }, [])

  const showFromField = recipientsFocused || isXsSheet

  useLayoutEffect(() => {
    if (!isInline || !compose.focusToOnMount) return
    setRecipientsFocused(true)
  }, [isInline, compose.focusToOnMount])

  useEffect(() => {
    if (!recipientsFocused) return
    const handleClickOutside = (e: Event) => {
      const target = e.target as Node
      const root = isInline ? inlineRecipientShellRef.current : fieldsRef.current
      if (root && !root.contains(target)) {
        const el = e.target as HTMLElement | null
        const portal = el?.closest?.(
          "[data-radix-popper-content-wrapper], [data-radix-dropdown-menu-content], [data-slot='dropdown-menu-content'], [data-slot='popover-content']"
        )
        if (portal) return
        setRecipientsFocused(false)
        if (compose.showCc && compose.cc.length === 0) {
          updateCompose(compose.id, { showCc: false })
        }
        if (compose.showBcc && compose.bcc.length === 0) {
          updateCompose(compose.id, { showBcc: false })
        }
      }
    }
    document.addEventListener("pointerdown", handleClickOutside)
    return () => document.removeEventListener("pointerdown", handleClickOutside)
  }, [
    recipientsFocused,
    isInline,
    compose.showCc,
    compose.showBcc,
    compose.cc.length,
    compose.bcc.length,
    compose.id,
    updateCompose,
  ])

  useEffect(() => {
    if (!editor || editor.isDestroyed) return
    const next = compose.bodyHtml
    if (editor.getHTML() === next) return
    editor.commands.setContent(next, { emitUpdate: false })
  }, [compose.bodyHtml, compose.threadKind, editor])

  useEffect(() => {
    if (!compose.focusSubjectOnMount || isInline) return
    const id = window.requestAnimationFrame(() => {
      subjectInputRef.current?.focus()
      updateCompose(compose.id, { focusSubjectOnMount: false })
    })
    return () => window.cancelAnimationFrame(id)
  }, [compose.focusSubjectOnMount, isInline, compose.id, updateCompose])

  useEffect(() => {
    if (!compose.focusBodyOnMount || !editor || editor.isDestroyed) return
    let cancelled = false
    const outer = window.requestAnimationFrame(() => {
      window.requestAnimationFrame(() => {
        if (cancelled || !editor || editor.isDestroyed) return
        try {
          editor.chain().focus().setTextSelection(1).run()
        } catch {
          editor.chain().focus().run()
        }
        updateCompose(compose.id, { focusBodyOnMount: false })
      })
    })
    return () => {
      cancelled = true
      window.cancelAnimationFrame(outer)
    }
  }, [compose.focusBodyOnMount, compose.id, editor, updateCompose])

  const clearFocusToMount = useCallback(() => {
    updateCompose(compose.id, { focusToOnMount: false })
  }, [compose.id, updateCompose])

  const ThreadKindIcon =
    compose.threadKind === "forward"
      ? Forward
      : compose.threadKind === "replyAll"
        ? ReplyAll
        : Reply

  const recipientSummary =
    compose.to.length === 0
      ? "Destinataires"
      : compose.to.length === 1 && compose.to[0]
        ? compose.to[0].name === compose.to[0].email
          ? compose.to[0].email
          : `${compose.to[0].name} <${compose.to[0].email}>`
        : `${compose.to.length} destinataires`

  const showReplyAllInMenu = useMemo(
    () =>
      Boolean(
        threadSourceEmail &&
          collectThreadParticipants(threadSourceEmail).length > 1
      ),
    [threadSourceEmail]
  )

  const openInlinePreset = useCallback(
    (kind: "reply" | "replyAll" | "forward") => {
      if (!threadSourceEmail) return
      applyComposePreset(
        compose.id,
        buildThreadComposePreset(threadSourceEmail, kind)
      )
    },
    [threadSourceEmail, applyComposePreset, compose.id]
  )

  const openDockFromInline = useCallback(
    (opts?: { focusSubject?: boolean }) => {
      setRecipientsFocused(false)
      updateCompose(compose.id, {
        placement: "dock",
        threadEmailId: null,
        focusToOnMount: false,
        focusBodyOnMount: false,
        minimized: false,
        maximized: false,
        focusSubjectOnMount: Boolean(opts?.focusSubject),
      })
    },
    [compose.id, updateCompose]
  )

  const recipientFieldsProps = {
    compose,
    isInline,
    showFromField,
    updateCompose,
    handleIdentityChange,
    clearFocusToMount,
    subjectInputRef,
    onRecipientsActivate: () => setRecipientsFocused(true),
  }

  const modalContent = (
    <div
      className={cn(
        "relative flex flex-col overflow-hidden bg-white",
        isInline
          ? "min-h-[360px] w-full rounded-xl border border-[#dadce0] shadow-none transition-shadow focus-within:shadow-[0_1px_4px_rgba(60,64,67,0.12)]"
          : isXsSheet
            ? "h-full min-h-0 w-full max-w-none flex-1 rounded-none shadow-none"
            : cn(
                "rounded-t-lg shadow-[0_-2px_8px_rgba(0,0,0,0.08),_-4px_0_12px_rgba(0,0,0,0.12),_4px_0_12px_rgba(0,0,0,0.12)]",
                compose.maximized
                  ? readCoarsePointerMatches()
                    ? "fixed inset-0 z-60 rounded-none"
                    : "fixed inset-12 z-60 rounded-lg"
                  : "h-[480px] w-[500px]"
              )
      )}
      onDrop={handleDrop}
      onDragOver={handleDragOver}
      onDragLeave={handleDragLeave}
    >
      {/* Hidden file inputs */}
      <input
        ref={fileInputRef}
        type="file"
        multiple
        className="hidden"
        onChange={(e) => {
          if (e.target.files && e.target.files.length > 0) {
            addFiles(e.target.files)
            e.target.value = ""
          }
        }}
      />
      <input
        ref={imageInputRef}
        type="file"
        multiple
        accept="image/*"
        className="hidden"
        onChange={(e) => {
          if (e.target.files && e.target.files.length > 0) {
            addFiles(e.target.files)
            e.target.value = ""
          }
        }}
      />

      {/* Drop overlay */}
      {isDragOver && (
        <div className="absolute inset-0 z-50 flex items-center justify-center rounded-lg bg-blue-50/90 border-2 border-dashed border-[#1a73e8]">
          <div className="text-center">
            <Paperclip className="mx-auto h-8 w-8 text-[#1a73e8]" />
            <p className="mt-2 text-sm font-medium text-[#1a73e8]">Déposer les fichiers ici</p>
          </div>
        </div>
      )}
      {isInline ? (
        <div ref={inlineRecipientShellRef} className="flex shrink-0 flex-col">
          <div
            className="flex h-10 shrink-0 items-center gap-2 bg-white px-2"
            title={
              compose.threading
                ? `In-Reply-To: ${compose.threading.inReplyTo}\nReferences: ${compose.threading.references.join(" ")}`
                : undefined
            }
          >
            <DropdownMenu modal={false}>
              <DropdownMenuTrigger asChild>
                <button
                  type="button"
                  className="flex h-8 shrink-0 items-center gap-0.5 rounded-full px-1.5 text-[#5f6368] transition-colors hover:bg-[#f1f3f4]"
                  title="Type de message"
                >
                  <ThreadKindIcon className="h-[18px] w-[18px] shrink-0" strokeWidth={1.75} />
                  <ChevronDown className="h-4 w-4 shrink-0" />
                </button>
              </DropdownMenuTrigger>
              <DropdownMenuContent
                align="start"
                className={cn("min-w-[260px]", COMPOSE_PORTAL_Z)}
                onCloseAutoFocus={(e) => e.preventDefault()}
              >
                <DropdownMenuItem
                  disabled={!threadSourceEmail}
                  onSelect={() => openInlinePreset("reply")}
                >
                  <Reply className="mr-2 h-4 w-4 shrink-0 text-[#5f6368]" strokeWidth={1.75} />
                  Répondre
                </DropdownMenuItem>
                {showReplyAllInMenu ? (
                  <DropdownMenuItem
                    disabled={!threadSourceEmail}
                    onSelect={() => openInlinePreset("replyAll")}
                  >
                    <ReplyAll className="mr-2 h-4 w-4 shrink-0 text-[#5f6368]" strokeWidth={1.75} />
                    Répondre à tous
                  </DropdownMenuItem>
                ) : null}
                <DropdownMenuItem
                  disabled={!threadSourceEmail}
                  onSelect={() => openInlinePreset("forward")}
                >
                  <Forward className="mr-2 h-4 w-4 shrink-0 text-[#5f6368]" strokeWidth={1.75} />
                  Transférer
                </DropdownMenuItem>
                <DropdownMenuSeparator />
                <DropdownMenuItem onSelect={() => openDockFromInline({ focusSubject: true })}>
                  <Pencil className="mr-2 h-4 w-4 shrink-0 text-[#5f6368]" strokeWidth={1.75} />
                  Modifier l&apos;objet
                </DropdownMenuItem>
                <DropdownMenuItem onSelect={() => openDockFromInline()}>
                  <SquareArrowOutUpRight className="mr-2 h-4 w-4 shrink-0 text-[#5f6368]" strokeWidth={1.75} />
                  Ouvrir une fenêtre de réponse
                </DropdownMenuItem>
              </DropdownMenuContent>
            </DropdownMenu>

            <button
              type="button"
              className="min-w-0 flex-1 truncate rounded px-1 py-1 text-left text-sm text-[#202124] hover:bg-[#f1f3f4]/70"
              onClick={() => setRecipientsFocused(true)}
            >
              {recipientSummary}
            </button>

            {!recipientsFocused && (!compose.showCc || !compose.showBcc) ? (
              <div className="flex shrink-0 items-center gap-2">
                {!compose.showCc ? (
                  <button
                    type="button"
                    onClick={() => {
                      updateCompose(compose.id, { showCc: true })
                      setRecipientsFocused(true)
                    }}
                    className="text-sm text-[#5f6368] hover:text-[#202124] hover:underline"
                  >
                    Cc
                  </button>
                ) : null}
                {!compose.showBcc ? (
                  <button
                    type="button"
                    onClick={() => {
                      updateCompose(compose.id, { showBcc: true })
                      setRecipientsFocused(true)
                    }}
                    className="text-sm text-[#5f6368] hover:text-[#202124] hover:underline"
                  >
                    Cci
                  </button>
                ) : null}
              </div>
            ) : null}

            <button
              type="button"
              className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-[#5f6368] hover:bg-[#f1f3f4]"
              title="Ouvrir dans une fenêtre"
              onClick={() => openDockFromInline()}
            >
              <SquareArrowOutUpRight className="h-[18px] w-[18px]" strokeWidth={1.75} />
            </button>
          </div>
          <div
            ref={fieldsRef}
            className={cn(
              "flex shrink-0 flex-col",
              !recipientsFocused && "hidden"
            )}
          >
            <ComposeRecipientFields {...recipientFieldsProps} />
          </div>
        </div>
      ) : isXsSheet ? (
        <div
          className={cn(
            "flex h-11 shrink-0 items-center border-b border-[#dadce0] bg-[#f2f6fc] px-3",
            "pt-[max(_0.25rem,env(safe-area-inset-top))]"
          )}
        >
          <span className="min-w-0 flex-1 truncate text-sm font-medium text-[#3c4043]">
            {titleText}
          </span>
          <button
            type="button"
            onClick={handleClose}
            className="flex h-8 w-8 items-center justify-center rounded-full text-[#5f6368] hover:text-[#202124] hover:bg-black/5"
            title="Fermer"
          >
            <X className="h-4 w-4" />
          </button>
        </div>
      ) : (
        <>
          {/* Title bar */}
          <div
            className="flex h-10 shrink-0 cursor-pointer items-center rounded-t-lg bg-[#f2f6fc] px-3"
            onClick={() => toggleMinimize(compose.id)}
          >
            <span className="min-w-0 flex-1 truncate text-sm font-medium text-[#3c4043]">
              {titleText}
            </span>
            <div className="flex items-center gap-0.5">
              <button
                type="button"
                onClick={(e) => {
                  e.stopPropagation()
                  toggleMinimize(compose.id)
                }}
                className="flex h-6 w-6 items-center justify-center rounded-full text-[#5f6368] hover:text-[#202124] hover:bg-black/5"
                title="Réduire"
              >
                <svg
                  xmlns="http://www.w3.org/2000/svg"
                  width="14"
                  height="14"
                  viewBox="0 0 24 24"
                  fill="none"
                  stroke="currentColor"
                  strokeWidth="2"
                  strokeLinecap="round"
                  className="shrink-0"
                  aria-hidden
                >
                  <line x1="5" y1="17" x2="19" y2="17" />
                </svg>
              </button>
              <button
                type="button"
                onClick={(e) => {
                  e.stopPropagation()
                  toggleMaximize(compose.id)
                }}
                className="flex h-6 w-6 items-center justify-center rounded-full text-[#5f6368] hover:text-[#202124] hover:bg-black/5"
                title={compose.maximized ? "Réduire la fenêtre" : "Plein écran"}
              >
                {compose.maximized ? (
                  <Minimize2 className="h-3.5 w-3.5" />
                ) : (
                  <Maximize2 className="h-3.5 w-3.5" />
                )}
              </button>
              <button
                type="button"
                onClick={(e) => {
                  e.stopPropagation()
                  handleClose()
                }}
                className="flex h-6 w-6 items-center justify-center rounded-full text-[#5f6368] hover:text-[#202124] hover:bg-black/5"
                title="Fermer"
              >
                <X className="h-3.5 w-3.5" />
              </button>
            </div>
          </div>
        </>
      )}

      {!isInline && (
      <div
        ref={fieldsRef}
        className="flex shrink-0 flex-col"
      >
        <ComposeRecipientFields {...recipientFieldsProps} />
      </div>
      )}

      {/* Editor */}
      <div className="min-h-0 flex-1 overflow-y-auto">
        <EditorContent editor={editor} />
      </div>

      {/* Attachments */}
      {compose.attachments.length > 0 && (
        <div className="flex shrink-0 flex-col gap-1 border-t border-[#eef0f2] px-3 py-2 max-h-[120px] overflow-y-auto">
          {compose.attachments.map((att) => (
            <div
              key={att.id}
              className="flex items-center gap-2 rounded-lg border border-[#dadce0] bg-[#f8f9fa] px-3 py-1.5"
            >
              {att.type.startsWith("image/") ? (
                <ImageIcon className="h-4 w-4 shrink-0 text-[#1a73e8]" />
              ) : (
                <Paperclip className="h-4 w-4 shrink-0 text-[#5f6368]" />
              )}
              <span className="min-w-0 flex-1 truncate text-sm text-[#3c4043]">
                {att.name}
              </span>
              <span className="shrink-0 text-xs text-[#80868b]">
                {att.size < 1024
                  ? `${att.size} o`
                  : att.size < 1048576
                    ? `${(att.size / 1024).toFixed(1)} Ko`
                    : `${(att.size / 1048576).toFixed(1)} Mo`}
              </span>
              <button
                type="button"
                onClick={() => removeAttachment(att.id)}
                className="flex h-5 w-5 shrink-0 items-center justify-center rounded-full text-[#5f6368] hover:bg-black/10"
                title="Supprimer"
              >
                <X className="h-3.5 w-3.5" />
              </button>
            </div>
          ))}
        </div>
      )}

      {/* Formatting toolbar (toggle) */}
      {showFormatting && <FormattingToolbar editor={editor} />}

      {/* Bottom toolbar */}
      <div className="flex shrink-0 items-center gap-1 border-t border-[#dadce0] px-2 py-1.5">
        {/* Send / save + dropdown */}
        <div className="flex items-center">
          {isEditingScheduled ? (
            <>
              <button
                type="button"
                onClick={() => void saveScheduledEdit()}
                className="h-9 rounded-l-full bg-[#0b57d0] px-5 text-sm font-medium text-white hover:bg-[#0842a0] hover:shadow-md transition-all"
              >
                Enregistrer
              </button>
              <DropdownMenu modal={false} open={sendMenuOpen} onOpenChange={setSendMenuOpen}>
                <DropdownMenuTrigger asChild>
                  <button
                    type="button"
                    className="h-9 rounded-r-full border-l border-white/30 bg-[#0b57d0] px-1.5 text-white hover:bg-[#0842a0] transition-colors"
                  >
                    <ChevronDown className="h-4 w-4" />
                  </button>
                </DropdownMenuTrigger>
                <DropdownMenuContent align="start" className={cn("min-w-[220px]", COMPOSE_PORTAL_Z)}>
                  <DropdownMenuItem
                    onSelect={() => {
                      void sendScheduledFromEditNow()
                    }}
                  >
                    <Send className="h-4 w-4 text-[#5f6368]" strokeWidth={1.5} />
                    Envoyer maintenant
                  </DropdownMenuItem>
                  <DropdownMenuSub>
                    <DropdownMenuSubTrigger className="[&>svg:last-child]:text-[#5f6368]">
                      <Clock className="h-4 w-4 text-[#5f6368]" strokeWidth={1.5} />
                      Planifier
                    </DropdownMenuSubTrigger>
                    <DropdownMenuSubContent className={cn("min-w-[220px]", COMPOSE_PORTAL_Z)}>
                      <DropdownMenuItem
                        onSelect={() => {
                          void applyScheduledPlanAt(
                            new Date(Date.now() + 60 * 60 * 1000)
                          )
                        }}
                      >
                        <Clock className="h-4 w-4 text-[#5f6368]" strokeWidth={1.5} />
                        Envoyer dans une heure
                      </DropdownMenuItem>
                      <DropdownMenuItem
                        onSelect={() => {
                          void applyScheduledPlanAt(
                            getNextLocalWallClockDate(9, 0)
                          )
                        }}
                      >
                        <Clock className="h-4 w-4 text-[#5f6368]" strokeWidth={1.5} />
                        Envoyer à 9h
                      </DropdownMenuItem>
                    </DropdownMenuSubContent>
                  </DropdownMenuSub>
                </DropdownMenuContent>
              </DropdownMenu>
            </>
          ) : (
            <>
              <button
                type="button"
                onClick={handleSend}
                className="h-9 rounded-l-full bg-[#0b57d0] px-5 text-sm font-medium text-white hover:bg-[#0842a0] hover:shadow-md transition-all"
              >
                Envoyer
              </button>
              <DropdownMenu modal={false} open={sendMenuOpen} onOpenChange={setSendMenuOpen}>
                <DropdownMenuTrigger asChild>
                  <button
                    type="button"
                    className="h-9 rounded-r-full border-l border-white/30 bg-[#0b57d0] px-1.5 text-white hover:bg-[#0842a0] transition-colors"
                  >
                    <ChevronDown className="h-4 w-4" />
                  </button>
                </DropdownMenuTrigger>
                <DropdownMenuContent align="start" className={cn("min-w-[220px]", COMPOSE_PORTAL_Z)}>
                  <DropdownMenuItem
                    onSelect={() => {
                      void submitScheduledSendAt(
                        new Date(Date.now() + 60 * 60 * 1000)
                      )
                    }}
                  >
                    <Clock className="h-4 w-4 text-[#5f6368]" />
                    Envoyer dans une heure
                  </DropdownMenuItem>
                  <DropdownMenuItem
                    onSelect={() => {
                      void submitScheduledSendAt(
                        getNextLocalWallClockDate(9, 0)
                      )
                    }}
                  >
                    <Clock className="h-4 w-4 text-[#5f6368]" />
                    Envoyer à 9h
                  </DropdownMenuItem>
                  <DropdownMenuItem onSelect={() => setSendMenuOpen(false)}>
                    <Clock className="h-4 w-4 text-[#5f6368]" />
                    Programmer l&apos;envoi
                  </DropdownMenuItem>
                </DropdownMenuContent>
              </DropdownMenu>
            </>
          )}
        </div>

        {/* Toolbar icons */}
        <div className="flex items-center gap-0.5 ml-1">
          <button
            type="button"
            onClick={() => setShowFormatting(!showFormatting)}
            className={cn(
              "flex h-8 w-8 items-center justify-center rounded-full text-[#5f6368] hover:bg-[#f1f3f4] transition-colors",
              showFormatting && "bg-[#e8eaed] text-[#202124]"
            )}
            title="Options de mise en forme"
          >
            <Type className="h-[18px] w-[18px]" />
          </button>
          <button
            type="button"
            className="flex h-8 w-8 items-center justify-center rounded-full text-[#5f6368] hover:bg-[#f1f3f4] transition-colors"
            title="Joindre des fichiers"
            onClick={() => fileInputRef.current?.click()}
          >
            <Paperclip className="h-[18px] w-[18px]" />
          </button>
          <LinkButton editor={editor} />
          <EmojiButton editor={editor} />
          <button
            type="button"
            className="flex h-8 w-8 items-center justify-center rounded-full text-[#5f6368] hover:bg-[#f1f3f4] transition-colors"
            title="Insérer des fichiers avec Google Drive"
          >
            <HardDrive className="h-[18px] w-[18px]" />
          </button>
          <button
            type="button"
            className="flex h-8 w-8 items-center justify-center rounded-full text-[#5f6368] hover:bg-[#f1f3f4] transition-colors"
            title="Insérer une photo"
            onClick={() => imageInputRef.current?.click()}
          >
            <ImageIcon className="h-[18px] w-[18px]" />
          </button>
          <button
            type="button"
            className="flex h-8 w-8 items-center justify-center rounded-full text-[#5f6368] hover:bg-[#f1f3f4] transition-colors"
            title="Activer le mode confidentiel"
          >
            <Lock className="h-[18px] w-[18px]" />
          </button>
          <SignatureButton editor={editor} compose={compose} />
          <button
            type="button"
            className="flex h-8 w-8 items-center justify-center rounded-full text-[#5f6368] hover:bg-[#f1f3f4] transition-colors"
            title="Plus d'options"
          >
            <MoreVertical className="h-[18px] w-[18px]" />
          </button>
        </div>

        <div className="flex-1" />

        <button
          type="button"
          onClick={handleClose}
          className="flex h-8 w-8 items-center justify-center rounded-full text-[#5f6368] hover:bg-[#f1f3f4] transition-colors"
          title="Supprimer le brouillon"
        >
          <Trash2 className="h-[18px] w-[18px]" />
        </button>
      </div>
    </div>
  )

  if (compose.minimized && !isInline && !isXsSheet) {
    return (
      <div
        className="flex h-9 w-[280px] cursor-pointer items-center rounded-t-lg bg-[#f2f6fc] px-3 shadow-lg transition-shadow hover:shadow-xl"
        onClick={() => toggleMinimize(compose.id)}
      >
        <span className="min-w-0 flex-1 truncate text-sm font-medium text-[#3c4043]">
          {titleText}
        </span>
        <div className="flex items-center gap-0.5">
          <button
            type="button"
            onClick={(e) => {
              e.stopPropagation()
              toggleMaximize(compose.id)
            }}
            className="flex h-6 w-6 items-center justify-center rounded-full text-[#5f6368] hover:text-[#202124] hover:bg-black/5"
          >
            <Maximize2 className="h-3.5 w-3.5" />
          </button>
          <button
            type="button"
            onClick={(e) => {
              e.stopPropagation()
              handleClose()
            }}
            className="flex h-6 w-6 items-center justify-center rounded-full text-[#5f6368] hover:text-[#202124] hover:bg-black/5"
          >
            <X className="h-3.5 w-3.5" />
          </button>
        </div>
      </div>
    )
  }

  if (compose.maximized && !isInline && !isXsSheet) {
    return (
      <>
        <div
          className="fixed inset-0 z-55 bg-black/50"
          onClick={() => toggleMaximize(compose.id)}
        />
        {modalContent}
      </>
    )
  }

  return modalContent
}

export function ComposeModalManager() {
  const { composeWindows } = useComposeWindows()
  const isXs = useIsXs()

  const nonMaximized = composeWindows.filter(
    (w) => !w.maximized && w.placement !== "inline"
  )
  const maximized = composeWindows.filter((w) => w.maximized && w.placement !== "inline")

  const xsSheetCloseRef = useRef<(() => void) | null>(null)
  const bindXsSheetClose = useCallback((fn: (() => void) | null) => {
    xsSheetCloseRef.current = fn
  }, [])

  /** Une seule fenêtre dock visible en xs : la plus récente (comportement type pile). */
  const xsActiveDock =
    isXs && nonMaximized.length > 0 ? nonMaximized[nonMaximized.length - 1] : null

  const handleXsSheetOpenChange = useCallback((open: boolean) => {
    if (!open) {
      xsSheetCloseRef.current?.()
    }
  }, [])

  const MODAL_WIDTH = 500
  const MINIMIZED_WIDTH = 280
  const GAP = 12
  const RIGHT_OFFSET = 80

  const positions = useMemo(() => {
    const reversed = [...nonMaximized].reverse()
    const result: { id: string; right: number; hidden: boolean }[] = []
    let cursor = RIGHT_OFFSET
    for (let i = 0; i < reversed.length; i++) {
      const w = reversed[i]
      const width = w.minimized ? MINIMIZED_WIDTH : MODAL_WIDTH
      result.push({
        id: w.id,
        right: cursor,
        hidden: i >= 2 && !w.minimized,
      })
      cursor += width + GAP
    }
    return result
  }, [nonMaximized])

  if (isXs) {
    return (
      <>
        <Sheet open={xsActiveDock != null} onOpenChange={handleXsSheetOpenChange}>
          <SheetContent
            side="bottom"
            hideClose
            overlayClassName="z-[60]"
            className="z-[61] h-[100dvh] max-h-[100dvh] w-full gap-0 rounded-none border-0 p-0 shadow-none duration-300 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:slide-in-from-bottom data-[state=closed]:slide-out-to-bottom overflow-hidden pb-[env(safe-area-inset-bottom)]"
          >
            <SheetTitle className="sr-only">
              {(xsActiveDock?.subject ?? "").trim() || "Nouveau message"}
            </SheetTitle>
            {xsActiveDock ? (
              <ComposeWindow
                key={xsActiveDock.id}
                compose={xsActiveDock}
                isXsSheet
                bindXsSheetClose={bindXsSheetClose}
              />
            ) : null}
          </SheetContent>
        </Sheet>

        {maximized.map((compose) => (
          <div key={compose.id} className="pointer-events-auto">
            <ComposeWindow compose={compose} />
          </div>
        ))}
      </>
    )
  }

  return (
    <>
      {nonMaximized.map((compose) => {
        const pos = positions.find((p) => p.id === compose.id)
        if (!pos) return null
        return (
          <div
            key={compose.id}
            className={cn(
              "pointer-events-auto fixed bottom-0 z-50 transition-all duration-300",
              pos.hidden && "invisible"
            )}
            style={{ right: pos.right }}
          >
            <ComposeWindow compose={compose} />
          </div>
        )
      })}

      {maximized.map((compose) => (
        <div key={compose.id} className="pointer-events-auto">
          <ComposeWindow compose={compose} />
        </div>
      ))}
    </>
  )
}
