import {AlertTriangle, Book, BookOpen, Bot, Send, User} from 'lucide-react';
import React, {Dispatch, RefObject, SetStateAction, useContext, useEffect, useRef, useState,} from 'react';
import {Conversation, ConversationType, Message} from "@/lib/types/quillsense";
import {getSubLevel, isGeminiEnabled} from "@/lib/utils/quillsense";
import {ChapterContext, ChapterContextProps} from "@/context/ChapterContext";
import {BookContext, BookContextProps} from "@/context/BookContext";
import {AlertContext, AlertContextProps} from "@/context/AlertContext";
import {SessionContext, SessionContextProps} from '@/context/SessionContext';
import {apiGet, apiPost} from '@/lib/api/client';
import {useTranslations} from '@/lib/i18n';
import {LangContext, LangContextProps} from "@/context/LangContext";
import {AIUsageContext, AIUsageContextProps} from "@/context/AIUsageContext";
import Button from "@/components/ui/Button";
import IconButton from "@/components/ui/IconButton";
import IconContainer from "@/components/ui/IconContainer";
import LockCard from "@/components/ui/LockCard";

interface QuillConversationProps {
    disabled: boolean;
    selectedConversation: string;
    setSelectConversation: Dispatch<SetStateAction<string>>;
}

type ContextType = 'none' | 'chapter' | 'book';

