/**
 * @license
 * SPDX-License-Identifier: Apache-2.0
*/
import React, { useEffect, useRef, useState, useCallback } from 'react';
// import WelcomeScreen from '../welcome-screen/WelcomeScreen';
// FIX: Import LiveServerContent to correctly type the content handler.
import { LiveConnectConfig, Modality, LiveServerContent } from '@google/genai';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';

import { useLiveAPIContext } from '../../contexts/LiveAPIContext';
import {
  useSettings,
  useLogStore,
  useTools,
  ConversationTurn,
  useUI,
} from '@/lib/state';
import { SourcesPopover } from '../sources-popover/sources-popover';
import { GroundingWidget } from '../GroundingWidget';

const formatTimestamp = (date: Date) => {
  const pad = (num: number, size = 2) => num.toString().padStart(size, '0');
  const hours = pad(date.getHours());
  const minutes = pad(date.getMinutes());
  const seconds = pad(date.getSeconds());
  const milliseconds = pad(date.getMilliseconds(), 3);
  return `${hours}:${minutes}:${seconds}.${milliseconds}`;
};

// Hook to detect screen size for responsive component rendering
const useMediaQuery = (query: string) => {
  const [matches, setMatches] = useState(false);

  useEffect(() => {
    const media = window.matchMedia(query);
    if (media.matches !== matches) {
      setMatches(media.matches);
    }
    const listener = () => {
      setMatches(media.matches);
    };
    media.addEventListener('change', listener);
    return () => media.removeEventListener('change', listener);
  }, [matches, query]);

  return matches;
};


