import { useState, useCallback, useMemo, useEffect, useRef } from "react";
import { Masthead } from "../components/Masthead";
import { SpeakerPanel } from "../components/listen/SpeakerPanel";
import { TranscriptPanel } from "../components/listen/TranscriptPanel";
import { ControlPanel, type ContractOption } from "../components/listen/ControlPanel";
import { TranscriptAnalysisPanel } from "../components/listen/TranscriptAnalysisPanel";
import { useMicrophone } from "../hooks/useMicrophone";
import { useWebSocket } from "../hooks/useWebSocket";
import { listContracts } from "../lib/api";
import { useAuth } from "../contexts/AuthContext";

export default function ListenPage() {
  const [isListening, setIsListening] = useState(false);
  const [activeSpeaker, setActiveSpeaker] = useState<string | null>(null);
  const [permissionRequested, setPermissionRequested] = useState(false);
  const isListeningRef = useRef(false);

  // Contract selection state
  const [contracts, setContracts] = useState<ContractOption[]>([]);
  const [selectedContractId, setSelectedContractId] = useState<string | null>(null);
  const [contractsLoading, setContractsLoading] = useState(true);
  const { session, isAuthenticated } = useAuth();

  // Saved transcript state for analysis
  const [savedTranscript, setSavedTranscript] = useState<{
    fileId: string;
    contractId: string;
  } | null>(null);

  // Fetch contracts on mount
  useEffect(() => {
    if (!isAuthenticated) {
      setContractsLoading(false);
      return;
    }

    async function fetchContracts() {
      try {
        const response = await listContracts();
        setContracts(
          response.contracts.map((c) => ({
            id: c.id,
            name: c.name,
          }))
        );
      } catch (err) {
        console.error("Failed to fetch contracts:", err);
      } finally {
        setContractsLoading(false);
      }
    }
    fetchContracts();
  }, [isAuthenticated]);

  // Keep ref in sync with state for use in callbacks
  useEffect(() => {
    isListeningRef.current = isListening;
  }, [isListening]);

  const ws = useWebSocket({
    onTranscript: (transcript) => {
      // Track active speaker
      if (!transcript.isFinal) {
        setActiveSpeaker(transcript.speaker);
      }
    },
    onStopped: () => {
      setIsListening(false);
      setActiveSpeaker(null);
    },
    onTranscriptSaved: (fileId, contractId) => {
      // Store the saved transcript info for analysis
      setSavedTranscript({ fileId, contractId });
    },
  });

  const wsRef = useRef(ws);
  useEffect(() => {
    wsRef.current = ws;
  }, [ws]);

  const handleAudioData = useCallback((samples: Float32Array) => {
    if (wsRef.current.isConnected && isListeningRef.current) {
      wsRef.current.sendAudio(samples);
    }
  }, []);

  const mic = useMicrophone({
    sampleRate: 16000,
    onAudioData: handleAudioData,
  });

  // Request microphone permission on page load
  useEffect(() => {
    if (!permissionRequested) {
      setPermissionRequested(true);
      mic.requestPermission();
    }
  }, [permissionRequested, mic.requestPermission]);

  // Derive unique speakers from transcripts
  const speakers = useMemo(() => {
    const speakerSet = new Set<string>();
    ws.transcripts.forEach((t) => speakerSet.add(t.speaker));

    return Array.from(speakerSet).map((speaker) => ({
      id: speaker,
      label: speaker,
      isActive: speaker === activeSpeaker,
    }));
  }, [ws.transcripts, activeSpeaker]);

  // Clear active speaker after a delay
  useEffect(() => {
    if (activeSpeaker) {
      const timer = setTimeout(() => setActiveSpeaker(null), 1500);
      return () => clearTimeout(timer);
    }
  }, [activeSpeaker]);

  const handleToggle = useCallback(async () => {
    if (isListening) {
      // Stop listening
      mic.stop();
      ws.stopSession("user_stopped");
      setIsListening(false);
      setActiveSpeaker(null);
      return;
    }

    // If permission was denied or errored, try requesting again
    if (mic.status === "denied" || mic.status === "error") {
      const permitted = await mic.requestPermission();
      if (!permitted) {
        return;
      }
    }

    // Start listening - start the microphone
    const micStarted = await mic.start();
    if (!micStarted) {
      // Microphone permission denied or error
      return;
    }

    // Microphone started, now connect to WebSocket
    const connected = await ws.connect();
    if (!connected) {
      // Connection failed - stop the microphone
      mic.stop();
      return;
    }

    // Both microphone and WebSocket are ready - start the session
    // Pass contract_id and auth token if available
    const authToken = session?.access_token || null;
    ws.startSession(mic.sampleRate, mic.channels, selectedContractId, authToken);
    setIsListening(true);
  }, [isListening, mic, ws, selectedContractId, session]);

  const handleNew = useCallback(() => {
    // Stop current session - backend auto-saves transcript on disconnect
    mic.stop();
    if (ws.isConnected) {
      ws.stopSession("new_session");
    }
    ws.clearTranscripts();
    ws.disconnect();
    setIsListening(false);
    setActiveSpeaker(null);
    setSavedTranscript(null);
  }, [mic, ws]);

  const handleCloseAnalysis = useCallback(() => {
    setSavedTranscript(null);
  }, []);

  const error = ws.error || mic.error;

  return (
    <div className="relative z-10 h-screen flex flex-col overflow-hidden">
      <Masthead showTicker={false} showNav />

      <main className="flex-1 p-4 md:p-6 grid grid-cols-1 md:grid-cols-[300px_1fr] grid-rows-[minmax(0,1fr)_auto] md:grid-rows-[minmax(0,1fr)_auto] gap-4 min-h-0 overflow-hidden">
        {/* Speaker Panel - top left on desktop, hidden on mobile */}
        <div className="hidden md:block row-span-1 min-h-0 overflow-hidden">
          <SpeakerPanel speakers={speakers} />
        </div>

        {/* Transcript Panel - right side, spans 2 rows on desktop */}
        <div className="md:row-span-2 min-h-0 overflow-hidden">
          <TranscriptPanel transcripts={ws.transcripts} />
        </div>

        {/* Control Panel - bottom left on desktop */}
        <div className="md:col-start-1 md:row-start-2 shrink-0">
          <ControlPanel
            isListening={isListening}
            isConnected={ws.isConnected}
            micStatus={mic.status}
            micVolume={mic.volume}
            hasTranscripts={ws.transcripts.length > 0}
            onToggle={handleToggle}
            onNew={handleNew}
            error={error}
            contracts={contracts}
            selectedContractId={selectedContractId}
            onContractChange={setSelectedContractId}
            contractsLoading={contractsLoading}
            connectionStatus={ws.status}
          />
        </div>
      </main>

      {/* Transcript Analysis Panel - shown after recording stops and transcript is saved */}
      {savedTranscript && !isListening && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60">
          <div className="w-full max-w-2xl mx-4 max-h-[90vh] overflow-hidden">
            <TranscriptAnalysisPanel
              fileId={savedTranscript.fileId}
              contractId={savedTranscript.contractId}
              selectedContractId={selectedContractId}
              onContractCreated={(response) => {
                // Refresh contracts list and select the new contract
                setContracts((prev) => [
                  { id: response.contractId, name: response.contractName },
                  ...prev,
                ]);
                setSelectedContractId(response.contractId);
              }}
              onContractUpdated={() => {
                // Keep the current selection
              }}
              onClose={handleCloseAnalysis}
            />
          </div>
        </div>
      )}
    </div>
  );
}
