'use client';

import React from 'react';
import { Bot, Loader2, Paperclip, User } from 'lucide-react';

import type { ChatMessage, ProcessArtifact, ProcessEvent, ProcessRun } from '@/types';
import { getAccessToken, getFileUrl } from '@/lib/api';
import { AgentTeamBlock } from '@/components/chat-workbench/AgentTeamBlock';
import { MarkdownContent } from '@/components/chat-workbench/MarkdownContent';
import { ScrollArea } from '@/components/ui/scroll-area';

function AuthImage({ src, alt, className }: { src: string; alt: string; className?: string }) {
  const [blobUrl, setBlobUrl] = React.useState<string | null>(null);

  React.useEffect(() => {
    const token = getAccessToken();
    const headers: Record<string, string> = {};
    if (token) headers.Authorization = `Bearer ${token}`;

    let revoke: string | null = null;
    fetch(src, { headers })
      .then((res) => res.blob())
      .then((blob) => {
        revoke = URL.createObjectURL(blob);
        setBlobUrl(revoke);
      })
      .catch(() => {});

    return () => {
      if (revoke) URL.revokeObjectURL(revoke);
    };
  }, [src]);

  if (!blobUrl) return <div className="w-32 h-32 bg-muted animate-pulse rounded" />;
  return <img src={blobUrl} alt={alt} className={className} loading="lazy" decoding="async" />;
}

function MessageBubble({ message }: { message: ChatMessage }) {
  const isUser = message.role === 'user';
  const textContent = typeof message.content === 'string' ? message.content : String(message.content || '');

  return (
    <div className={`flex gap-3 ${isUser ? 'justify-end' : ''}`}>
      {!isUser && (
        <div className="w-7 h-7 rounded-full bg-primary/10 flex items-center justify-center flex-shrink-0 mt-0.5">
          <Bot className="w-4 h-4 text-primary" />
        </div>
      )}
      <div
        className={`rounded-xl px-4 py-3 max-w-[88%] shadow-sm ${
          isUser
            ? 'bg-primary text-primary-foreground'
            : 'bg-card border border-border/80'
        }`}
      >
        {message.attachments && message.attachments.length > 0 && (
          <div className="mb-2 space-y-2">
            {message.attachments.map((att) => {
              const fileUrl = getFileUrl(att.file_id);
              if (att.content_type.startsWith('image/')) {
                return (
                  <a key={att.file_id} href={fileUrl} target="_blank" rel="noopener noreferrer">
                    <AuthImage
                      src={fileUrl}
                      alt={att.name}
                      className="max-w-xs max-h-60 rounded border border-border/50 cursor-pointer hover:opacity-90"
                    />
                  </a>
                );
              }
              return (
                <a
                  key={att.file_id}
                  href={fileUrl}
                  download={att.name}
                  className={`flex items-center gap-2 px-3 py-2 rounded-md text-sm ${
                    isUser
                      ? 'bg-primary-foreground/10 hover:bg-primary-foreground/20'
                      : 'bg-muted hover:bg-muted/80'
                  }`}
                >
                  <Paperclip className="w-3.5 h-3.5 flex-shrink-0" />
                  <span className="truncate">{att.name}</span>
                  {att.size && (
                    <span className="text-xs opacity-70 flex-shrink-0">
                      {att.size > 1024 * 1024
                        ? `${(att.size / 1024 / 1024).toFixed(1)}MB`
                        : `${(att.size / 1024).toFixed(0)}KB`}
                    </span>
                  )}
                </a>
              );
            })}
          </div>
        )}

        {isUser ? (
          <p className="text-sm whitespace-pre-wrap">{textContent}</p>
        ) : (
          <MarkdownContent content={textContent} />
        )}
      </div>
      {isUser && (
        <div className="w-7 h-7 rounded-full bg-secondary flex items-center justify-center flex-shrink-0 mt-0.5">
          <User className="w-4 h-4" />
        </div>
      )}
    </div>
  );
}

type AgentTeamGroup = {
  rootRun: ProcessRun;
  memberRuns: ProcessRun[];
  startedAt: string;
};

function parseTimelineTime(value?: string | null): number | null {
  if (!value) return null;
  const parsed = new Date(value).getTime();
  return Number.isFinite(parsed) ? parsed : null;
}

