/**
 * ConversationLog.jsx — Real-time transcript with speaker labels.
 *
 * Subscribes:
 *   /social/speech/transcript      (SpeechTranscript) — human utterances
 *   /social/conversation/response  (ConversationResponse) — bot replies
 */

import { useEffect, useRef, useState } from 'react';

const MAX_ENTRIES = 200;

function formatTime(ts) {
  return new Date(ts).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
}

function HumanBubble({ entry }) {
  return (
    <div className="flex flex-col items-end gap-0.5">
      <div className="flex items-center gap-2 text-xs text-gray-500">
        <span className="text-xs">{formatTime(entry.ts)}</span>
        <span className="text-blue-400 font-bold">{entry.speaker || 'unknown'}</span>
        {entry.confidence != null && (
          <span className="text-gray-600">({Math.round(entry.confidence * 100)}%)</span>
        )}
        {entry.partial && <span className="text-amber-600 text-xs italic">partial</span>}
      </div>
      <div className={`max-w-xs sm:max-w-md bubble-human rounded-lg px-3 py-2 text-sm text-blue-100 ${entry.partial ? 'bubble-partial' : ''}`}>
        {entry.text}
      </div>
    </div>
  );
}

function BotBubble({ entry }) {
  return (
    <div className="flex flex-col items-start gap-0.5">
      <div className="flex items-center gap-2 text-xs text-gray-500">
        <span className="text-teal-400 font-bold">Salty</span>
        {entry.speaker && <span className="text-gray-600">→ {entry.speaker}</span>}
        <span className="text-xs">{formatTime(entry.ts)}</span>
        {entry.partial && <span className="text-amber-600 text-xs italic">streaming…</span>}
      </div>
      <div className={`max-w-xs sm:max-w-md bubble-bot rounded-lg px-3 py-2 text-sm text-teal-100 ${entry.partial ? 'bubble-partial' : ''}`}>
        {entry.text}
      </div>
    </div>
  );
}

export function ConversationLog({ subscribe }) {
  const [entries, setEntries] = useState([]);
  const [autoScroll, setAutoScroll] = useState(true);
  const bottomRef = useRef(null);
  const scrollRef = useRef(null);

  // Auto-scroll to bottom when new entries arrive
  useEffect(() => {
    if (autoScroll && bottomRef.current) {
      bottomRef.current.scrollIntoView({ behavior: 'smooth' });
    }
  }, [entries, autoScroll]);

  // Human transcript
  useEffect(() => {
    const unsub = subscribe(
      '/social/speech/transcript',
      'saltybot_social_msgs/SpeechTranscript',
      (msg) => {
        setEntries((prev) => {
          const entry = {
            id: `h-${msg.header?.stamp?.sec ?? Date.now()}-${msg.turn_id ?? Math.random()}`,
            type: 'human',
            text: msg.text,
            speaker: msg.speaker_id,
            confidence: msg.confidence,
            partial: msg.is_partial,
            ts: Date.now(),
          };

          // Replace partial entry with same turn if exists
          if (msg.is_partial) {
            const idx = prev.findLastIndex(
              (e) => e.type === 'human' && e.partial && e.speaker === msg.speaker_id
            );
            if (idx !== -1) {
              const updated = [...prev];
              updated[idx] = entry;
              return updated;
            }
          } else {
            // Replace any trailing partial for same speaker
            const idx = prev.findLastIndex(
              (e) => e.type === 'human' && e.partial && e.speaker === msg.speaker_id
            );
            if (idx !== -1) {
              const updated = [...prev];
              updated[idx] = { ...entry, id: prev[idx].id };
              return updated.slice(-MAX_ENTRIES);
            }
          }

          return [...prev, entry].slice(-MAX_ENTRIES);
        });
      }
    );
    return unsub;
  }, [subscribe]);

  // Bot response
  useEffect(() => {
    const unsub = subscribe(
      '/social/conversation/response',
      'saltybot_social_msgs/ConversationResponse',
      (msg) => {
        setEntries((prev) => {
          const entry = {
            id: `b-${msg.turn_id ?? Math.random()}`,
            type: 'bot',
            text: msg.text,
            speaker: msg.speaker_id,
            partial: msg.is_partial,
            turnId: msg.turn_id,
            ts: Date.now(),
          };

          // Replace streaming partial with same turn_id
          if (msg.turn_id != null) {
            const idx = prev.findLastIndex(
              (e) => e.type === 'bot' && e.turnId === msg.turn_id
            );
            if (idx !== -1) {
              const updated = [...prev];
              updated[idx] = entry;
              return updated;
            }
          }

          return [...prev, entry].slice(-MAX_ENTRIES);
        });
      }
    );
    return unsub;
  }, [subscribe]);

  const handleScroll = () => {
    const el = scrollRef.current;
    if (!el) return;
    const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 60;
    setAutoScroll(atBottom);
  };

  const handleClear = () => setEntries([]);

  return (
    <div className="flex flex-col h-full" style={{ minHeight: '400px', maxHeight: '70vh' }}>
      {/* Toolbar */}
      <div className="flex items-center justify-between mb-2 shrink-0">
        <div className="text-cyan-700 text-xs font-bold tracking-widest">
          CONVERSATION LOG ({entries.length})
        </div>
        <div className="flex items-center gap-2">
          <label className="flex items-center gap-1 cursor-pointer">
            <input
              type="checkbox"
              checked={autoScroll}
              onChange={(e) => setAutoScroll(e.target.checked)}
              className="accent-cyan-500 w-3 h-3"
            />
            <span className="text-gray-500 text-xs">Auto-scroll</span>
          </label>
          <button
            onClick={handleClear}
            className="px-2 py-0.5 rounded border border-gray-700 text-gray-500 hover:text-gray-300 text-xs"
          >
            Clear
          </button>
        </div>
      </div>

      {/* Scroll container */}
      <div
        ref={scrollRef}
        onScroll={handleScroll}
        className="flex-1 overflow-y-auto space-y-3 pr-1"
        style={{ minHeight: '300px' }}
      >
        {entries.length === 0 ? (
          <div className="text-gray-600 text-sm text-center py-12 border border-dashed border-gray-800 rounded-lg">
            Waiting for conversation…
          </div>
        ) : (
          entries.map((entry) =>
            entry.type === 'human' ? (
              <HumanBubble key={entry.id} entry={entry} />
            ) : (
              <BotBubble key={entry.id} entry={entry} />
            )
          )
        )}
        <div ref={bottomRef} />
      </div>

      {/* Legend */}
      <div className="flex gap-4 mt-2 pt-2 border-t border-gray-900 shrink-0">
        <div className="flex items-center gap-1.5">
          <div className="w-3 h-3 rounded-sm bg-blue-950 border border-blue-700" />
          <span className="text-gray-600 text-xs">Human</span>
        </div>
        <div className="flex items-center gap-1.5">
          <div className="w-3 h-3 rounded-sm bg-teal-950 border border-teal-700" />
          <span className="text-gray-600 text-xs">Salty</span>
        </div>
        <div className="flex items-center gap-1.5">
          <div className="w-2 h-2 rounded-full bg-amber-600 opacity-60" />
          <span className="text-gray-600 text-xs">Streaming</span>
        </div>
      </div>
    </div>
  );
}
