/**
 * @file MessageComponentBox.tsx
 * @description This file defines the MessageComponentBox component, which renders the content
 * of an AssistantMessage. It supports rendering various message types such as grounded text,
 * normal text, and follow-up questions. The component uses React and MobX for state management
 * and includes functionality for handling citation and follow-up actions, as well as displaying
 * agent processing information.
 */

import React, { useState } from 'react';
import { observer } from 'mobx-react';
import { AssistantMessage, Citation, MessageContent, PROCESSING_TYPE, ProcessingInfo, TEXT_TYPE } from '../types/types';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';

/**
 * Props for the MessageComponentBox.
 * @interface MessageComponentProps
 * @property {AssistantMessage} message - The message data to display.
 * @property {number} index - The index of the message.
 * @property {Function} onFollowUpClick - Callback to handle follow-up question clicks.
 * @property {Function} onCitationClick - Callback to handle citation clicks.
 * @property {Function} updateMessageCitations - Function to update message citations.
 */
interface MessageComponentProps {
    message: AssistantMessage;
    onFollowUpClick: (question: string) => void;
    onCitationClick: (citation: Citation) => void;
    updateMessageCitations: (index: number, citations: Citation[]) => void;
}

/**
 * MessageComponentBox displays the content of an AssistantMessage including text, citations,
 * processing information, and follow-up questions.
 * @param {MessageComponentProps} props - The props for the component.
 */
const MessageComponentBox: React.FC<MessageComponentProps> = ({ message, onFollowUpClick, onCitationClick }) => {
    // State for managing whether the dropdown is open or closed for processing info
    const [dropdownOpen, setDropdownOpen] = useState(false);

    /**
     * Renders the content of the message based on the type (e.g., grounded text, normal text).
     * @param {MessageContent} item - The content item to render.
     * @returns {JSX.Element} JSX element rendering the content.
     */
    const renderContent = (item: MessageContent) => {
        const i = item.index;

        // Handle grounded text with citations
        if (item.type === TEXT_TYPE.GROUNDED) {
            const citation_ids = item.citation_ids || [];
            return (
                <span key={i} className="grounded-text">
                    <ReactMarkdown
                        remarkPlugins={[remarkGfm]}
                        components={{
                            p: ({ node, children }) => (
                                <span className="grounded-text">
                                    {children}
                                    {citation_ids.map((id, idx) => {
                                        const citation = message.citations?.find(c => c.citation_id === id);
                                        if (!citation) return null;
                                        return (
                                            <button key={i + idx} className="citation-button" onClick={() => onCitationClick(citation)} style={{ display: 'inline-flex', alignItems: 'center', marginLeft: '4px' }}>
                                                {i + idx + 1}
                                            </button>
                                        );
                                    })}
                                    <br />
                                </span>
                            ),
                        }}>
                        {item.text}
                    </ReactMarkdown>
                </span>
            );
        }

        // Handle normal text
        else if (item.type === TEXT_TYPE.NORMAL) {
            return (
                <span key={i} className="normal-text">
                    <ReactMarkdown remarkPlugins={[remarkGfm]}>{item.text}</ReactMarkdown>
                </span>
            );
        }

        // Handle query type content
        else if ('query' in item) {
            return (
                <span key={i} className="query-text">
                    <ReactMarkdown>{JSON.stringify(item.query)}</ReactMarkdown>
                </span>
            );
        }

        // Fallback for any other content type
        else {
            return (
                <span key={i}>
                    <ReactMarkdown>{item.text}</ReactMarkdown>
                </span>
            );
        }
    };

    // Check if the message contains processing information (thoughts/actions)
    const hasProcessingInfo = message.processing_info && message.processing_info.length > 0;

    /**
     * Renders processing information such as thoughts or actions during message handling.
     * @param {ProcessingInfo} info - The processing information to render.
     * @returns {JSX.Element | null} JSX element rendering the processing info or null.
     */
    const renderProcessingInfo = (info: ProcessingInfo) => {
        if (info.type === PROCESSING_TYPE.THOUGHT) {
            return (
                <div key={info.index} className="dropdown-item">
                    <strong>Thought:</strong> {info.content}
                </div>
            );
        } else if (info.type === PROCESSING_TYPE.ACTION) {
            return (
                <div key={info.index} className="dropdown-item">
                    <strong>Action:</strong> {info.content}
                </div>
            );
        }
        return null;
    };

    /**
     * Formats the follow-up question text to ensure proper capitalization
     * @param {string} question - The original question text
     * @returns {string} The formatted question
     */
    const formatFollowUpQuestion = (question: string) => {
        // Only capitalize first letter if needed and preserve the rest
        if (!question) return '';
        const formattedQuestion = question.charAt(0).toUpperCase() + question.slice(1).toLowerCase();
        return formattedQuestion;
    };

    return (
        <div className={`message ${message.role}`}>
            {/* Processing Information Dropdown */}
            {hasProcessingInfo && (
                <div className="processing-info">
                    <button className="toggle-info" onClick={() => setDropdownOpen(!dropdownOpen)}>
                        {dropdownOpen ? 'Hide Agent Thoughts/Actions' : 'Show Agent Thoughts/Actions'}
                    </button>
                    {dropdownOpen && <div className="info-content">{message.processing_info.map(renderProcessingInfo)}</div>}
                </div>
            )}

            {/* Message Content */}
            <div className="message-content">{message.content && message.content.map(messageFragment => <React.Fragment key={messageFragment.index}>{renderContent(messageFragment)}</React.Fragment>)}</div>

            {/* Follow-up Questions Section */}
            {message.follow_up_questions && message.follow_up_questions.length > 0 && (
                <div className="follow-up-questions">
                    <h4>Follow-up Questions:</h4>
                    <div className="questions-list">
                        {message.follow_up_questions.map((question, idx) => (
                            <button key={idx} className="follow-up-button" onClick={() => onFollowUpClick(question)}>
                                {question}
                            </button>
                        ))}
                    </div>
                </div>
            )}
        </div>
    );
};

// Export the observer-wrapped component to allow MobX to react to state changes
export default observer(MessageComponentBox);
