// Conversation — the Messages right-pane showing one chat + composer.
//
// Responsibilities:
//   * Render header with contact identity + close button.
//   * Auto-scroll the message list to the bottom on new arrival.
//   * Composer with Enter-to-send, Shift+Enter for newline.
//   * Fan out every outgoing message across the recipient's device
//     registry (falls back to legacy single-X25519 for pre-v2.2.0
//     peers). One envelope per device; Promise.all, any failure
//     rejects the batch so the user sees it.

import React, { useEffect, useRef, useState } from 'react';
import { useStore } from '@/lib/store';
import { encryptMessage, shortAddr } from '@/lib/crypto';
import { sendEnvelope, resolveRecipientKeys } from '@/lib/relay';
import { appendMessage as persist } from '@/lib/storage';
import type { Message } from '@/lib/types';

export function Conversation({ address }: { address: string }): React.ReactElement {
  const keyFile  = useStore(s => s.keyFile);
  const contact  = useStore(s => s.contacts.find(c => c.address === address));
  const messages = useStore(s => s.messages[address] ?? []);
  const clearUnread = useStore(s => s.clearUnread);
  const appendMsg   = useStore(s => s.appendMessage);

  const [text,    setText]    = useState('');
  const [sending, setSending] = useState(false);
  const [error,   setError]   = useState<string | null>(null);

  const scrollRef = useRef<HTMLDivElement>(null);

  // Seeing a conversation drops its unread count.
  useEffect(() => { clearUnread(address); }, [address, clearUnread]);

  // Pin the scroll to the bottom on new messages. Only if the user
  // is already near the bottom — don't yank them back if they're
  // scrolling through older history.
  useEffect(() => {
    const el = scrollRef.current;
    if (!el) return;
    const nearBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 120;
    if (nearBottom) el.scrollTop = el.scrollHeight;
  }, [messages.length]);

  const isSelf = !!keyFile && keyFile.pub_key === address;

  const send = async () => {
    if (!keyFile || sending) return;
    const body = text.trim();
    if (!body) return;

    setSending(true); setError(null);
    try {
      // Saved Messages path — the conversation address equals our own
      // master pub. Mobile parity: append locally, skip the relay
      // round-trip entirely (no fees, no ciphertext ever leaves).
      if (!isSelf) {
        const pubs = await resolveRecipientKeys(address);
        if (pubs.length === 0) {
          throw new Error('recipient has no encryption key published');
        }
        await Promise.all(pubs.map(async (rpub) => {
          const { nonce, ciphertext } = encryptMessage(
            body, keyFile.x25519_priv, rpub,
          );
          await sendEnvelope({
            senderPub:    keyFile.x25519_pub,
            recipientPub: rpub,
            senderEd25519Pub: keyFile.pub_key,
            nonce, ciphertext,
          });
        }));
      }

      const m: Message = {
        id:        `out-${Date.now()}${Math.floor(Math.random() * 1e6)}`,
        from:      keyFile.x25519_pub,
        text:      body,
        timestamp: Math.floor(Date.now() / 1000),
        mine:      true,
        read:      false,
        edited:    false,
      };
      appendMsg(address, m);
      persist(address, m);
      setText('');
    } catch (e) {
      setError(e instanceof Error ? e.message : String(e));
    } finally {
      setSending(false);
    }
  };

  const onKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
    if (e.key === 'Enter' && !e.shiftKey) {
      e.preventDefault();
      send();
    }
  };

  const name = contact?.username ? `@${contact.username}`
    : contact?.alias
      ? contact.alias
      : isSelf
        ? 'Saved Messages'
        : shortAddr(address, 8);

  return (
    <div style={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
      {/* Header */}
      <div style={{
        padding: '12px 16px', borderBottom: '1px solid #1f1f1f',
        display: 'flex', alignItems: 'center', gap: 10,
      }}>
        <div style={{
          width: 32, height: 32, borderRadius: 16,
          background: isSelf ? '#1d9bf0' : '#1a1a1a',
          color: '#fff', fontWeight: 700, fontSize: 14,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}>
          {isSelf ? '★' : name.replace(/^@/, '').charAt(0).toUpperCase()}
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ color: '#fff', fontSize: 14, fontWeight: 700 }}>{name}</div>
          <div style={{ color: '#6a6a6a', fontSize: 11, fontFamily: 'monospace' }}>
            {shortAddr(address, 6)}
          </div>
        </div>
      </div>

      {/* Messages */}
      <div
        ref={scrollRef}
        style={{ flex: 1, overflowY: 'auto', padding: '14px 16px' }}
      >
        {messages.length === 0 ? (
          <div style={{
            color: '#6a6a6a', fontSize: 13, textAlign: 'center',
            marginTop: 40,
          }}>
            {isSelf
              ? 'Notes to self. Messages here stay on this device only.'
              : 'No messages yet. Type below to send the first one.'}
          </div>
        ) : (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            {messages.map(m => <Bubble key={m.id} message={m} />)}
          </div>
        )}
      </div>

      {/* Composer */}
      <div style={{
        borderTop: '1px solid #1f1f1f', padding: 12,
        display: 'flex', gap: 10, alignItems: 'flex-end',
      }}>
        <textarea
          value={text}
          onChange={e => setText(e.target.value)}
          onKeyDown={onKeyDown}
          placeholder="Message…"
          rows={1}
          style={{
            flex: 1, resize: 'none',
            background: '#0a0a0a', border: '1px solid #1f1f1f',
            borderRadius: 10, padding: '10px 12px',
            color: '#fff', fontSize: 13, fontFamily: 'inherit',
            outline: 'none', lineHeight: 1.4, maxHeight: 140,
          }}
        />
        <button
          onClick={send}
          disabled={sending || text.trim().length === 0}
          style={{
            padding: '10px 16px', borderRadius: 999, border: 'none',
            background: '#1d9bf0', color: '#fff', fontSize: 13, fontWeight: 700,
            cursor: sending || text.trim().length === 0 ? 'default' : 'pointer',
            opacity: sending || text.trim().length === 0 ? 0.5 : 1,
          }}
        >
          {sending ? '…' : 'Send'}
        </button>
      </div>
      {error && (
        <div style={{
          padding: '6px 16px 10px', fontSize: 11, color: '#ff6b6b',
        }}>
          {error}
        </div>
      )}
    </div>
  );
}

function Bubble({ message }: { message: Message }) {
  const mine = message.mine;
  return (
    <div style={{
      display: 'flex', justifyContent: mine ? 'flex-end' : 'flex-start',
    }}>
      <div className="selectable" style={{
        maxWidth: '70%',
        padding: '8px 12px', borderRadius: 14,
        background: mine ? '#1d9bf0' : '#1a1a1a',
        color: mine ? '#fff' : '#e0e0e0',
        fontSize: 13, lineHeight: 1.45,
        whiteSpace: 'pre-wrap', wordBreak: 'break-word',
      }}>
        {message.text}
      </div>
    </div>
  );
}
