import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "preact/hooks";
import { MessageTools, type IMessage } from "../../messages";
import { StateContext } from "../../contexts/state";
import { DOMTools } from "../../dom";

import styles from './message.module.css';
import { AutoTextarea } from "../autoTextarea";

interface IProps {
    message: IMessage;
    index: number;
    isLastUser: boolean;
    isLastAssistant: boolean;
}

export const Message = ({ message, index, isLastUser, isLastAssistant }: IProps) => {
    const { messages, editMessage, deleteMessage, setCurrentSwipe, setMessages } = useContext(StateContext);
    const [editing, setEditing] = useState(false);
    const [savedMessage, setSavedMessage] = useState('');
    const textRef = useRef<HTMLDivElement>(null);

    const content = useMemo(() => MessageTools.getSwipe(message)?.content, [message]);
    const htmlContent = useMemo(() => MessageTools.format(content ?? ''), [content]);

    const handleToggleEdit = useCallback(() => {
        setEditing(!editing);
        if (!editing) {
            setSavedMessage(content ?? '');
        }
    }, [editing, content]);

    const handleCancelEdit = useCallback(() => {
        setEditing(false);
        editMessage(index, savedMessage);
    }, [editMessage, index, savedMessage]);

    const handleDeleteMessage = useCallback(() => {
        if (confirm('Delete message?')) {
            setEditing(false);
            deleteMessage(index);
        }
    }, [deleteMessage, index]);

    const handleStopHere = useCallback(() => {
        if (confirm('Delete all messages after that?')) {
            setMessages(messages.filter((_, i) => i <= index));
            setEditing(false);
        }
    }, [messages, setMessages, index]);

    const handleEdit = useCallback((e: InputEvent) => {
        if (e.target instanceof HTMLTextAreaElement) {
            const newContent = e.target.value;
            editMessage(index, newContent);
        }
    }, [editMessage, index]);

    const handleSwipeLeft = useCallback(() => {
        setCurrentSwipe(index, message.currentSwipe - 1);
        DOMTools.animate(textRef.current, 'swipe-from-left');
    }, [setCurrentSwipe, index, message]);

    const handleSwipeRight = useCallback(() => {
        setCurrentSwipe(index, message.currentSwipe + 1);
        DOMTools.animate(textRef.current, 'swipe-from-right');
    }, [setCurrentSwipe, index, message]);

    return (
        <div class={`${styles.message} ${styles[message.role]} ${isLastUser ? styles.lastUser : ''}`}>
            <div class={styles.content}>
                {editing
                    ? <AutoTextarea onInput={handleEdit} value={content} />
                    : <div class={styles.text} dangerouslySetInnerHTML={{ __html: htmlContent }} ref={textRef} />
                }
                {(isLastUser || message.role === 'assistant') &&
                    <div class={styles.buttons}>
                        {editing
                            ? <>
                                <button class='icon' onClick={handleToggleEdit}>✔</button>
                                <button class='icon' onClick={handleDeleteMessage}>🗑️</button>
                                <button class='icon' onClick={handleStopHere} title='Stop here'>⛔</button>
                                <button class='icon' onClick={handleCancelEdit}>❌</button>
                            </>
                            : <>
                                {isLastAssistant &&
                                    <div class={styles.swipes}>
                                        <div onClick={handleSwipeLeft}>◀</div>
                                        <div>{message.currentSwipe + 1}/{message.swipes.length}</div>
                                        <div onClick={handleSwipeRight}>▶</div>
                                    </div>
                                }
                                <button class='icon' onClick={handleToggleEdit} title="Edit">🖊</button>
                            </>
                        }
                    </div>
                }
            </div>
        </div>
    );
};
