import { useState, useEffect, useRef, useCallback, memo } from 'react';
import { Sparkles } from 'lucide-react';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import { motion, AnimatePresence } from 'framer-motion';
import { trpc } from '@/lib/trpc';
import { ChatInputBox } from '@/components/ai/ChatInputBox';
import { Skeleton } from '@/components/ui/skeleton';
import { ScrollArea } from '@/components/ui/scroll-area';
import { useTranslation } from 'react-i18next';

interface ChatMessage {
  id: string;
  role: 'assistant' | 'user';
  content: string;
  error?: boolean;
}

interface BriefingResult {
  briefingMarkdown: string;
  canvasDraft: string | null;
  canvasKind: string | null;
}

interface TaskBriefChatProps {
  taskId: string;
  projectId?: string | null;
  /** Pre-loaded briefing from DB/session cache. Null triggers research. */
  initialBriefing: BriefingResult | null;
  onBriefingReady: (result: BriefingResult) => void;
}

export function TaskBriefChat({ taskId, projectId, initialBriefing, onBriefingReady }: TaskBriefChatProps) {
  const { t } = useTranslation();
  const sessionId = useRef(crypto.randomUUID()).current;
  const cacheKey = `brief-${taskId}`;

  // Load persisted follow-up messages — only when briefing already exists
  const chatHistoryQuery = trpc.ai.getTaskBriefChats.useQuery(
    { taskId },
    { enabled: !!initialBriefing },
  );
  const saveChatMutation = trpc.ai.saveTaskBriefChat.useMutation();

  const [messages, setMessages] = useState<ChatMessage[]>(() => {
    if (initialBriefing) {
      return [{ id: 'briefing', role: 'assistant', content: initialBriefing.briefingMarkdown }];
    }
    return [];
  });
  // True until DB history is applied (or skipped when no briefing)
  const [historyLoaded, setHistoryLoaded] = useState(!initialBriefing);
  const [isResearching, setIsResearching] = useState(!initialBriefing);
  const [isStreaming, setIsStreaming] = useState(false);
  const [streamingContent, setStreamingContent] = useState('');
  const [briefingText, setBriefingText] = useState<string>(initialBriefing?.briefingMarkdown ?? '');

  const streamingRef = useRef('');
  const messagesEndRef = useRef<HTMLDivElement>(null);

  const researchMutation = trpc.ai.taskBriefResearch.useMutation();
  const chatMutation = trpc.ai.chat.useMutation();

  // Merge DB history into messages once query settles
  useEffect(() => {
    if (historyLoaded) return;
    if (chatHistoryQuery.isLoading) return;
    setHistoryLoaded(true);
    if (!chatHistoryQuery.data || chatHistoryQuery.data.length === 0) return;
    setMessages([
      { id: 'briefing', role: 'assistant', content: initialBriefing!.briefingMarkdown },
      ...chatHistoryQuery.data.map((m) => ({
        id: m.id,
        role: m.role as 'user' | 'assistant',
        content: m.content,
        error: !!m.isError,
      })),
    ]);
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [chatHistoryQuery.isLoading, chatHistoryQuery.data]);

  // Auto-scroll on new content
  useEffect(() => {
    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  }, [messages, streamingContent]);

  // Research phase: fire on mount if no initial briefing
  useEffect(() => {
    if (initialBriefing) return;

    const requestId = crypto.randomUUID();
    let accumulated = '';

    const unsubscribe = window.electronAI.onStreamEvent((event) => {
      if (event.requestId !== requestId) return;

      switch (event.type) {
        case 'stream_text':
          accumulated += event.chunk;
          streamingRef.current = accumulated;
          setStreamingContent(accumulated);
          break;

        case 'stream_end': {
          const finalText = stripCanvas(streamingRef.current);
          const mutations = event.mutations as Array<Record<string, unknown>> | undefined;
          const canvasMut = mutations?.find((m) => m.type === 'canvas_draft');
          const canvasDraft = (canvasMut?.content as string) ?? null;
          const canvasKind = (canvasMut?.kind as string) ?? null;

          setBriefingText(finalText);
          setMessages([{ id: 'briefing', role: 'assistant', content: finalText }]);
          setStreamingContent('');
          streamingRef.current = '';
          setIsResearching(false);
          setHistoryLoaded(true);

          onBriefingReady({ briefingMarkdown: finalText, canvasDraft, canvasKind });
          unsubscribe();
          break;
        }
      }
    });

    researchMutation.mutate({ taskId, requestId });
    return () => unsubscribe();
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const handleSend = useCallback((message: string) => {
    const trimmed = message.trim();
    if (!trimmed || isStreaming || isResearching || !historyLoaded) return;

    const userMsg: ChatMessage = { id: crypto.randomUUID(), role: 'user', content: trimmed };
    setMessages((prev) => [...prev, userMsg]);
    saveChatMutation.mutate({ id: userMsg.id, taskId, role: 'user', content: trimmed, createdAt: Date.now() });

    setIsStreaming(true);
    setStreamingContent('');
    streamingRef.current = '';

    const requestId = crypto.randomUUID();

    const unsubscribe = window.electronAI.onStreamEvent((event) => {
      if (event.requestId !== requestId) return;

      switch (event.type) {
        case 'stream_text':
          streamingRef.current += event.chunk;
          setStreamingContent(streamingRef.current);
          break;

        case 'stream_end': {
          const finalContent = streamingRef.current;
          const assistantMsgId = crypto.randomUUID();
          setMessages((prev) => [...prev, { id: assistantMsgId, role: 'assistant', content: finalContent }]);
          if (finalContent) {
            saveChatMutation.mutate({ id: assistantMsgId, taskId, role: 'assistant', content: finalContent, createdAt: Date.now() });
          }
          setStreamingContent('');
          streamingRef.current = '';
          setIsStreaming(false);
          unsubscribe();
          break;
        }
      }
    });

    const conversationHistory = messages.slice(-20).map((m) => ({
      role: m.role as 'user' | 'assistant',
      content: m.content,
    }));

    chatMutation.mutate(
      {
        requestId,
        message: trimmed,
        conversationHistory,
        sessionId,
        mode: 'floating',
        scope: { type: 'task', id: taskId },
        briefMode: true,
        briefingContext: briefingText || undefined,
      },
      {
        onSuccess: (data) => {
          if (data.error) {
            unsubscribe();
            setMessages((prev) => [...prev, {
              id: crypto.randomUUID(), role: 'assistant', content: data.error!, error: true,
            }]);
            setStreamingContent('');
            streamingRef.current = '';
            setIsStreaming(false);
          } else {
            unsubscribe();
            const content = streamingRef.current;
            if (content) {
              const assistantMsgId = crypto.randomUUID();
              setMessages((prev) => [...prev, { id: assistantMsgId, role: 'assistant', content }]);
              saveChatMutation.mutate({ id: assistantMsgId, taskId, role: 'assistant', content, createdAt: Date.now() });
            }
            setStreamingContent('');
            streamingRef.current = '';
            setIsStreaming(false);
          }
        },
        onError: (err) => {
          unsubscribe();
          setMessages((prev) => [...prev, {
            id: crypto.randomUUID(), role: 'assistant', content: err.message || 'An unexpected error occurred.', error: true,
          }]);
          setStreamingContent('');
          streamingRef.current = '';
          setIsStreaming(false);
        },
      },
    );
  }, [isStreaming, isResearching, historyLoaded, messages, taskId, sessionId, briefingText, chatMutation, saveChatMutation]);

  const isInputBlocked = isStreaming || isResearching || !historyLoaded;

  return (
    <div className="flex flex-col h-full">
      <ScrollArea className="flex-1 min-h-0">
        <div className="px-5 py-5 space-y-5">
          {/* Researching state */}
          {isResearching && (
            <div>
              <div className="flex items-end gap-2.5 mb-1">
                <Sparkles size={24} className="text-foreground" />
                <span className="text-xl font-semibold leading-none">
                  adiuv<span className="font-bold text-primary">AI</span>
                </span>
              </div>
              <div className="pl-[32px] space-y-2">
                {streamingContent ? (
                  <BriefMarkdown content={stripCanvas(streamingContent, true)} />
                ) : (
                  <>
                    <p className="text-sm text-muted-foreground">{t('brief.researching')}</p>
                    <Skeleton className="h-4 w-3/4" />
                    <Skeleton className="h-4 w-1/2" />
                    <Skeleton className="h-4 w-2/3" />
                  </>
                )}
              </div>
            </div>
          )}

          {/* Message list */}
          <AnimatePresence initial={false}>
            {messages.map((msg) => (
              <motion.div
                key={msg.id}
                initial={{ opacity: 0, y: 8 }}
                animate={{ opacity: 1, y: 0 }}
                transition={{ type: 'spring', stiffness: 400, damping: 30 }}
              >
                {msg.role === 'assistant' ? (
                  <div>
                    <div className="flex items-end gap-2.5 mb-1">
                      <Sparkles size={24} className="text-foreground" />
                      <span className="text-xl font-semibold leading-none">
                        adiuv<span className="font-bold text-primary">AI</span>
                      </span>
                    </div>
                    <div className={`pl-[32px] ${msg.error ? 'text-destructive' : ''}`}>
                      <BriefMarkdown content={msg.content} />
                    </div>
                  </div>
                ) : (
                  <div className="flex justify-end">
                    <div className="max-w-[80%] rounded-2xl bg-muted px-4 py-2.5 text-sm">
                      {msg.content}
                    </div>
                  </div>
                )}
              </motion.div>
            ))}
          </AnimatePresence>

          {/* Streaming follow-up */}
          {isStreaming && (
            <motion.div
              initial={{ opacity: 0, y: 8 }}
              animate={{ opacity: 1, y: 0 }}
              transition={{ type: 'spring', stiffness: 400, damping: 30 }}
            >
              <div className="flex items-end gap-2.5 mb-1">
                <Sparkles size={24} className="text-foreground" />
                <span className="text-xl font-semibold leading-none">
                  adiuv<span className="font-bold text-primary">AI</span>
                </span>
              </div>
              <div className="pl-[32px]">
                {streamingContent ? (
                  <BriefMarkdown content={streamingContent} />
                ) : (
                  <div className="space-y-2">
                    <Skeleton className="h-4 w-48" />
                    <Skeleton className="h-4 w-32" />
                  </div>
                )}
              </div>
            </motion.div>
          )}

          <div ref={messagesEndRef} />
        </div>
      </ScrollArea>

      {/* Input */}
      <div className="shrink-0 px-4 pb-4 pt-2">
        <div className="relative rounded-2xl bg-background/70 backdrop-blur-xl border border-border/50 shadow-md ring-1 ring-border/20 transition-shadow focus-within:shadow-lg focus-within:border-ring/50">
          <ChatInputBox
            cacheKey={cacheKey}
            isStreaming={isInputBlocked}
            onSend={handleSend}
            placeholder={t('brief.inputPlaceholder')}
          />
        </div>
      </div>
    </div>
  );
}

// Strip <canvas> block — canvas goes to right panel, not chat text
const CANVAS_COMPLETE_RE = /<canvas\b[^>]*>[\s\S]*?<\/canvas>/gi;
const CANVAS_PARTIAL_RE = /<canvas\b[\s\S]*$/i;

function stripCanvas(text: string, partial = false): string {
  if (partial) return text.replace(CANVAS_PARTIAL_RE, '');
  return text.replace(CANVAS_COMPLETE_RE, '').trim();
}

const BriefMarkdown = memo(function BriefMarkdown({ content }: { content: string }) {
  return (
    <div className="prose prose-sm dark:prose-invert max-w-none text-foreground text-sm">
      <ReactMarkdown remarkPlugins={[remarkGfm]}>{content}</ReactMarkdown>
    </div>
  );
});
