// src/features/messages/ui/composer.jsx
//
// Bottom composer: text input + paperclip + send. Drag-drop onto the whole
// composer area adds files. Pending files shown as pills above the text input
// with a remove × each.

const ACCEPT_MIME = [
  'image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/heic',
  'application/pdf',
];
const ACCEPT_ATTR = ACCEPT_MIME.join(',');
const MAX_BYTES   = 10 * 1024 * 1024;

const Composer = ({ conversationId, onSent, disabled }) => {
  const [body,    setBody]    = React.useState('');
  const [files,   setFiles]   = React.useState([]);
  const [busy,    setBusy]    = React.useState(false);
  const [err,     setErr]     = React.useState('');
  const [dragOn,  setDragOn]  = React.useState(false);
  const [focused, setFocused] = React.useState(false);
  // visualViewport offset so the iOS / Android on-screen keyboard doesn't
  // cover the composer. When the keyboard opens, visualViewport.height shrinks
  // by the keyboard height — we push the sticky composer up by the same
  // amount. Defaults to 0 on desktop, where visualViewport isn't relevant.
  const [kbOffset, setKbOffset] = React.useState(0);
  const fileInputRef = React.useRef(null);
  const textRef      = React.useRef(null);

  React.useEffect(() => { setBody(''); setFiles([]); setErr(''); }, [conversationId]);

  React.useEffect(() => {
    const vv = window.visualViewport;
    if (!vv) return;
    const update = () => {
      // Difference between the layout viewport (window.innerHeight) and the
      // visual viewport — i.e. the portion currently covered by the keyboard.
      const cover = Math.max(0, window.innerHeight - vv.height - vv.offsetTop);
      setKbOffset(cover);
    };
    update();
    vv.addEventListener('resize', update);
    vv.addEventListener('scroll', update);
    return () => {
      vv.removeEventListener('resize', update);
      vv.removeEventListener('scroll', update);
    };
  }, []);

  const addFiles = (incoming) => {
    setErr('');
    const arr = Array.from(incoming || []);
    const bad = arr.find(f => f.size > MAX_BYTES);
    if (bad) { setErr(`"${bad.name}" is larger than 10 MB.`); return; }
    const wrongMime = arr.find(f => f.type && !ACCEPT_MIME.includes(f.type));
    if (wrongMime) { setErr(`"${wrongMime.name}" type not allowed.`); return; }
    setFiles(prev => [...prev, ...arr]);
  };

  const removeFile = (idx) => setFiles(prev => prev.filter((_, i) => i !== idx));

  const send = async () => {
    if (busy) return;
    setErr('');
    const safeBody = body.trim();
    if (!safeBody && files.length === 0) return;
    setBusy(true);
    try {
      await window.Messages.db.sendMessage({ conversationId, body: safeBody, files });
      setBody(''); setFiles([]);
      if (onSent) onSent();
      if (textRef.current) textRef.current.focus();
    } catch (e) {
      setErr(e.message || String(e));
    } finally {
      setBusy(false);
    }
  };

  const onKeyDown = (e) => {
    // Enter sends, Shift+Enter inserts newline. Cmd/Ctrl+Enter also sends.
    if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); }
  };

  const onDrop = (e) => {
    e.preventDefault(); setDragOn(false);
    if (e.dataTransfer?.files?.length) addFiles(e.dataTransfer.files);
  };

  const canSend = !disabled && !busy && (body.trim().length > 0 || files.length > 0);

  return (
    <div
      onDragOver={e => { e.preventDefault(); setDragOn(true); }}
      onDragLeave={() => setDragOn(false)}
      onDrop={onDrop}
      style={{
        borderTop:'1px solid oklch(92% 0.01 265)',
        boxShadow:'0 -10px 24px -20px rgba(20,22,40,0.25)',
        background: dragOn ? 'oklch(96% 0.04 265)' : '#fff',
        padding:'10px 14px 14px',
        fontFamily:"'Plus Jakarta Sans', sans-serif",
        position:'sticky', bottom: kbOffset,
        transition: 'bottom 120ms ease-out',
      }}
    >
      {files.length > 0 && (
        <div style={{ display:'flex', flexWrap:'wrap', gap:6, marginBottom:8 }}>
          {files.map((f, i) => (
            <span key={i} style={{
              display:'inline-flex', alignItems:'center', gap:6,
              padding:'4px 8px 4px 10px', background:'oklch(96% 0.005 60)',
              border:'1px solid oklch(90% 0.01 265)', borderRadius:14,
              fontSize:11, color:'oklch(34% 0.04 265)', maxWidth:240,
            }}>
              <span style={{ overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{f.name}</span>
              <button onClick={() => removeFile(i)} disabled={busy}
                style={{ background:'none', border:'none', cursor:busy?'wait':'pointer',
                         color:'oklch(48% 0.04 265)', fontSize:14, padding:0, lineHeight:1 }}
                aria-label={`Remove ${f.name}`}
              >×</button>
            </span>
          ))}
        </div>
      )}

      {err && (
        <div style={{ fontSize:11, color:'oklch(40% 0.15 25)', marginBottom:6 }}>{err}</div>
      )}

      <div style={{ display:'flex', alignItems:'flex-end', gap:8 }}>
        <button onClick={() => fileInputRef.current?.click()} disabled={disabled || busy}
          title="Attach file (image or PDF, 10 MB max)"
          style={{ width:40, height:40, borderRadius:'50%',
                   background:'oklch(96% 0.005 60)', border:'1px solid oklch(90% 0.01 265)',
                   cursor:(disabled||busy)?'not-allowed':'pointer',
                   color:'oklch(40% 0.04 265)', fontSize:18, flexShrink:0 }}
          aria-label="Attach file"
        >+</button>
        <input ref={fileInputRef} type="file" accept={ACCEPT_ATTR} multiple
          style={{ display:'none' }}
          onChange={e => { addFiles(e.target.files); e.target.value = ''; }} />
        <textarea
          ref={textRef}
          value={body}
          onChange={e => setBody(e.target.value)}
          onKeyDown={onKeyDown}
          onFocus={() => setFocused(true)}
          onBlur={() => setFocused(false)}
          disabled={disabled || busy}
          placeholder="Type a message…"
          rows={1}
          style={{ flex:1, resize:'none', padding:'10px 14px',
                   border:`1.5px solid ${focused ? 'oklch(58% 0.13 265)' : 'oklch(90% 0.015 265)'}`,
                   borderRadius:20,
                   fontSize:14, fontFamily:"'Plus Jakarta Sans', sans-serif",
                   color:'oklch(22% 0.06 265)',
                   background: focused ? '#fff' : 'oklch(98% 0.006 265)', outline:'none',
                   boxShadow: focused ? '0 0 0 3px oklch(58% 0.13 265 / 0.16)' : 'none',
                   transition:'border-color 140ms ease, box-shadow 140ms ease, background 140ms ease',
                   minHeight:40, maxHeight:120, overflowY:'auto', boxSizing:'border-box' }}
        />
        <button onClick={send} disabled={!canSend}
          style={{ background:canSend ? 'oklch(22% 0.06 265)' : 'oklch(88% 0.012 265)',
                   color: canSend ? '#fff' : 'oklch(60% 0.02 265)', border:'none', borderRadius:20,
                   padding:'10px 20px', fontWeight:600, fontSize:13,
                   cursor:canSend?'pointer':'not-allowed', flexShrink:0,
                   boxShadow: canSend ? '0 6px 16px -8px oklch(22% 0.06 265 / 0.7)' : 'none',
                   transition:'background 140ms ease, box-shadow 140ms ease, color 140ms ease',
                   fontFamily:"'Plus Jakarta Sans', sans-serif" }}
        >{busy ? 'Sending…' : 'Send'}</button>
      </div>
    </div>
  );
};

window.Messages.ui.Composer = Composer;
window.Composer             = Composer;
