import { Sparkles } from 'lucide-react';
import { useEffect, useRef } from 'react';
import { ChartMessage } from '@/components/agent/chart-message';
import { HtmlMessage } from '@/components/agent/html-message';
import { TableMessage } from '@/components/agent/table-message';
import type { Artifact, ChatMessage } from '@/lib/agent-stream';
import { cn } from '@/lib/utils';

function messageArtifacts(message: ChatMessage): Artifact[] {
    if (message.artifacts && message.artifacts.length > 0) {
        return message.artifacts;
    }

    return (message.charts ?? []).map((chart) => ({
        kind: 'chart' as const,
        spec: chart,
    }));
}

export function ChatMessages({
    messages,
    streaming,
    currency,
    onRetry,
}: {
    messages: ChatMessage[];
    streaming?: boolean;
    currency?: string;
    onRetry?: (message: string) => void;
}) {
    const containerRef = useRef<HTMLDivElement>(null);
    const shouldFollowRef = useRef(true);

    useEffect(() => {
        const container = containerRef.current;

        if (!container || !shouldFollowRef.current) {
            return;
        }

        container.scrollTo({
            top: container.scrollHeight,
            behavior: streaming ? 'auto' : 'smooth',
        });
    }, [messages, streaming]);

    if (messages.length === 0) {
        return null;
    }

    return (
        <div
            ref={containerRef}
            className="mx-auto flex h-full w-full max-w-3xl flex-col gap-6 overflow-y-auto px-4 py-6"
            onScroll={(event) => {
                const element = event.currentTarget;
                shouldFollowRef.current =
                    element.scrollHeight -
                        element.scrollTop -
                        element.clientHeight <
                    96;
            }}
            aria-live={streaming ? 'polite' : undefined}
            aria-busy={streaming}
        >
            {messages.map((message, index) => {
                const isUser = message.role === 'user';
                const isLast = index === messages.length - 1;
                const artifacts = messageArtifacts(message);

                return (
                    <div
                        key={message.id}
                        className={cn(
                            'flex flex-col gap-2',
                            isUser ? 'items-end' : 'items-start',
                        )}
                    >
                        <div
                            className={cn(
                                'max-w-[90%] rounded-2xl px-4 py-3 text-sm leading-relaxed wrap-anywhere whitespace-pre-wrap',
                                isUser
                                    ? 'bg-primary text-primary-foreground'
                                    : 'bg-muted text-foreground',
                            )}
                        >
                            {message.content ||
                                (streaming && isLast && !isUser ? '…' : '')}
                        </div>
                        {!isUser &&
                            artifacts.map((artifact, artifactIndex) => {
                                const artifactId = `${message.id}-artifact-${artifactIndex}`;

                                if (artifact.kind === 'chart') {
                                    return (
                                        <ChartMessage
                                            key={artifactId}
                                            artifactId={artifactId}
                                            chart={artifact.spec}
                                            currency={currency}
                                        />
                                    );
                                }

                                if (artifact.kind === 'table') {
                                    return (
                                        <TableMessage
                                            key={artifactId}
                                            artifactId={artifactId}
                                            table={artifact.spec}
                                            currency={currency}
                                        />
                                    );
                                }

                                return (
                                    <HtmlMessage
                                        key={artifactId}
                                        artifactId={artifactId}
                                        htmlSpec={artifact.spec}
                                    />
                                );
                            })}
                        {message.failed && onRetry && (
                            <button
                                type="button"
                                className="text-xs text-destructive underline underline-offset-4"
                                onClick={() => onRetry(message.content)}
                            >
                                Retry
                            </button>
                        )}
                    </div>
                );
            })}
            {streaming && (
                <output
                    className="flex items-center gap-3 text-xs text-muted-foreground"
                    aria-label="Monily is analyzing your financial data"
                >
                    <span className="relative flex size-7 items-center justify-center rounded-full bg-primary/10 text-primary">
                        <Sparkles className="size-3.5 animate-pulse motion-reduce:animate-none" />
                        <span className="absolute inset-0 animate-ping rounded-full bg-primary/20 motion-reduce:animate-none" />
                    </span>
                    <span>
                        <span className="font-medium text-foreground">
                            Monily is analyzing your financial data
                        </span>
                        <span
                            className="ml-1 inline-flex gap-0.5"
                            aria-hidden="true"
                        >
                            <span className="animate-bounce motion-reduce:animate-none">
                                .
                            </span>
                            <span className="animate-bounce [animation-delay:150ms] motion-reduce:animate-none">
                                .
                            </span>
                            <span className="animate-bounce [animation-delay:300ms] motion-reduce:animate-none">
                                .
                            </span>
                        </span>
                    </span>
                </output>
            )}
        </div>
    );
}