export default function QuillConversation(
    {
        disabled,
        selectedConversation,
        setSelectConversation,
    }: QuillConversationProps): React.JSX.Element {
    const t = useTranslations();
    const {lang}: LangContextProps = useContext<LangContextProps>(LangContext);
    const {session}: SessionContextProps = useContext<SessionContextProps>(SessionContext);
    const {errorMessage}: AlertContextProps = useContext<AlertContextProps>(AlertContext);
    const {book}: BookContextProps = useContext<BookContextProps>(BookContext);
    const {chapter}: ChapterContextProps = useContext<ChapterContextProps>(ChapterContext);
    const {setTotalPrice, setTotalCredits}: AIUsageContextProps = useContext<AIUsageContextProps>(AIUsageContext)

    const [inputText, setInputText] = useState<string>('');
    const [messages, setMessages] = useState<Message[]>([]);
    const [isLoading, setIsLoading] = useState<boolean>(false);
    const [contextType, setContextType] = useState<ContextType>('none');
    const [showContextAlert, setShowContextAlert] = useState<boolean>(false);
    const [pendingContextType, setPendingContextType] = useState<ContextType>('none');
    const messageContainerRef: RefObject<HTMLDivElement | null> = useRef<HTMLDivElement>(null);
    const textareaRef: RefObject<HTMLTextAreaElement | null> = useRef<HTMLTextAreaElement>(null);

    const [mode, setMode] = useState<ConversationType>('chatbot');

    const geminiEnabled: boolean = isGeminiEnabled(session);
    const isSubTierTwo: boolean = getSubLevel(session) >= 2;
    const hasAccess: boolean = geminiEnabled || isSubTierTwo;

    function adjustTextareaHeight(): void {
        const textarea: HTMLTextAreaElement | null = textareaRef.current;
        if (textarea) {
            textarea.style.height = 'auto';
            const newHeight: number = Math.min(Math.max(textarea.scrollHeight, 42), 120);
            textarea.style.height = `${newHeight}px`;
        }
    }

    function scrollToBottom(): void {
        const messageContainer: HTMLDivElement | null = messageContainerRef.current;
        if (messageContainer) {
            messageContainer.scrollTop = messageContainer.scrollHeight;
        }
    }
    
    function LoadingMessage(): React.JSX.Element {
        return (
            <div className="flex mb-6 justify-start">
                <div className="mr-3">
                    <IconContainer icon={Bot} size="sm" shape="circle"/>
                </div>
                <div
                    className="max-w-[75%] p-4 rounded-2xl bg-secondary text-text-primary rounded-bl-md">
                    <div className="flex items-center space-x-2">
                        <span className="text-text-secondary text-sm">{t('quillConversation.loadingMessage')}</span>
                        <div className="flex space-x-1">
                            <div className="w-2 h-2 bg-primary rounded-full animate-pulse pulse-dot-1"></div>
                            <div className="w-2 h-2 bg-primary rounded-full animate-pulse pulse-dot-2"></div>
                            <div className="w-2 h-2 bg-primary rounded-full animate-pulse pulse-dot-3"></div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
    
    function WelcomeMessage(): React.JSX.Element {
        return (
            <div className="flex flex-col items-center justify-center h-full p-8">
                <div className="mb-6">
                    <IconContainer icon={Bot} size="lg" shape="rounded"/>
                </div>
                <h2 className="text-2xl font-['ADLaM_Display'] text-text-primary mb-3">{t('quillConversation.welcomeTitle')}</h2>
                <p className="text-muted text-center leading-relaxed text-lg max-w-md mb-6">
                    {t('quillConversation.welcomeDescription')}
                </p>
                <div className="bg-tertiary rounded-xl p-4">
                    <p className="text-sm text-text-secondary text-center">
                        {t('quillConversation.welcomeTip')}
                    </p>
                </div>
            </div>
        );
    }
    
    function ContextAlert(): React.JSX.Element {
        const contextDescription: string = pendingContextType === 'chapter'
            ? t('quillConversation.contextAlert.chapter')
            : t('quillConversation.contextAlert.book');

        return (
            <div
                className="fixed inset-0 bg-darkest-background/60 backdrop-blur-md flex items-center justify-center z-50">
                <div className="bg-tertiary rounded-2xl p-5 max-w-md">
                    <div className="flex items-center mb-4">
                        <div className="mr-3">
                            <IconContainer icon={AlertTriangle} size="md" shape="square"/>
                        </div>
                        <h3 className="text-xl font-['ADLaM_Display'] text-text-primary">{t('quillConversation.contextAlert.title')}</h3>
                    </div>
                    <p className="text-muted mb-6 leading-relaxed text-lg">
                        {contextDescription}
                    </p>
                    <div className="flex space-x-3">
                        <div className="flex-1">
                            <Button
                                variant="secondary"
                                fullWidth
                                onClick={(): void => {
                                    setShowContextAlert(false);
                                    setPendingContextType('none');
                                }}
                            >
                                {t('common.cancel')}
                            </Button>
                        </div>
                        <div className="flex-1">
                            <Button
                                variant="primary"
                                fullWidth
                                onClick={(): void => {
                                    setContextType(pendingContextType);
                                    setShowContextAlert(false);
                                    setPendingContextType('none');
                                }}
                            >
                                {t('common.confirm')}
                            </Button>
                        </div>
                    </div>
                </div>
            </div>
        );
    }

    function handleContextChange(type: ContextType): void {
        if (type === 'none') {
            setContextType('none');
        } else {
            setPendingContextType(type);
            setShowContextAlert(true);
        }
    }
    
    useEffect((): void => {
        if (selectedConversation !== '' && hasAccess) {
            getMessages().then();
        }
    }, []);
    
    useEffect((): void => {
        scrollToBottom();
    }, [messages, isLoading]);
    
    useEffect((): void => {
        adjustTextareaHeight();
    }, [inputText]);
    
    
    async function getMessages(): Promise<void> {
        try {
            const response: Conversation =
                await apiGet<Conversation>(
                    `quillsense/conversation`,
                    session.accessToken,
                    "fr",
                    {id: selectedConversation},
                );
            if (response) {
                setMessages(response.messages);
                setMode(response.type ?? 'chatbot');
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t('quillConversation.genericError'));
            }
        }
    }
    
    function getCurrentTime(): string {
        const now: Date = new Date();
        return now.toLocaleTimeString([], {hour: '2-digit', minute: '2-digit'});
    }
    
    async function handleSend(): Promise<void> {
        if (!inputText.trim()) {
            errorMessage(t('quillConversation.emptyMessageError'));
            return;
        }
        try {
            const tempId: number = Date.now();
            const newMessage: Message = {
                id: tempId,
                message: inputText,
                type: 'user',
                date: getCurrentTime(),
            };
            setMessages((prevMessages: Message[]): Message[] => [...prevMessages, newMessage]);
            setInputText('');
            setIsLoading(true);
            
            const response: Conversation = await apiPost<Conversation>('quillsense/chatbot/send', {
                message: inputText,
                bookId: book?.bookId || null,
                chapterId: chapter?.chapterId || null,
                conversationId: selectedConversation ?? '',
                mode: mode,
                contextType: contextType,
                version: chapter?.chapterContent.version || null,
            }, session.accessToken, lang);
            setIsLoading(false);
            if (response) {
                setMessages((prevMessages: Message[]): Message[] => {
                    const userMessageFromServer: Message | undefined =
                        response.messages.find(
                            (msg: Message): boolean => msg.type === 'user',
                        );
                    const aiMessageFromServer: Message | undefined =
                        response.messages.find(
                            (msg: Message): boolean => msg.type === 'model',
                        );
                    
                    const updatedMessages: Message[] = prevMessages.map(
                        (msg: Message): Message =>
                            msg.id === tempId && userMessageFromServer
                                ? {
                                    ...msg,
                                    id: userMessageFromServer.id,
                                    date: userMessageFromServer.date,
                                }
                                : msg,
                    );
                    
                    return aiMessageFromServer
                        ? [...updatedMessages, aiMessageFromServer]
                        : updatedMessages;
                });
                
                if (response.useYourKey) {
                    setTotalPrice((prevTotal: number): number => prevTotal + (response.totalPrice || 0));
                } else {
                    setTotalCredits(response.totalPrice || 0);
                }
                
                if (selectedConversation === '') {
                    setSelectConversation(response.id);
                }
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t('quillConversation.genericError'));
            }
            setIsLoading(false);
        }
    }
    
    if (!hasAccess) {
        return (
            <div className="flex flex-col h-full">
                <LockCard title={t('quillConversation.accessRequired.title')}
                          description={t('quillConversation.accessRequired.description')}/>
                <div className="p-4">
                    <div
                        className="flex items-center rounded-2xl bg-tertiary p-3 opacity-50">
                        <textarea
                            disabled={true}
                            placeholder={t('quillConversation.inputPlaceholder')}
                            rows={1}
                            className="flex-1 bg-transparent border-0 outline-none px-4 py-2 text-text-primary placeholder-text-secondary resize-none overflow-hidden min-h-[42px] max-h-[120px] cursor-not-allowed"
                        />
                        <div className="ml-2">
                            <IconButton icon={Send} variant="muted" size="lg" shape="square" disabled={true}/>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
    
    return (
        <>
            <div ref={messageContainerRef} className="flex-1 p-6 overflow-y-auto">
                {messages.length === 0 && !isLoading ? (
                    <WelcomeMessage/>
                ) : (
                    messages.map((message: Message): React.JSX.Element => (
                        <div
                            key={message.id}
                            className={`flex mb-6 ${message.type === 'user' ? 'justify-end' : 'justify-start'}`}
                        >
                            {message.type === 'model' && (
                                <div className="mr-3">
                                    <IconContainer icon={Bot} size="sm" shape="circle"/>
                                </div>
                            )}
                            <div
                                className={`max-w-[75%] p-4 rounded-2xl ${
                                    message.type === 'user'
                                        ? 'bg-primary text-text-primary rounded-br-md'
                                        : 'bg-tertiary text-text-primary rounded-bl-md'
                                }`}
                            >
                                <p className="leading-relaxed whitespace-pre-wrap">{message.message}</p>
                                <p className={`text-xs mt-2 ${
                                    message.type === 'user'
                                        ? 'text-text-primary/70'
                                        : 'text-text-secondary'
                                }`}>
                                    {message.date}
                                </p>
                            </div>
                            {message.type === 'user' && (
                                <div className="ml-3">
                                    <IconContainer icon={User} size="sm" shape="circle"/>
                                </div>
                            )}
                        </div>
                    ))
                )}
                {isLoading && <LoadingMessage/>}
            </div>
            
            <div className="p-4">
                <div className="flex items-center space-x-4 mb-3 px-2">
                    <span
                        className="text-sm text-text-secondary font-medium">{t('quillConversation.contextLabel')}</span>
                    <div className="flex items-center space-x-2">
                        <Button variant={contextType === 'none' ? 'primary' : 'secondary'} size="sm"
                                onClick={(): void => handleContextChange('none')}>
                            {t('quillConversation.context.none')}
                        </Button>
                        {chapter && (
                            <Button variant={contextType === 'chapter' ? 'primary' : 'secondary'} size="sm"
                                    icon={BookOpen}
                                    onClick={(): void => handleContextChange('chapter')}>
                                {t('quillConversation.context.chapter')}
                            </Button>
                        )}
                        {book && (
                            <Button variant={contextType === 'book' ? 'primary' : 'secondary'} size="sm"
                                    icon={Book}
                                    onClick={(): void => handleContextChange('book')}>
                                {t('quillConversation.context.book')}
                            </Button>
                        )}
                    </div>
                </div>
                <div className="flex items-end rounded-2xl bg-tertiary">
                    <textarea
                        disabled={disabled || isLoading}
                        ref={textareaRef}
                        value={inputText}
                        onChange={(e: React.ChangeEvent<HTMLTextAreaElement>): void => setInputText(e.target.value)}
                        onKeyDown={async (e: React.KeyboardEvent<HTMLTextAreaElement>): Promise<void> => {
                            if (e.key === 'Enter' && !e.shiftKey) {
                                e.preventDefault();
                                await handleSend();
                            }
                        }}
                        placeholder={t('quillConversation.inputPlaceholder')}
                        rows={1}
                        className="flex-1 bg-transparent border-0 outline-none px-4 text-text-primary placeholder-text-secondary resize-none overflow-hidden min-h-[42px] max-h-[120px] leading-relaxed"
                    />
                    <div className="m-2">
                        <IconButton icon={Send}
                                    variant={inputText.trim() === '' || isLoading ? 'muted' : 'primary'}
                                    size="lg" shape="square"
                                    onClick={handleSend}
                                    disabled={inputText.trim() === '' || isLoading}/>
                    </div>
                </div>
            </div>
            
            {showContextAlert && <ContextAlert/>}
        </>
    );
}