function buildAgentTeamGroups(processRuns: ProcessRun[]): AgentTeamGroup[] {
  const runMap = new Map(processRuns.map((run) => [run.run_id, run]));
  const groups = new Map<string, AgentTeamGroup>();

  for (const run of processRuns) {
    if (run.actor_type !== 'agent') {
      continue;
    }

    let root = run;
    const seen = new Set<string>([run.run_id]);
    let parentId = run.parent_run_id ?? null;
    while (parentId) {
      const parent = runMap.get(parentId);
      if (!parent || seen.has(parent.run_id)) {
        break;
      }
      root = parent;
      seen.add(parent.run_id);
      parentId = parent.parent_run_id ?? null;
    }

    const existing = groups.get(root.run_id);
    if (existing) {
      existing.memberRuns.push(run);
      continue;
    }
    groups.set(root.run_id, {
      rootRun: root,
      memberRuns: [run],
      startedAt: root.started_at || run.started_at,
    });
  }

  return Array.from(groups.values())
    .map((group) => ({
      ...group,
      memberRuns: [...group.memberRuns].sort((a: ProcessRun, b: ProcessRun) => {
        const at = parseTimelineTime(a.started_at) ?? 0;
        const bt = parseTimelineTime(b.started_at) ?? 0;
        return at - bt;
      }),
    }))
    .sort((a, b) => {
      const at = parseTimelineTime(a.startedAt) ?? 0;
      const bt = parseTimelineTime(b.startedAt) ?? 0;
      return at - bt;
    });
}

export function MessageList({
  messages,
  isThinking,
  messagesEndRef,
  viewportRef,
  processRuns,
  processEvents,
  processArtifacts,
  selectedRunId,
  onSelectRun,
  onCancelRun,
}: {
  messages: ChatMessage[];
  isThinking: boolean;
  messagesEndRef: React.RefObject<HTMLDivElement>;
  viewportRef: React.RefObject<HTMLDivElement>;
  processRuns: ProcessRun[];
  processEvents: ProcessEvent[];
  processArtifacts: ProcessArtifact[];
  selectedRunId: string | null;
  onSelectRun: (runId: string) => void;
  onCancelRun: (runId: string) => void;
}) {
  const teamGroups = React.useMemo(() => buildAgentTeamGroups(processRuns), [processRuns]);
  const timelineItems = React.useMemo(() => {
    const messageItems = messages.map((message, index) => ({
      kind: 'message' as const,
      key: `${message.role}:${message.timestamp || index}:${index}`,
      sortTime: parseTimelineTime(message.timestamp) ?? Number.MAX_SAFE_INTEGER / 2 + index,
      order: index,
      message,
    }));
    const teamItems = teamGroups.map((group, index) => ({
      kind: 'team' as const,
      key: `team:${group.rootRun.run_id}`,
      sortTime: parseTimelineTime(group.startedAt) ?? Number.MAX_SAFE_INTEGER / 2 + messages.length + index,
      order: messages.length + index,
      group,
    }));

    return [...messageItems, ...teamItems].sort((a, b) => {
      if (a.sortTime !== b.sortTime) {
        return a.sortTime - b.sortTime;
      }
      return a.order - b.order;
    });
  }, [messages, teamGroups]);

  return (
    <ScrollArea className="h-full px-4" viewportRef={viewportRef}>
      <div className="max-w-6xl mx-auto py-4 space-y-4">
        {messages.length === 0 && teamGroups.length === 0 && !isThinking && (
          <div className="flex flex-col items-center justify-center py-20 text-muted-foreground">
            <Bot className="w-12 h-12 mb-4 opacity-50" />
            <p className="text-lg font-medium">Boardware Agent Sandbox</p>
            <p className="text-sm">发送消息开始对话</p>
          </div>
        )}

        {timelineItems.map((item) =>
          item.kind === 'message' ? (
            <MessageBubble key={item.key} message={item.message} />
          ) : (
            <AgentTeamBlock
              key={item.key}
              rootRun={item.group.rootRun}
              memberRuns={item.group.memberRuns}
              events={processEvents}
              artifacts={processArtifacts}
              selectedRunId={selectedRunId}
              onSelectRun={onSelectRun}
              onCancelRun={onCancelRun}
            />
          )
        )}

        {isThinking && (
          <div className="flex items-center gap-2 text-muted-foreground px-1">
            <Bot className="w-5 h-5" />
            <Loader2 className="w-4 h-4 animate-spin" />
            <span className="text-sm">思考中...</span>
          </div>
        )}

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