"use client"

/**
 * MessageThread — composant de messagerie partagé
 * Utilisé côté client (portail) ET côté tenant (admin)
 *
 * Features:
 * - Messages texte + pièces jointes (images, PDF, fichiers, audio)
 * - Enregistrement audio via MediaRecorder
 * - Indicateur de frappe (polling)
 * - Auto-refresh (polling toutes les 5s)
 * - Défilement automatique vers le bas
 * - Modifier / Supprimer ses messages
 * - Avatars, côtés (customer / tenant), horodatage relatif
 */

import React, { useCallback, useEffect, useRef, useState } from "react"
import {
  Send, Paperclip, Mic, MicOff, StopCircle, Pencil, Trash2, X,
  FileText, FileImage, FileAudio2, FileVideo2, File as FileIcon, Download,
  ChevronDown, Loader2, CheckCheck, AlertCircle, Play, Pause,
  Phone, Video,
} from "lucide-react"
import type { CallSession } from "@/src/lib/api/calls"
import { CallModal, IncomingCallBanner } from "@/src/components/messaging/CallModal"

// ── Types ──────────────────────────────────────────────────────────────────
export type MsgAttachment = {
  id: number
  filename?: string | null
  content_type?: string | null
  size?: number | null
  file: string | null
  created_at?: string
}

export type Msg = {
  id: number
  case_id?: number
  author: { id: number; username: string; first_name?: string | null; last_name?: string | null } | null
  author_side: "customer" | "tenant"
  body: string
  visibility?: "shared" | "internal"
  action_required?: boolean
  created_at: string
  is_read?: boolean | null
  attachments: MsgAttachment[]
}

export type MessageThreadProps = {
  /** ID de l'utilisateur connecté (pour déterminer "mes messages") */
  myUserId: number | null
  /** Quel côté est l'utilisateur courant */
  mySide: "customer" | "tenant"
  /** Messages à afficher */
  messages: Msg[]
  loading: boolean
  sending: boolean
  error?: string | null
  /** Labels des personnes en train d'écrire */
  typingLabels?: string[]
  /** Appels API injectés depuis le parent */
  onSend: (payload: { body: string; files?: File[] }) => Promise<void>
  onEdit?: (msg: Msg, newBody: string) => Promise<void>
  onDelete?: (msg: Msg) => Promise<void>
  onMarkRead?: (msgId: number) => void
  /** Appelé quand l'utilisateur tape (pour signaler au backend) */
  onTyping?: () => void
  onStopTyping?: () => void
  /** Palette de couleurs */
  accentColor?: string
  myBubbleColor?: string
  otherBubbleColor?: string
  /** Labels i18n */
  placeholder?: string
  sendLabel?: string
  internalLabel?: string
  labels?: {
    loading?: string
    noMessages?: string
    save?: string
    cancel?: string
    editingLabel?: string
    recording?: string
    stopRecording?: string
    joinCall?: string
    callAudio?: string
    callVideo?: string
    attachFile?: string
    voiceMsg?: string
    stopRecord?: string
    agentBadge?: string
    internalBadge?: string
    typingOne?: string
    typingMany?: string
    confirmDelete?: string
    fileLabel?: string
  }
  /** Appels audio/vidéo */
  activeCall?: CallSession | null
  myCallDisplayName?: string
  onStartCall?: (type: "audio" | "video") => void
  onJoinCall?: () => void
  onEndCall?: () => void
}

// ── Helpers ────────────────────────────────────────────────────────────────
function cx(...parts: Array<string | false | null | undefined>) {
  return parts.filter(Boolean).join(" ")
}