export default function StreamingConsole() {
  const {
    client,
    setConfig,
    heldGroundingChunks,
    clearHeldGroundingChunks,
    heldGroundedResponse,
    clearHeldGroundedResponse,
  } = useLiveAPIContext();
  const { systemPrompt, voice } = useSettings();
  const { tools } = useTools();
  const turns = useLogStore(state => state.turns);
  const { showSystemMessages } = useUI();
  const isAwaitingFunctionResponse = useLogStore(
    state => state.isAwaitingFunctionResponse,
  );
  const scrollRef = useRef<HTMLDivElement>(null);
  const isMobile = useMediaQuery('(max-width: 768px)');

  const displayedTurns = showSystemMessages
    ? turns
    : turns.filter(turn => turn.role !== 'system');

  // Set the configuration for the Live API
  useEffect(() => {
    const enabledTools = tools
      .filter(tool => tool.isEnabled)
      .map(tool => ({
        functionDeclarations: [
          {
            name: tool.name,
            description: tool.description,
            parameters: tool.parameters,
          },
        ],
      }));
    // Text-only configuration for agricultural form-based application
    const config: any = {
      responseModalities: [Modality.TEXT],
      systemInstruction: {
        parts: [
          {
            text: systemPrompt,
          },
        ],
      },
      tools: enabledTools,
      thinkingConfig: {
        thinkingBudget: 0
      },
    };

    setConfig(config);
  }, [setConfig, systemPrompt, tools]);

  useEffect(() => {
    const { addTurn, updateLastTurn, mergeIntoLastAgentTurn } =
      useLogStore.getState();


    const handleContent = (serverContent: LiveServerContent) => {
      const { turns, updateLastTurn, addTurn, mergeIntoLastAgentTurn } =
        useLogStore.getState();
      const text =
        serverContent.modelTurn?.parts
          ?.map((p: any) => p.text)
          .filter(Boolean)
          .join('') ?? '';
      const groundingChunks = serverContent.groundingMetadata?.groundingChunks;

      if (!text && !groundingChunks) return;

      const last = turns[turns.length - 1];

      if (last?.role === 'agent' && !last.isFinal) {
        const updatedTurn: Partial<ConversationTurn> = {
          text: last.text + text,
        };
        if (groundingChunks) {
          updatedTurn.groundingChunks = [
            ...(last.groundingChunks || []),
            ...groundingChunks,
          ];
        }
        updateLastTurn(updatedTurn);
      } else {
        const lastAgentTurnIndex = turns.map(t => t.role).lastIndexOf('agent');
        let shouldMerge = false;
        if (lastAgentTurnIndex !== -1) {
          const subsequentTurns = turns.slice(lastAgentTurnIndex + 1);
          if (
            subsequentTurns.length > 0 &&
            subsequentTurns.every(t => t.role === 'system')
          ) {
            shouldMerge = true;
          }
        }

        const newTurnData: Omit<ConversationTurn, 'timestamp' | 'role'> = {
          text,
          isFinal: false,
          groundingChunks,
        };
        if (heldGroundingChunks) {
          const combinedChunks = [
            ...(heldGroundingChunks || []),
            ...(newTurnData.groundingChunks || []),
          ];
          newTurnData.groundingChunks = combinedChunks;
          clearHeldGroundingChunks();
        }
        if (heldGroundedResponse) {
          newTurnData.toolResponse = heldGroundedResponse;
          clearHeldGroundedResponse();
        }

        if (shouldMerge) {
          mergeIntoLastAgentTurn(newTurnData);
        } else {
          addTurn({ ...newTurnData, role: 'agent' });
        }
      }
    };

    const handleTurnComplete = () => {
      const turns = useLogStore.getState().turns;
      // FIX: Replace .at(-1) with array indexing for broader compatibility.
      const last = turns[turns.length - 1];
      if (last && !last.isFinal) {
        updateLastTurn({ isFinal: true });
      }
    };

    client.on('content', handleContent);
    client.on('turncomplete', handleTurnComplete);
    client.on('generationcomplete', handleTurnComplete);

    return () => {
      client.off('content', handleContent);
      client.off('turncomplete', handleTurnComplete);
      client.off('generationcomplete', handleTurnComplete);
    };
  }, [
    client,
    heldGroundingChunks,
    clearHeldGroundingChunks,
    heldGroundedResponse,
    clearHeldGroundedResponse,
  ]);

  useEffect(() => {
    if (scrollRef.current) {
      // The widget has a 300ms transition for max-height. We need to wait
      // for that transition to finish before we can accurately scroll to the bottom.
      const scrollTimeout = setTimeout(() => {
        if (scrollRef.current) {
          scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
        }
      }, 350); // A little longer than the transition duration

      return () => clearTimeout(scrollTimeout);
    }
  }, [turns, isAwaitingFunctionResponse]);

  return (
    <div className="transcription-container">
      {displayedTurns.length === 0 && !isAwaitingFunctionResponse ? (
        <div></div>
      ) : (
        <div className="transcription-view" ref={scrollRef}>
          {displayedTurns.map((t) => {
            if (t.role === 'system') {
              return (
                <div
                  key={t.timestamp.toISOString()}
                  className={`transcription-entry system`}
                >
                  <div className="transcription-header">
                    <div className="transcription-source">System</div>
                    <div className="transcription-timestamp">
                      {formatTimestamp(t.timestamp)}
                    </div>
                  </div>
                  <div className="transcription-text-content">
                    <ReactMarkdown remarkPlugins={[remarkGfm]}>{t.text}</ReactMarkdown>
                  </div>
                </div>
              )
            }
            const widgetToken =
              t.toolResponse?.candidates?.[0]?.groundingMetadata
                ?.googleMapsWidgetContextToken;
            
            let sources: { uri: string; title: string }[] = [];
            if (t.groundingChunks) {
              sources =
                t.groundingChunks
                  .map(chunk => {
                    const source = chunk.web || chunk.maps;
                    if (source && source.uri) {
                      return {
                        uri: source.uri,
                        title: source.title || source.uri,
                      };
                    }
                    return null;
                  })
                  .filter((s): s is { uri: string; title: string } => s !== null);

              if (t.groundingChunks.length === 1) {
                const chunk = t.groundingChunks[0];
                // The type for `placeAnswerSources` might be missing or incomplete. Use `any` for safety.
                const placeAnswerSources = (chunk.maps as any)?.placeAnswerSources;
                if (
                  placeAnswerSources &&
                  Array.isArray(placeAnswerSources.reviewSnippets)
                ) {
                  const reviewSources = placeAnswerSources.reviewSnippets
                    .map((review: any) => {
                      if (review.googleMapsUri && review.title) {
                        return {
                          uri: review.googleMapsUri,
                          title: review.title,
                        };
                      }
                      return null;
                    })
                    .filter((s): s is { uri: string; title: string } => s !== null);
                  sources.push(...reviewSources);
                }
              }
            }

            const hasSources = sources.length > 0;

            return (
              <div
                key={t.timestamp.toISOString()}
                className={`transcription-entry ${t.role} ${!t.isFinal ? 'interim' : ''
                  }`}
              >
                <div className="avatar">
                  <span className="icon">{t.role === 'user' ? 'person' : 'auto_awesome'}</span>
                </div>
                <div className="message-bubble">
                  <div className="transcription-text-content">
                    <ReactMarkdown remarkPlugins={[remarkGfm]}>
                      {t.text}
                    </ReactMarkdown>
                  </div>
                  {hasSources && (
                    <SourcesPopover
                      className="grounding-chunks"
                      sources={sources}
                    />
                  )}
                  {widgetToken && !isMobile && (
                    <div
                      style={{
                        marginTop: '12px',
                      }}
                    >
                      <GroundingWidget
                        contextToken={widgetToken}
                        mapHidden={true}
                      />
                    </div>
                  )}
                </div>
              </div>
            );
          })}
          {isAwaitingFunctionResponse && (
            <div className="spinner-container">
              <div className="spinner"></div>
              <p>Calling tool...</p>
            </div>
          )}
        </div>
      )}
    </div>
  );
}