import { useEffect, useState, useRef } from 'react';
import { LocalDB, Group, TranscriptionSegment } from '../lib/localdb';
import { translateText, apiHealth, preloadModel, sttStatus, transcribeAudio } from '../lib/api';
import { useAuth } from '../contexts/useAuth';
import { useNavigate } from './NavigationHooks';
import { Mic, MicOff, StopCircle, Copy, Check, QrCode, Users, Trash2, Download } from 'lucide-react';
import { QRCodeDisplay } from './QRCodeDisplay';

interface HostViewProps {
  groupId: string;
}

export function HostView({ groupId }: HostViewProps) {
  // ...existing code...
  // Subscribe to group updates so HostView always reflects latest source/target language
  useEffect(() => {
    const unsubGroup = LocalDB.onGroupUpdated(groupId, (updated) => {
      setGroup(updated);
    });
    return () => unsubGroup();
  }, [groupId]);
  // ...existing code...
  // Show only originals toggle
  const [showOriginalsOnly, setShowOriginalsOnly] = useState(false);
  // Malay-English model test state
  const [msEnAvailable, setMsEnAvailable] = useState<null | boolean>(null);
  const [msEnChecking, setMsEnChecking] = useState(false);
  // Parallel translation: track IDs currently being translated
  const [translatingIds, setTranslatingIds] = useState<Set<string>>(new Set());
  const { user } = useAuth();
  const navigate = useNavigate();
  const [group, setGroup] = useState<Group | null>(null);
  const [isRecording, setIsRecording] = useState(false);
  // Segments always sorted by sequence number
  const [segments, setSegments] = useState<TranscriptionSegment[]>([]);
  const [memberCount, setMemberCount] = useState(0);
  const [showQR, setShowQR] = useState(false);
  const [copied, setCopied] = useState(false);
  const [interimText, setInterimText] = useState('');
  const [apiOk, setApiOk] = useState<boolean | null>(null);
  // Advanced audio upload support
  const [sttAvailable, setSttAvailable] = useState(false);
  const [sttBusy, setSttBusy] = useState(false);
  // Removed unused diag variable
  const [retryingIds, setRetryingIds] = useState<Set<string>>(new Set());
  const [bulkRetrying, setBulkRetrying] = useState(false);
  // Sentence-level buffering for mic recognition
  const [bufferedText, setBufferedText] = useState('');
  const flushTimerRef = useRef<any>(null);

  const recognitionRef = useRef<any>(null);
  const isRecordingFlagRef = useRef(false);
  const sequenceNumberRef = useRef(0);
  const preloadAttemptedRef = useRef(false);
  const [modelReady, setModelReady] = useState<null | boolean>(null);

  useEffect(() => {
    if (!user) return;

    loadGroup();
    loadSegments();
    loadMemberCount();
    // Preload model for selected target language when group changes
    if (group && apiOk) {
      preloadModel({ source_language: group.source_language, target_language: group.target_language });
    }

    const unsubMembers = LocalDB.onMembersChanged(groupId, () => {
      loadMemberCount();
    });
    // poll API health
    let healthTimer: any;
    (async () => {
      const ok = await apiHealth();
      setApiOk(ok);
      // Check if Whisper STT is available (backend should expose this)
      if (ok) {
        try { setSttAvailable(await sttStatus()); } catch (e) { setSttAvailable(true); }
      }
      // Auto-preload model when API is online and group is known
      if (ok && group && !preloadAttemptedRef.current) {
        preloadAttemptedRef.current = true;
        setModelReady(null);
        const warmed = await autoPreloadForGroup(group);
        setModelReady(warmed);
      }
      healthTimer = setInterval(async () => {
        const healthy = await apiHealth();
        setApiOk(healthy);
        if (healthy) {
          try { setSttAvailable(await sttStatus()); } catch (e) { setSttAvailable(true); }
        } else {
          setSttAvailable(false);
        }
        // Re-attempt preload if API just came online
        if (healthy && group && !preloadAttemptedRef.current) {
          preloadAttemptedRef.current = true;
          setModelReady(null);
          const warmed = await autoPreloadForGroup(group);
          setModelReady(warmed);
        }
      }, 15000);
    })();

    return () => {
      unsubMembers();
      stopRecording();
      if (healthTimer) clearInterval(healthTimer);
    };
  }, [groupId, user]);

  // When group becomes available, kick off auto preload once
  useEffect(() => {
    if (group) {
      if (apiOk && !preloadAttemptedRef.current) {
        preloadAttemptedRef.current = true;
        (async () => {
          setModelReady(null);
          const warmed = await autoPreloadForGroup(group);
          setModelReady(warmed);
        })();
      }
    }
  }, [group?.id, apiOk]);

  const autoPreloadForGroup = async (g: Group): Promise<boolean> => {
  let ok = await preloadModel({ source_language: g.source_language, target_language: g.target_language });
  if (!ok && g.target_language === 'en' && (g.source_language === 'auto' || !g.source_language)) {
    const okMs = await preloadModel({ source_language: 'ms', target_language: 'en' });
    const okId = await preloadModel({ source_language: 'id', target_language: 'en' });
    ok = okMs || okId;
  }
  return ok;
  };

  const loadGroup = async () => {
    const data = LocalDB.getGroupById(groupId);
    if (data) {
      setGroup(data);
    } else {
      navigate('/');
    }
  };

  const loadSegments = async () => {
    const data = LocalDB.getSegments(groupId);
    setSegments(data);
    sequenceNumberRef.current = data.length;
  };

  const loadMemberCount = async () => {
    setMemberCount(LocalDB.getMemberCount(groupId));
  };

  const setRecording = (v: boolean) => {
    setIsRecording(v);
    isRecordingFlagRef.current = v;
  };

  const startRecording = async () => {
    if (!('webkitSpeechRecognition' in window) && !('SpeechRecognition' in window)) {
      alert('Speech recognition is not supported in your browser. Please use Chrome or Edge.');
      return;
    }

    const SpeechRecognition = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition;
    const recognition = new SpeechRecognition();

    recognition.continuous = true;
    recognition.interimResults = true;
  const srcLang = (group?.source_language === 'auto' ? 'en' : group?.source_language || 'en').toLowerCase();
  recognition.lang = srcLang === 'auto' ? 'en-US'
            : srcLang === 'ur' ? 'ur-PK'
            : srcLang === 'ar' ? 'ar-SA'
            : srcLang === 'es' ? 'es-ES'
            : srcLang === 'fr' ? 'fr-FR'
            : srcLang === 'de' ? 'de-DE'
            : srcLang === 'hi' ? 'hi-IN'
            : srcLang === 'zh' ? 'zh-CN'
            : srcLang === 'ms' ? 'ms-MY'
            : srcLang === 'id' ? 'id-ID'
            : 'en-US';

    recognition.onresult = async (event: any) => {
      let interim = '';
      let finalChunk = '';

      for (let i = event.resultIndex; i < event.results.length; i++) {
        const transcript = (event.results[i][0].transcript || '').trim();
        if (!transcript) continue;
        if (event.results[i].isFinal) {
          finalChunk += (finalChunk ? ' ' : '') + transcript;
        } else {
          interim += (interim ? ' ' : '') + transcript;
        }
      }

      if (interim) {
        setInterimText(interim);
      } else {
        setInterimText('');
      }

      // Append final chunk to buffer and flush on sentence boundaries or heuristics
      if (finalChunk) {
        const combined = (bufferedText + ' ' + finalChunk).replace(/\s+/g, ' ').trim();
        setBufferedText(combined);

        // Heuristics for when to flush the buffered sentence
  const endsSentence = /[.!?…]\s*$/.test(combined);
        const wordCount = combined.split(/\s+/).filter(Boolean).length;
        const overChars = combined.length >= 180; // max chars per segment
        const minWordsReached = wordCount >= 10; // avoid word-by-word for long speech

        // Clear any previous pending flush; we will schedule a new one below
        if (flushTimerRef.current) {
          clearTimeout(flushTimerRef.current);
          flushTimerRef.current = null;
        }

        const doFlush = async (forced = false) => {
          const txt = combined.trim();
          if (!txt) return;
          // Skip ultra-short fillers unless sentence ended
          const wc = txt.split(/\s+/).filter(Boolean).length;
          // Immediate flush (on punctuation/length) keeps stricter rule; timer-based can be lenient
          if (!forced) {
            if (!endsSentence && wc < 3) return; // allow short 2-3 word utterances only if they feel like a sentence
          } else {
            if (wc < 1) return; // if timer fired and there's at least one word, flush
          }
          setBufferedText('');
          await saveSegment(txt);
        };

        if (endsSentence || overChars || (minWordsReached && !interim)) {
          await doFlush(false);
        } else {
          // Debounce-based flush after short pause
          flushTimerRef.current = setTimeout(async () => {
            await doFlush(true);
          }, 1500);
        }
      }
    };

    recognition.onerror = (event: any) => {
      console.error('Speech recognition error:', event.error);
      if (event.error === 'no-speech') {
        return;
      }
      setRecording(false);
    };

    recognition.onend = () => {
      if (isRecordingFlagRef.current) {
        try {
          recognition.start();
        } catch (e) {
          setTimeout(() => {
            if (isRecordingFlagRef.current) {
              try { recognition.start(); } catch (_e) { /* ignore restart error */ }
            }
          }, 250);
        }
      }
    };

    setRecording(true);
    recognition.start();
    recognitionRef.current = recognition;
  };

  const stopRecording = () => {
    if (recognitionRef.current) {
      setRecording(false);
      recognitionRef.current.stop();
      recognitionRef.current = null;
    }
    setInterimText('');
    setBufferedText('');
    if (flushTimerRef.current) {
      clearTimeout(flushTimerRef.current);
      flushTimerRef.current = null;
    }
  };

  // Save a segment and always add in order
  // Save segment and add to translation queue
  const saveSegment = async (text: string) => {
    if (!user || !group) return;
    // Add segment immediately with translation: null (processing)
    const tempSegment = LocalDB.addSegment({
      groupId,
      originalText: text,
      translatedText: null,
      sequenceNumber: sequenceNumberRef.current,
      createdBy: user.id,
    });
    setSegments((prev: TranscriptionSegment[]) => {
      const exists = prev.some((s: TranscriptionSegment) => s.id === tempSegment.id);
      if (exists) return prev;
      return [...prev, tempSegment].sort((a: TranscriptionSegment, b: TranscriptionSegment) => a.sequence_number - b.sequence_number);
    });
    sequenceNumberRef.current++;
    // Start translation in background for this segment
    setTranslatingIds((prev) => new Set([...prev, tempSegment.id]));
    translateSegment(tempSegment);
  };

  // Translate a segment in the background
  const translateSegment = async (segment: TranscriptionSegment) => {
    if (!group) return;
    let translatedText: string | null = null;
    if (group && group.source_language !== group.target_language) {
      const attempts: string[] = [];
      attempts.push(group.source_language === 'auto' ? 'auto' : group.source_language);
      if (!attempts.includes('ms')) attempts.push('ms');
      if (!attempts.includes('id')) attempts.push('id');
      let foundTranslation: string | null = null;
      for (const src of attempts) {
        const res = await translateText({ text: segment.original_text, source_language: src, target_language: group.target_language });
        const isNoModel = typeof res === 'string' && /^\[No model for/i.test(res);
        const isEcho = !!res && res.trim() === segment.original_text.trim();
        if (res && !isNoModel && !isEcho) {
          foundTranslation = res;
          break;
        }
      }
      if (foundTranslation) {
        translatedText = foundTranslation;
      }
    } else {
      translatedText = segment.original_text;
    }
    setSegments((prev: TranscriptionSegment[]) => prev.map((s: TranscriptionSegment) =>
      s.id === segment.id ? { ...s, translated_text: translatedText } : s
    ).sort((a: TranscriptionSegment, b: TranscriptionSegment) => a.sequence_number - b.sequence_number));
    LocalDB.updateSegmentTranslation(groupId, segment.id, translatedText);
    setTranslatingIds((prev) => {
      const next = new Set(prev);
      next.delete(segment.id);
      return next;
    });
  };

  // Retry translation for a segment
  const retryTranslateOne = async (seg: TranscriptionSegment) => {
    if (!group) return;
    setRetryingIds((prev) => new Set(Array.from(prev).concat(seg.id)));
    setSegments((prev: TranscriptionSegment[]) => prev.map((s: TranscriptionSegment) =>
      s.id === seg.id ? { ...s, translated_text: null } : s
    ));
    setTranslatingIds((prev) => new Set([...prev, seg.id]));
    await translateSegment(seg);
    setRetryingIds((prev) => {
      const next = new Set(prev);
      next.delete(seg.id);
      return next;
    });
  };

  // Translate all segments currently missing a translation
  const retryTranslateMissing = async () => {
    if (!group) return;
    setBulkRetrying(true);
    try {
      const missing = segments.filter((seg) => !seg.translated_text || seg.translated_text === seg.original_text);
      await Promise.all(missing.map(async (seg) => {
        setRetryingIds((prev) => new Set(Array.from(prev).concat(seg.id)));
        setSegments((prev: TranscriptionSegment[]) => prev.map((s: TranscriptionSegment) =>
          s.id === seg.id ? { ...s, translated_text: null } : s
        ));
        setTranslatingIds((prev) => new Set([...prev, seg.id]));
        await translateSegment(seg);
        setRetryingIds((prev) => {
          const next = new Set(prev);
          next.delete(seg.id);
          return next;
        });
      }));
    } finally {
      setBulkRetrying(false);
    }
  };

  const endSession = async () => {
    stopRecording();
    LocalDB.setGroupActive(groupId, false);

    navigate('/');
  };

  // Upload removed

  const deleteSession = async () => {
    stopRecording();
    if (confirm('Delete this session? This will remove all local data for it.')) {
      LocalDB.deleteGroup(groupId);
      navigate('/');
    }
  };

  const copyJoinCode = () => {
    if (group) {
      navigator.clipboard.writeText(group.join_code);
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    }
  };

  // Manual preload removed; handled automatically via autoPreloadForGroup()

  const handleExport = async () => {
    if (!group) return;
    const data = LocalDB.exportGroup(groupId);
    const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
  a.download = `${group.name.replace(/[^a-z0-9-]+/gi, '_') || 'session'}_${group.join_code}.json`;
    document.body.appendChild(a);
    a.click();
    a.remove();
    URL.revokeObjectURL(url);
  };

  if (!group) {
    return (
      <div className="min-h-screen bg-gray-100 flex items-center justify-center">
        <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
      </div>
    );
  }

  const speechSupported = typeof window !== 'undefined' &&
    (("webkitSpeechRecognition" in window) || ("SpeechRecognition" in window));

  return (
    <div className="min-h-screen bg-gradient-to-br from-slate-50 to-blue-50">
      <div className="max-w-4xl mx-auto p-4">
        <div className="bg-white rounded-xl shadow-lg mb-4">
          <div className="p-6 border-b border-gray-200">
            <div className="flex items-center justify-between mb-4">
              <h1 className="text-2xl font-bold text-gray-900">{group.name}</h1>
              <div className="flex items-center space-x-2">
                <div className="flex items-center bg-gray-100 rounded-lg px-3 py-2">
                  <Users className="w-5 h-5 text-gray-600 mr-2" />
                  <span className="font-semibold text-gray-900">{memberCount}</span>
                </div>
                <div className="flex items-center rounded-lg px-3 py-2 border" title={apiOk === null ? 'Checking API' : apiOk ? 'API Online' : 'API Offline'}>
                  <span className={`w-2 h-2 rounded-full mr-2 ${apiOk === null ? 'bg-gray-400 animate-pulse' : apiOk ? 'bg-green-600' : 'bg-red-600'}`}></span>
                  <span className="text-sm text-gray-700">API</span>
                </div>
                {/* Toggle to show only original text */}
                <label className="ml-2 flex items-center text-xs cursor-pointer">
                  <input
                    type="checkbox"
                    checked={showOriginalsOnly}
                    onChange={e => setShowOriginalsOnly(e.target.checked)}
                    className="mr-1"
                  />
                  Show only originals
                </label>
                {/* Malay-English model test button */}
                <button
                  onClick={async () => {
                    setMsEnChecking(true);
                    setMsEnAvailable(null);
                    try {
                      const ok = await preloadModel({ source_language: 'ms', target_language: 'en' });
                      setMsEnAvailable(ok);
                    } finally {
                      setMsEnChecking(false);
                    }
                  }}
                  className="ml-2 px-3 py-2 rounded-lg border text-xs"
                  disabled={msEnChecking}
                  title="Check if Malay-English model is available"
                >
                  {msEnChecking ? 'Checking…' : 'Test Malay→English'}
                </button>
                {msEnAvailable !== null && (
                  <span className={`ml-2 text-xs font-bold ${msEnAvailable ? 'text-green-600' : 'text-red-600'}`}>{msEnAvailable ? 'Available' : 'Not available'}</span>
                )}
              </div>
            </div>

            <div className="flex items-center space-x-3">
              <div className="flex-1 bg-blue-50 rounded-lg p-3 flex items-center justify-between">
                <div>
                  <span className="text-sm text-gray-600">Join Code:</span>
                  <span className="ml-2 text-2xl font-mono font-bold text-blue-600">
                    {group.join_code}
                  </span>
                </div>
                <button
                  onClick={copyJoinCode}
                  className="p-2 hover:bg-blue-100 rounded-lg transition-colors"
                >
                  {copied ? (
                    <Check className="w-5 h-5 text-green-600" />
                  ) : (
                    <Copy className="w-5 h-5 text-blue-600" />
                  )}
                </button>
              </div>

              <button
                onClick={() => setShowQR(true)}
                className="bg-blue-600 text-white p-3 rounded-lg hover:bg-blue-700 transition-colors"
              >
                <QrCode className="w-6 h-6" />
              </button>
            </div>
          </div>

          <div className="p-6">
            <div className="flex items-center justify-center space-x-4 mb-6">
              {!isRecording ? (
                <button
                  onClick={startRecording}
                  disabled={!speechSupported}
                  className="bg-green-600 disabled:bg-gray-400 disabled:cursor-not-allowed text-white px-8 py-4 rounded-full font-semibold hover:bg-green-700 transition-colors flex items-center shadow-lg"
                >
                  <Mic className="w-6 h-6 mr-2" />
                  Start Recording
                </button>
              ) : (
                <button
                  onClick={stopRecording}
                  className="bg-red-600 text-white px-8 py-4 rounded-full font-semibold hover:bg-red-700 transition-colors flex items-center shadow-lg animate-pulse"
                >
                  <MicOff className="w-6 h-6 mr-2" />
                  Stop Recording
                </button>
              )}

              {/* Mic language selector removed for simplicity; we infer from group source */}

              <button
                onClick={endSession}
                className="bg-gray-600 text-white px-6 py-4 rounded-full font-semibold hover:bg-gray-700 transition-colors flex items-center"
              >
                <StopCircle className="w-5 h-5 mr-2" />
                End Session
              </button>
              {/* Preload button removed; model warm-up runs automatically */}
              <button
                onClick={deleteSession}
                className="bg-red-600 text-white px-6 py-4 rounded-full font-semibold hover:bg-red-700 transition-colors flex items-center"
              >
                <Trash2 className="w-5 h-5 mr-2" />
                Delete Session
              </button>
              <button
                onClick={handleExport}
                className="bg-white border px-6 py-4 rounded-full font-semibold hover:bg-gray-50 transition-colors flex items-center"
                title="Export this session as JSON so you can delete safely if storage is full"
              >
                <Download className="w-5 h-5 mr-2" />
                Export JSON
              </button>
            </div>


            {/* Advanced audio upload for Whisper STT */}
            {apiOk && sttAvailable && (
              <div className="mt-4">
                <label className="block text-sm text-gray-600 mb-1">Upload audio (Whisper)</label>
                <div className="flex items-center gap-2">
                  <input
                    type="file"
                    accept="audio/*"
                    onChange={async (e) => {
                      const file = e.target.files?.[0];
                      if (!file) return;
                      setSttBusy(true);
                      try {
                        // Use transcribeAudio from lib/api for Whisper backend
                        const res = await transcribeAudio(file, (group?.source_language || undefined));
                        if (res && res.text && res.text.trim()) {
                          await saveSegment(res.text.trim());
                        }
                      } finally {
                        setSttBusy(false);
                        e.currentTarget.value = '';
                      }
                    }}
                    disabled={sttBusy}
                    className="border rounded-lg px-3 py-2 text-sm"
                  />
                  {sttBusy && <span className="text-xs text-gray-500">Transcribing…</span>}
                </div>
                <div className="text-xs text-gray-500 mt-1">Supported: common audio types; processed server-side via Whisper.</div>
              </div>
            )}
            {apiOk && (
              <div className="mt-2 text-center">
                <span className="text-xs text-gray-500">
                  Model: {modelReady === null ? 'warming…' : modelReady ? 'ready' : 'will load on first request'}
                </span>
              </div>
            )}

            {isRecording && (
              <div className="text-center mb-4">
                <div className="inline-flex items-center bg-red-100 text-red-700 px-4 py-2 rounded-full">
                  <span className="w-3 h-3 bg-red-600 rounded-full mr-2 animate-pulse"></span>
                  Recording in progress
                </div>
              </div>
            )}
            {!isRecording && !speechSupported && (
              <div className="text-center mb-4">
                <div className="inline-flex items-center bg-yellow-100 text-yellow-800 px-4 py-2 rounded-full">
                  Your browser doesn't support Speech Recognition. Use Chrome/Edge or the manual input below.
                </div>
              </div>
            )}
            {/* Manual input fallback for quick testing or browsers without speech recognition */}
            <ManualInput onSubmit={saveSegment} disabled={!!isRecording && !!recognitionRef.current} />
          </div>
        </div>

        <div className="bg-white rounded-xl shadow-lg p-6">
          <div className="flex items-center justify-between mb-4">
            <h2 className="text-xl font-bold text-gray-900">Live Transcription</h2>
            <button
              onClick={retryTranslateMissing}
              disabled={bulkRetrying || segments.every((s) => s.translated_text && s.translated_text !== s.original_text)}
              className="text-sm px-3 py-1 rounded-md border disabled:opacity-50 hover:bg-gray-50"
              title="Retry translation for lines without English"
            >
              {bulkRetrying ? 'Translating…' : 'Translate missing'}
            </button>
          </div>
          <div className="space-y-3 max-h-96 overflow-y-auto">
            <div className="text-xs text-gray-500 mb-2">Approx. storage used by this app: {Math.round(LocalDB.getStorageBytes()/1024)} KB</div>
            {segments
              .slice()
              .sort((a, b) => a.sequence_number - b.sequence_number)
              .map((segment) => (
                <div key={segment.id} className="bg-gray-50 rounded-lg p-4">
                  <p className="text-gray-900">{segment.original_text}</p>
                  {!showOriginalsOnly && (
                    <>
                      {translatingIds.has(segment.id) || segment.translated_text === null ? (
                        <div className="mt-2 flex items-center gap-2">
                          <span className="text-xs text-blue-400 animate-pulse">Processing…</span>
                        </div>
                      ) : segment.translated_text && segment.translated_text !== segment.original_text ? (
                        <p className="text-blue-600 text-sm mt-2 italic">{segment.translated_text}</p>
                      ) : (
                        <div className="mt-2 flex items-center gap-2">
                          <span className="text-xs text-gray-400">No English yet</span>
                          <button
                            onClick={() => retryTranslateOne(segment)}
                            disabled={retryingIds.has(segment.id)}
                            className="text-xs px-2 py-1 border rounded-md disabled:opacity-50 hover:bg-gray-50"
                          >
                            {retryingIds.has(segment.id) ? 'Translating…' : 'Translate'}
                          </button>
                        </div>
                      )}
                    </>
                  )}
                  <span className="text-xs text-gray-500 mt-2 block">
                    {new Date(segment.created_at).toLocaleTimeString()}
                  </span>
                </div>
              ))}
            {interimText && (
              <div className="bg-yellow-50 rounded-lg p-4 border-2 border-yellow-200">
                <p className="text-gray-700 italic">{interimText}</p>
                <span className="text-xs text-gray-500 mt-2 block">Processing...</span>
              </div>
            )}
            {segments.length === 0 && !interimText && (
              <div className="text-center py-12 text-gray-500">
                <Mic className="w-12 h-12 mx-auto mb-3 text-gray-400" />
                <p>Start recording to see live transcriptions appear here</p>
              </div>
            )}
          </div>
        </div>
      </div>

      {showQR && group && (
        <QRCodeDisplay
          joinCode={group.join_code}
          groupName={group.name}
          onClose={() => setShowQR(false)}
        />
      )}
    </div>
  );
}

function ManualInput({ onSubmit, disabled }: { onSubmit: (text: string) => void | Promise<void>; disabled?: boolean }) {
  const [text, setText] = useState('');
  const [busy, setBusy] = useState(false);
  const canSubmit = text.trim().length > 0 && !busy && !disabled;
  return (
    <div className="mt-4">
      <label className="block text-sm text-gray-600 mb-1">Type a line to add manually</label>
      <div className="flex gap-2">
        <input
          type="text"
          value={text}
          onChange={(e) => setText(e.target.value)}
          onKeyDown={async (e) => {
            if (e.key === 'Enter' && canSubmit) {
              setBusy(true);
              await onSubmit(text.trim());
              setText('');
              setBusy(false);
            }
          }}
          className="flex-1 px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
          placeholder="Hello everyone..."
          disabled={disabled}
        />
        <button
          onClick={async () => {
            if (!canSubmit) return;
            setBusy(true);
            await onSubmit(text.trim());
            setText('');
            setBusy(false);
          }}
          disabled={!canSubmit}
          className="px-4 py-2 bg-blue-600 text-white rounded-lg disabled:opacity-50 disabled:cursor-not-allowed hover:bg-blue-700"
        >
          Add
        </button>
      </div>
    </div>
  );
}