function timeAgo(iso: string): string {
  const diff = (Date.now() - new Date(iso).getTime()) / 1000
  if (diff < 60) return "à l'instant"
  if (diff < 3600) return `il y a ${Math.floor(diff / 60)} min`
  if (diff < 86400) return `il y a ${Math.floor(diff / 3600)} h`
  return new Date(iso).toLocaleDateString("fr-FR", { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" })
}

function authorLabel(msg: Msg): string {
  const a = msg.author
  if (!a) return msg.author_side === "tenant" ? "Agent" : "Client"
  const full = `${a.first_name ?? ""} ${a.last_name ?? ""}`.trim()
  return full || a.username
}

function bytesHuman(n?: number | null): string {
  if (!n) return ""
  if (n < 1024) return `${n} B`
  if (n < 1048576) return `${(n / 1024).toFixed(1)} KB`
  return `${(n / 1048576).toFixed(1)} MB`
}

function fileIcon(att: MsgAttachment) {
  const ct = (att.content_type ?? "").toLowerCase()
  const name = (att.filename ?? "").toLowerCase()
  if (ct.startsWith("image/")) return <FileImage className="h-4 w-4 shrink-0" />
  if (ct.startsWith("audio/") || name.endsWith(".mp3") || name.endsWith(".wav") || name.endsWith(".ogg") || name.endsWith(".m4a") || name.endsWith(".opus") || name.endsWith(".webm"))
    return <FileAudio2 className="h-4 w-4 shrink-0" />
  if (ct.startsWith("video/")) return <FileVideo2 className="h-4 w-4 shrink-0" />
  if (ct === "application/pdf" || name.endsWith(".pdf")) return <FileText className="h-4 w-4 shrink-0" />
  return <FileIcon className="h-4 w-4 shrink-0" />
}

function isAudio(att: MsgAttachment): boolean {
  const ct = (att.content_type ?? "").toLowerCase()
  const name = (att.filename ?? "").toLowerCase()
  return ct.startsWith("audio/") || [".mp3",".wav",".ogg",".m4a",".opus",".webm"].some(e => name.endsWith(e))
}

function isImage(att: MsgAttachment): boolean {
  return (att.content_type ?? "").startsWith("image/")
}

// ── Audio Player ───────────────────────────────────────────────────────────
function AudioPlayer({ src }: { src: string }) {
  const ref = useRef<HTMLAudioElement>(null)
  const [playing, setPlaying] = useState(false)
  const [progress, setProgress] = useState(0)
  const [duration, setDuration] = useState(0)

  function toggle() {
    const a = ref.current
    if (!a) return
    if (playing) { a.pause(); setPlaying(false) }
    else { a.play(); setPlaying(true) }
  }

  return (
    <div className="flex items-center gap-2 rounded-xl bg-white/60 px-3 py-2 border border-white/40 min-w-[180px]">
      <audio ref={ref}
        src={src}
        onTimeUpdate={() => { const a = ref.current; if (a) setProgress(a.currentTime) }}
        onLoadedMetadata={() => { const a = ref.current; if (a) setDuration(a.duration) }}
        onEnded={() => setPlaying(false)}
      />
      <button onClick={toggle} className="shrink-0 rounded-full p-1 hover:bg-black/10 transition">
        {playing ? <Pause className="h-4 w-4" /> : <Play className="h-4 w-4" />}
      </button>
      <div className="flex-1 relative h-1.5 rounded-full bg-black/10 overflow-hidden cursor-pointer"
        onClick={(e) => {
          const a = ref.current
          if (!a || !duration) return
          const rect = e.currentTarget.getBoundingClientRect()
          a.currentTime = ((e.clientX - rect.left) / rect.width) * duration
        }}>
        <div className="h-full rounded-full bg-current transition-all"
          style={{ width: duration ? `${(progress / duration) * 100}%` : "0%" }} />
      </div>
      <span className="text-[10px] tabular-nums opacity-60 shrink-0">
        {duration ? `${Math.floor(progress)}s / ${Math.floor(duration)}s` : ""}
      </span>
    </div>
  )
}

// ── Attachment preview ─────────────────────────────────────────────────────
function AttachmentView({ att, accent }: { att: MsgAttachment; accent: string }) {
  if (!att.file) return null

  if (isAudio(att)) {
    return (
      <div className="mt-1.5">
        <AudioPlayer src={att.file} />
        {att.filename && <div className="mt-0.5 text-[10px] opacity-50">{att.filename}</div>}
      </div>
    )
  }

  if (isImage(att)) {
    return (
      <a href={att.file} target="_blank" rel="noopener noreferrer" className="block mt-1.5">
        {/* eslint-disable-next-line @next/next/no-img-element */}
        <img src={att.file} alt={att.filename ?? "image"} className="max-h-52 max-w-xs rounded-xl object-cover border border-white/20" />
      </a>
    )
  }

  return (
    <a href={att.file} target="_blank" rel="noopener noreferrer"
      className="mt-1.5 flex items-center gap-2 rounded-xl border border-white/30 bg-white/20 px-3 py-2 hover:bg-white/30 transition text-sm">
      {fileIcon(att)}
      <span className="truncate max-w-[180px]">{att.filename ?? "…"}</span>
      {att.size && <span className="text-[10px] opacity-60 shrink-0">{bytesHuman(att.size)}</span>}
      <Download className="h-3.5 w-3.5 shrink-0 opacity-60 ml-auto" />
    </a>
  )
}

// ── Mic recorder ───────────────────────────────────────────────────────────
function useMicRecorder(onBlob: (blob: Blob, name: string) => void) {
  const [recording, setRecording] = useState(false)
  const [seconds, setSeconds] = useState(0)
  const recRef = useRef<MediaRecorder | null>(null)
  const chunksRef = useRef<Blob[]>([])
  const timerRef = useRef<ReturnType<typeof setInterval> | null>(null)

  async function start() {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
      const mimeType = MediaRecorder.isTypeSupported("audio/webm;codecs=opus")
        ? "audio/webm;codecs=opus"
        : MediaRecorder.isTypeSupported("audio/ogg;codecs=opus")
        ? "audio/ogg;codecs=opus"
        : "audio/webm"
      const rec = new MediaRecorder(stream, { mimeType })
      chunksRef.current = []
      rec.ondataavailable = (e) => { if (e.data.size > 0) chunksRef.current.push(e.data) }
      rec.onstop = () => {
        stream.getTracks().forEach(t => t.stop())
        const blob = new Blob(chunksRef.current, { type: mimeType })
        const ext = mimeType.includes("ogg") ? "ogg" : "webm"
        onBlob(blob, `voice-${Date.now()}.${ext}`)
      }
      rec.start(200)
      recRef.current = rec
      setRecording(true)
      setSeconds(0)
      timerRef.current = setInterval(() => setSeconds(s => s + 1), 1000)
    } catch {
      alert("Impossible d'accéder au microphone.")
    }
  }

  function stop() {
    recRef.current?.stop()
    recRef.current = null
    if (timerRef.current) clearInterval(timerRef.current)
    setRecording(false)
    setSeconds(0)
  }

  function cancel() {
    recRef.current?.stop()
    recRef.current = null
    chunksRef.current = []
    if (timerRef.current) clearInterval(timerRef.current)
    setRecording(false)
    setSeconds(0)
  }

  return { recording, seconds, start, stop, cancel }
}

// ── Message bubble ─────────────────────────────────────────────────────────
function Bubble({
  msg, isMe, accent, myBubble, otherBubble,
  onEdit, onDelete, agentBadge, internalBadge,
}: {
  msg: Msg
  isMe: boolean
  accent: string
  myBubble: string
  otherBubble: string
  onEdit?: (msg: Msg) => void
  onDelete?: (msg: Msg) => void
  agentBadge?: string
  internalBadge?: string
}) {
  const [hover, setHover] = useState(false)
  const bg = isMe ? myBubble : otherBubble
  const textColor = isMe ? "text-white" : "text-slate-800"

  return (
    <div
      className={cx("flex gap-2 group", isMe ? "flex-row-reverse" : "flex-row")}
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
    >
      {/* Avatar */}
      <div className="h-7 w-7 rounded-full flex items-center justify-center text-[11px] font-bold text-white shrink-0 mt-1"
        style={{ background: isMe ? accent : "#94a3b8" }}>
        {authorLabel(msg).charAt(0).toUpperCase()}
      </div>

      {/* Bubble */}
      <div className={cx("max-w-[75%] space-y-0.5", isMe ? "items-end flex flex-col" : "items-start flex flex-col")}>
        {/* Name + time */}
        <div className={cx("flex items-center gap-2 px-1", isMe ? "flex-row-reverse" : "flex-row")}>
          <span className="text-[11px] font-semibold text-slate-500">{authorLabel(msg)}</span>
          <span className="text-[10px] text-slate-400">{timeAgo(msg.created_at)}</span>
          {msg.author_side === "tenant" && !isMe && (
            <span className="text-[9px] bg-blue-100 text-blue-600 rounded-full px-1.5 py-0.5 font-medium">{agentBadge ?? "Agent"}</span>
          )}
          {msg.visibility === "internal" && (
            <span className="text-[9px] bg-amber-100 text-amber-700 rounded-full px-1.5 py-0.5 font-medium">{internalBadge ?? "Interne"}</span>
          )}
        </div>

        {/* Content */}
        <div className={cx("rounded-2xl px-4 py-2.5 text-sm leading-relaxed shadow-sm relative", textColor)}
          style={{ background: bg }}>
          {msg.body && <p className="whitespace-pre-wrap break-words">{msg.body}</p>}
          {msg.attachments.map(att => (
            <AttachmentView key={att.id} att={att} accent={accent} />
          ))}

          {/* Hover actions */}
          {(onEdit || onDelete) && hover && (
            <div className={cx(
              "absolute -top-7 flex items-center gap-1 bg-white border border-slate-200 rounded-xl shadow-sm px-1.5 py-1",
              isMe ? "right-0" : "left-0"
            )}>
              {onEdit && (
                <button onClick={() => onEdit(msg)}
                  className="rounded-lg p-1 hover:bg-slate-100 text-slate-500 transition"
                  title="Modifier">
                  <Pencil className="h-3.5 w-3.5" />
                </button>
              )}
              {onDelete && (
                <button onClick={() => onDelete(msg)}
                  className="rounded-lg p-1 hover:bg-red-50 text-red-500 transition"
                  title="Supprimer">
                  <Trash2 className="h-3.5 w-3.5" />
                </button>
              )}
            </div>
          )}
        </div>

        {/* Read receipt (only for my messages) */}
        {isMe && msg.is_read && (
          <div className="px-1">
            <CheckCheck className="h-3 w-3 text-slate-400" />
          </div>
        )}
      </div>
    </div>
  )
}

// ── Main component ─────────────────────────────────────────────────────────
const MAX_FILE_MB = 10
const MAX_TOTAL_MB = 25
const ALLOWED_EXT = new Set([
  ".pdf", ".png", ".jpg", ".jpeg", ".webp", ".gif",
  ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx",
  ".txt", ".csv",
  ".mp3", ".wav", ".ogg", ".m4a", ".webm", ".opus",
  ".mp4", ".mov",
])

export function MessageThread({
  myUserId, mySide, messages, loading, sending, error,
  typingLabels = [],
  onSend, onEdit, onDelete, onMarkRead,
  onTyping, onStopTyping,
  accentColor = "#4dba96",
  myBubbleColor,
  otherBubbleColor = "#f1f5f9",
  placeholder = "Écrire un message…",
  sendLabel = "Envoyer",
  labels = {},
  activeCall,
  myCallDisplayName = "Moi",
  onStartCall,
  onJoinCall,
  onEndCall,
}: MessageThreadProps) {
  const L = {
    loading:       labels.loading       ?? "Chargement…",
    noMessages:    labels.noMessages    ?? "Aucun message — commencez la conversation !",
    save:          labels.save          ?? "Sauvegarder",
    cancel:        labels.cancel        ?? "Annuler",
    editingLabel:  labels.editingLabel  ?? "Modification du message",
    recording:     labels.recording     ?? "Enregistrement…",
    stopRecording: labels.stopRecording ?? "Terminer",
    joinCall:      labels.joinCall      ?? "Rejoindre",
    callAudio:     labels.callAudio     ?? "Appel audio",
    callVideo:     labels.callVideo     ?? "Appel vidéo",
    attachFile:    labels.attachFile    ?? "Joindre un fichier",
    voiceMsg:      labels.voiceMsg      ?? "Message vocal",
    stopRecord:    labels.stopRecord    ?? "Arrêter l'enregistrement",
    agentBadge:    labels.agentBadge    ?? "Agent",
    internalBadge: labels.internalBadge ?? "Interne",
    typingOne:     labels.typingOne     ?? "écrit…",
    typingMany:    labels.typingMany    ?? "écrivent…",
    confirmDelete: labels.confirmDelete ?? "Supprimer ce message ?",
    fileLabel:     labels.fileLabel     ?? "Fichier",
  }
  const myBubble = myBubbleColor ?? accentColor

  const bottomRef = useRef<HTMLDivElement>(null)
  const fileInputRef = useRef<HTMLInputElement>(null)
  const typingTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)

  const [body, setBody] = useState("")
  const [pendingFiles, setPendingFiles] = useState<File[]>([])
  const [editingMsg, setEditingMsg] = useState<Msg | null>(null)
  const [editBody, setEditBody] = useState("")
  const [editBusy, setEditBusy] = useState(false)
  const [showScrollBtn, setShowScrollBtn] = useState(false)
  const [callOpen, setCallOpen] = useState(false)
  const [ignoredCallId, setIgnoredCallId] = useState<number | null>(null)

  // Scroll to bottom when new messages arrive
  useEffect(() => {
    bottomRef.current?.scrollIntoView({ behavior: "smooth" })
  }, [messages.length])

  // Auto mark unread visible messages as read
  useEffect(() => {
    if (!onMarkRead) return
    messages
      .filter(m => m.is_read === false)
      .forEach(m => onMarkRead(m.id))
  }, [messages, onMarkRead])

  // Typing signal
  function handleBodyChange(v: string) {
    setBody(v)
    if (onTyping) {
      onTyping()
      if (typingTimerRef.current) clearTimeout(typingTimerRef.current)
      typingTimerRef.current = setTimeout(() => {
        onStopTyping?.()
      }, 4000)
    }
  }

  // Mic recorder
  const mic = useMicRecorder((blob, name) => {
    const file = new File([blob], name, { type: blob.type })
    setPendingFiles(prev => [...prev, file])
  })

  function validateFiles(files: File[]): string | null {
    let total = 0
    for (const f of files) {
      const ext = "." + (f.name.split(".").pop() ?? "").toLowerCase()
      if (!ALLOWED_EXT.has(ext)) return `Type non autorisé : ${f.name}`
      if (f.size > MAX_FILE_MB * 1024 * 1024) return `Fichier trop grand : ${f.name}`
      total += f.size
      if (total > MAX_TOTAL_MB * 1024 * 1024) return `Total trop lourd (max ${MAX_TOTAL_MB} MB)`
    }
    return null
  }

  function onFileChange(e: React.ChangeEvent<HTMLInputElement>) {
    const files = Array.from(e.target.files ?? [])
    if (!files.length) return
    const err = validateFiles(files)
    if (err) { alert(err); return }
    setPendingFiles(prev => [...prev, ...files])
    e.target.value = ""
  }

  function removeFile(i: number) {
    setPendingFiles(prev => prev.filter((_, j) => j !== i))
  }

  async function submit() {
    const text = body.trim()
    if (!text && pendingFiles.length === 0) return
    const filesToSend = [...pendingFiles]
    setBody("")
    setPendingFiles([])
    onStopTyping?.()
    if (typingTimerRef.current) clearTimeout(typingTimerRef.current)
    await onSend({ body: text || "📎", files: filesToSend })
  }

  async function handleEdit() {
    if (!editingMsg || !onEdit) return
    const text = editBody.trim()
    if (!text) return
    setEditBusy(true)
    await onEdit(editingMsg, text)
    setEditBusy(false)
    setEditingMsg(null)
    setEditBody("")
  }

  async function handleDelete(msg: Msg) {
    if (!onDelete) return
    if (!confirm(L.confirmDelete)) return
    await onDelete(msg)
  }

  // Déduplication par ID + tri chronologique
  const sorted = [...messages]
    .filter((m, i, arr) => arr.findIndex(x => x.id === m.id) === i)
    .sort((a, b) => a.id - b.id)

  return (
    <div className="flex flex-col h-full min-h-0 bg-white rounded-2xl border border-slate-200 shadow-sm overflow-hidden">

      {/* Messages list */}
      <div
        className="flex-1 overflow-y-auto px-4 py-4 space-y-4 scroll-smooth"
        onScroll={(e) => {
          const el = e.currentTarget
          setShowScrollBtn(el.scrollHeight - el.scrollTop - el.clientHeight > 120)
        }}
      >
        {loading && (
          <div className="flex items-center justify-center py-10 text-slate-400">
            <Loader2 className="h-5 w-5 animate-spin mr-2" />
            {L.loading}
          </div>
        )}

        {!loading && sorted.length === 0 && (
          <div className="flex flex-col items-center justify-center py-16 text-slate-400 text-sm">
            <div className="h-12 w-12 rounded-2xl bg-slate-100 flex items-center justify-center mb-3">
              <Send className="h-5 w-5 opacity-40" />
            </div>
            <p>{L.noMessages}</p>
          </div>
        )}

        {sorted.map(msg => (
          <Bubble
            key={msg.id}
            msg={msg}
            isMe={!!myUserId && msg.author?.id === myUserId}
            accent={accentColor}
            myBubble={myBubble}
            otherBubble={otherBubbleColor}
            onEdit={onEdit ? (m) => { setEditingMsg(m); setEditBody(m.body) } : undefined}
            onDelete={onDelete ? handleDelete : undefined}
            agentBadge={L.agentBadge}
            internalBadge={L.internalBadge}
          />
        ))}

        {/* Typing indicator */}
        {typingLabels.length > 0 && (
          <div className="flex items-center gap-2 px-2 text-xs text-slate-400 italic">
            <span className="inline-flex gap-0.5">
              {[0,1,2].map(i => (
                <span key={i} className="h-1.5 w-1.5 rounded-full bg-slate-400 animate-bounce"
                  style={{ animationDelay: `${i * 0.15}s` }} />
              ))}
            </span>
            {typingLabels.join(", ")} {typingLabels.length === 1 ? L.typingOne : L.typingMany}
          </div>
        )}

        <div ref={bottomRef} />
      </div>

      {/* Scroll-to-bottom button */}
      {showScrollBtn && (
        <div className="relative">
          <button
            onClick={() => bottomRef.current?.scrollIntoView({ behavior: "smooth" })}
            className="absolute bottom-2 right-4 z-10 rounded-full border bg-white shadow-md p-1.5 hover:bg-slate-50 transition"
          >
            <ChevronDown className="h-4 w-4 text-slate-500" />
          </button>
        </div>
      )}

      {/* Incoming call banner (appel initié par l'autre côté) */}
      {activeCall && activeCall.status === "active" && !callOpen && activeCall.id !== ignoredCallId && (
        <IncomingCallBanner
          call={activeCall}
          onJoin={() => { setCallOpen(true); onJoinCall?.() }}
          onDecline={() => setIgnoredCallId(activeCall.id)}
        />
      )}

      {/* Error */}
      {error && (
        <div className="mx-4 mb-2 flex items-center gap-2 rounded-xl border border-red-100 bg-red-50 px-3 py-2 text-xs text-red-700">
          <AlertCircle className="h-3.5 w-3.5 shrink-0" /> {error}
        </div>
      )}

      {/* Pending files */}
      {pendingFiles.length > 0 && (
        <div className="mx-4 mb-1 flex flex-wrap gap-2">
          {pendingFiles.map((f, i) => (
            <div key={i} className="flex items-center gap-1.5 rounded-xl border bg-slate-50 px-2.5 py-1.5 text-xs text-slate-600">
              {f.type.startsWith("audio/") ? <FileAudio2 className="h-3.5 w-3.5" /> : fileIcon({ id: 0, filename: f.name, content_type: f.type, file: null })}
              <span className="max-w-[120px] truncate">{f.name}</span>
              <span className="text-slate-400">{bytesHuman(f.size)}</span>
              <button onClick={() => removeFile(i)} className="hover:text-red-500 transition">
                <X className="h-3 w-3" />
              </button>
            </div>
          ))}
        </div>
      )}

      {/* Mic recording bar */}
      {mic.recording && (
        <div className="mx-4 mb-1 flex items-center gap-3 rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700">
          <span className="inline-flex h-2 w-2 rounded-full bg-red-500 animate-pulse" />
          <span className="flex-1 font-medium">{L.recording} {mic.seconds}s</span>
          <button onClick={mic.cancel} className="text-slate-500 hover:text-red-600 transition" title={L.cancel}>
            <X className="h-4 w-4" />
          </button>
          <button onClick={mic.stop} className="rounded-xl bg-red-600 text-white px-3 py-1 text-xs font-semibold hover:bg-red-700 transition">
            <StopCircle className="h-4 w-4 inline mr-1" />{L.stopRecording}
          </button>
        </div>
      )}

      {/* Edit bar */}
      {editingMsg && (
        <div className="mx-4 mb-1 flex items-center gap-2 rounded-xl border border-amber-200 bg-amber-50 px-3 py-1.5 text-xs text-amber-700">
          <Pencil className="h-3.5 w-3.5 shrink-0" />
          <span className="flex-1">{L.editingLabel}</span>
          <button onClick={() => { setEditingMsg(null); setEditBody("") }} className="hover:text-red-500 transition">
            <X className="h-3.5 w-3.5" />
          </button>
        </div>
      )}

      {/* Composer */}
      <div className="px-4 pb-4 pt-2 border-t border-slate-100">
        {editingMsg ? (
          <div className="flex gap-2">
            <textarea
              className="flex-1 resize-none rounded-2xl border border-slate-200 bg-slate-50 px-4 py-2.5 text-sm outline-none focus:border-teal-400 focus:ring-2 focus:ring-teal-400/20 transition"
              rows={2}
              value={editBody}
              onChange={e => setEditBody(e.target.value)}
              onKeyDown={e => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); handleEdit() } }}
            />
            <div className="flex flex-col gap-1.5">
              <button onClick={handleEdit} disabled={editBusy || !editBody.trim()}
                className="rounded-xl px-3 py-2 text-xs font-semibold text-white disabled:opacity-50 transition"
                style={{ background: accentColor }}>
                {editBusy ? <Loader2 className="h-4 w-4 animate-spin" /> : L.save}
              </button>
              <button onClick={() => { setEditingMsg(null); setEditBody("") }}
                className="rounded-xl px-3 py-2 text-xs text-slate-500 border border-slate-200 hover:bg-slate-50 transition">
                {L.cancel}
              </button>
            </div>
          </div>
        ) : (
          <div className="flex items-end gap-2">
            <div className="flex-1 flex items-end rounded-2xl border border-slate-200 bg-slate-50 focus-within:border-teal-400 focus-within:ring-2 focus-within:ring-teal-400/20 transition overflow-hidden px-3 py-2 gap-2">
              <textarea
                className="flex-1 resize-none bg-transparent text-sm outline-none max-h-36 min-h-[38px] leading-relaxed"
                placeholder={placeholder}
                rows={1}
                value={body}
                onChange={e => { handleBodyChange(e.target.value); e.target.style.height = "auto"; e.target.style.height = e.target.scrollHeight + "px" }}
                onKeyDown={e => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); submit() } }}
              />
              {/* Attach */}
              <button type="button" onClick={() => fileInputRef.current?.click()}
                className="shrink-0 rounded-lg p-1.5 hover:bg-slate-200 text-slate-400 transition" title={L.attachFile}>
                <Paperclip className="h-4 w-4" />
              </button>
              {/* Mic */}
              {!mic.recording ? (
                <button type="button" onClick={mic.start}
                  className="shrink-0 rounded-lg p-1.5 hover:bg-slate-200 text-slate-400 transition" title={L.voiceMsg}>
                  <Mic className="h-4 w-4" />
                </button>
              ) : (
                <button type="button" onClick={mic.stop}
                  className="shrink-0 rounded-lg p-1.5 bg-red-100 text-red-600 transition animate-pulse" title={L.stopRecord}>
                  <MicOff className="h-4 w-4" />
                </button>
              )}
            </div>

            {/* Send */}
            <button
              onClick={submit}
              disabled={sending || (!body.trim() && pendingFiles.length === 0)}
              className="shrink-0 h-10 w-10 rounded-2xl flex items-center justify-center text-white shadow-sm disabled:opacity-50 hover:opacity-90 transition"
              style={{ background: accentColor }}
              title={sendLabel}
            >
              {sending ? <Loader2 className="h-4 w-4 animate-spin" /> : <Send className="h-4 w-4" />}
            </button>

            {/* Call buttons */}
            {onStartCall && (
              <>
                <button
                  onClick={() => { onStartCall("audio"); setCallOpen(true) }}
                  className="shrink-0 h-10 w-10 rounded-2xl flex items-center justify-center border border-slate-200 bg-white text-slate-500 hover:bg-slate-50 hover:text-teal-600 shadow-sm transition"
                  title={L.callAudio}
                >
                  <Phone className="h-4 w-4" />
                </button>
                <button
                  onClick={() => { onStartCall("video"); setCallOpen(true) }}
                  className="shrink-0 h-10 w-10 rounded-2xl flex items-center justify-center border border-slate-200 bg-white text-slate-500 hover:bg-slate-50 hover:text-teal-600 shadow-sm transition"
                  title={L.callVideo}
                >
                  <Video className="h-4 w-4" />
                </button>
              </>
            )}

            {/* Active call indicator (rejoindre si pas encore ouvert) */}
            {activeCall && activeCall.status === "active" && !callOpen && (
              <button
                onClick={() => { setCallOpen(true); onJoinCall?.() }}
                className="shrink-0 h-10 px-3 rounded-2xl flex items-center gap-1.5 border border-teal-200 bg-teal-50 text-teal-700 text-xs font-semibold hover:bg-teal-100 shadow-sm transition animate-pulse"
              >
                <Phone className="h-3.5 w-3.5" />
                {L.joinCall}
              </button>
            )}
          </div>
        )}

        <input ref={fileInputRef} type="file" multiple hidden
          accept=".pdf,.png,.jpg,.jpeg,.webp,.gif,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.csv,.mp3,.wav,.ogg,.m4a,.webm,.mp4,.mov"
          onChange={onFileChange}
        />
      </div>

      {/* WebRTC call modal */}
      {callOpen && activeCall && activeCall.status === "active" && (
        <CallModal
          call={activeCall}
          mySide={mySide}
          displayName={myCallDisplayName}
          onEnd={() => {
            setCallOpen(false)
            onEndCall?.()
          }}
        />
      )}
    </div>
  )
}
