/**
 * OrchestratorView - Chat interface for multi-agent orchestration
 * Features: Multi-agent conversation display, termination conditions, agent tracking
 */

import { useState, useCallback, useMemo, useEffect } from "react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { ChatBase } from "@/components/shared/chat-base";
import { SessionSwitcher } from "@/components/shared/session-switcher";
import { ExampleTasksDisplay } from "@/components/shared/example-tasks-display";
import { ContextInspector } from "@/components/shared/context-inspector";
import {
  Users,
  Bot,
  MessageSquare,
  StopCircle,
  ArrowUp,
  ArrowDown,
  Eye,
  ChevronRight,
  ChevronDown,
  ChevronUp,
  DollarSign,
  Sparkles,
  BotMessageSquare,
} from "lucide-react";
import { apiClient } from "@/services/api";
import { useEntityExecution } from "@/hooks/useEntityExecution";
import { OrchestratorMessageHandler } from "@/hooks/messageHandlers";
import { formatCost } from "@/lib/format-utils";
import { MessageRenderer } from "@/components/message_renderer";
import type {
  OrchestratorInfo,
  Message,
  StreamEvent,
  SessionInfo,
} from "@/types";

interface OrchestratorViewProps {
  selectedOrchestrator: OrchestratorInfo;
  userId?: string;
  currentSession?: SessionInfo;
  onSessionChange: (session: SessionInfo) => void;
  onDebugEvent: (event: StreamEvent) => void;
}

interface OrchestratorTurn {
  userMessage: Message;
  assistantMessages: Message[];
}

interface OrchestratorDisplayItem {
  message: Message;
  turnKey?: string;
  thinkingMessages?: Message[];
  incompleteStopReason?: string | null;
  isThinkingLive?: boolean;
}

const CONTROL_SIGNALS = new Set(["APPROVED", "TERMINATE"]);

function isControlOnlyMessage(message: Message): boolean {
  if (message.role !== "assistant") {
    return false;
  }
  return CONTROL_SIGNALS.has(message.content.trim().toUpperCase());
}

function getPrimaryAssistantMessage(
  assistantMessages: Message[]
): Message | null {
  const preferredMessages = assistantMessages.filter(
    (message) =>
      message.role === "assistant" &&
      !isControlOnlyMessage(message) &&
      message.source !== "reviewer" &&
      message.source !== "system"
  );
  if (preferredMessages.length > 0) {
    return preferredMessages.at(-1) ?? null;
  }

  const fallbackMessages = assistantMessages.filter(
    (message) =>
      message.role === "assistant" &&
      !isControlOnlyMessage(message) &&
      message.source !== "system"
  );
  return fallbackMessages.at(-1) ?? null;
}

function ThinkingDots() {
  return (
    <span className="inline-flex items-center gap-1 text-xs text-muted-foreground">
      <span className="inline-flex gap-1">
        <span className="h-1.5 w-1.5 rounded-full bg-current animate-bounce [animation-delay:-0.3s]" />
        <span className="h-1.5 w-1.5 rounded-full bg-current animate-bounce [animation-delay:-0.15s]" />
        <span className="h-1.5 w-1.5 rounded-full bg-current animate-bounce" />
      </span>
    </span>
  );
}

export function OrchestratorView({
  selectedOrchestrator,
  userId,
  currentSession,
  onSessionChange,
  onDebugEvent,
}: OrchestratorViewProps) {
  const [isContextInspectorOpen, setIsContextInspectorOpen] = useState(false);
  const [isExpanded, setIsExpanded] = useState(false);
  const [expandedThinkingByTurn, setExpandedThinkingByTurn] = useState<
    Record<string, boolean>
  >({});

  const messageHandler = useMemo(() => new OrchestratorMessageHandler(), []);

  const {
    messages,
    isStreaming,
    sessionTotalUsage,
    currentAgentSpeaking,
    finalResult,
    stopReason,
    handleSendMessage,
    handleStop,
    handleClearMessages,
  } = useEntityExecution({
    entityId: selectedOrchestrator.id,
    entityType: "orchestrator",
    entityName: selectedOrchestrator.name || selectedOrchestrator.id,
    userId,
    currentSession,
    onDebugEvent,
    onSessionChange,
    messageHandler,
    supportsToolApproval: false,
    supportsTokenStreaming: false,
  });

  useEffect(() => {
    setExpandedThinkingByTurn({});
  }, [currentSession?.id, selectedOrchestrator.id]);

  const handleLocalSessionChange = useCallback(
    async (sessionId: string | undefined) => {
      if (sessionId) {
        try {
          const sessions = await apiClient.getSessions(selectedOrchestrator.id, userId);
          const session = sessions.find((candidate) => candidate.id === sessionId);
          if (session) {
            onSessionChange(session);
          }
        } catch (error) {
          console.error("Failed to load session:", error);
        }
      }
    },
    [selectedOrchestrator.id, userId, onSessionChange]
  );

  const showSessionUsage =
    sessionTotalUsage.tokens_input > 0 ||
    sessionTotalUsage.tokens_output > 0 ||
    sessionTotalUsage.cost_estimate > 0;

  const incompleteStopReason = useMemo(() => {
    if (!stopReason) {
      return null;
    }
    return /(maximum|cancel|failed|error)/i.test(stopReason) ? stopReason : null;
  }, [stopReason]);

  const turns = useMemo<OrchestratorTurn[]>(() => {
    const nextTurns: OrchestratorTurn[] = [];
    let currentTurn: OrchestratorTurn | null = null;

    for (const message of messages) {
      if (message.role === "user") {
        if (currentTurn) {
          nextTurns.push(currentTurn);
        }
        currentTurn = {
          userMessage: message,
          assistantMessages: [],
        };
        continue;
      }

      if (message.role === "assistant" && currentTurn) {
        currentTurn.assistantMessages.push(message);
      }
    }

    if (currentTurn) {
      nextTurns.push(currentTurn);
    }

    return nextTurns;
  }, [messages]);

  const displayItems = useMemo<OrchestratorDisplayItem[]>(() => {
    const items: OrchestratorDisplayItem[] = [];

    turns.forEach((turn, turnIndex) => {
      const turnKey =
        turn.userMessage.timestamp ??
        `${selectedOrchestrator.id}-${turnIndex}-${turn.userMessage.content}`;
      const primaryAssistant = getPrimaryAssistantMessage(turn.assistantMessages);
      const isLatestTurn = turnIndex === turns.length - 1;
      const isLiveTurn = isLatestTurn && isStreaming;
      const primaryContent = isLiveTurn
        ? "Thinking"
        : isLatestTurn
          ? finalResult ?? primaryAssistant?.content ?? null
          : primaryAssistant?.content ?? null;

      items.push({
        message: turn.userMessage,
        turnKey,
      });

      if (!primaryContent && !turn.assistantMessages.length && !isLiveTurn) {
        return;
      }

      items.push({
        message: {
          role: "assistant",
          content: primaryContent ?? "Thinking",
          source: selectedOrchestrator.name || selectedOrchestrator.id,
        },
        turnKey,
        thinkingMessages: turn.assistantMessages,
        incompleteStopReason: isLatestTurn ? incompleteStopReason : null,
        isThinkingLive: isLiveTurn,
      });
    });

    return items;
  }, [
    finalResult,
    incompleteStopReason,
    isStreaming,
    selectedOrchestrator.id,
    selectedOrchestrator.name,
    turns,
  ]);

  const displayMessages = useMemo(
    () => displayItems.map((item) => item.message),
    [displayItems]
  );

  const toggleThinking = useCallback((turnKey: string) => {
    setExpandedThinkingByTurn((prev) => ({
      ...prev,
      [turnKey]: !prev[turnKey],
    }));
  }, []);

  const renderDisplayMessage = useCallback(
    ({
      message,
      index,
      isStreaming: isMessageStreaming,
      usage,
    }: {
      message: Message;
      index: number;
      isStreaming: boolean;
      usage?: {
        tokens_input: number;
        tokens_output: number;
        cost_estimate?: number;
      };
    }) => {
      const displayItem = displayItems[index];
      if (message.role !== "assistant" || !displayItem?.turnKey) {
        return null;
      }

      const isThinkingExpanded = Boolean(
        expandedThinkingByTurn[displayItem.turnKey]
      );
      const thinkingMessages = displayItem.thinkingMessages ?? [];
      const showThinkingToggle =
        displayItem.isThinkingLive || thinkingMessages.length > 0;

      return (
        <div className="flex gap-3">
          <div className="flex h-8 w-8 shrink-0 select-none items-center justify-center rounded-md border bg-muted">
            <Bot className="h-4 w-4" />
          </div>

          <div className="flex max-w-[80%] flex-col items-start space-y-1">
            {message.source && message.source !== "user" && (
              <div className="px-1 text-xs font-medium text-muted-foreground">
                {message.source}
              </div>
            )}

            <div className="w-full space-y-3">
              {showThinkingToggle && (
                <div className="w-full rounded bg-muted px-3 py-2 text-sm">
                  <button
                    type="button"
                    onClick={() => toggleThinking(displayItem.turnKey!)}
                    className="flex w-full items-center justify-between rounded-md border bg-background px-3 py-2 text-left transition-colors hover:bg-accent/40"
                  >
                    <div className="flex items-center gap-2">
                      {isThinkingExpanded ? (
                        <ChevronDown className="h-4 w-4 text-muted-foreground" />
                      ) : (
                        <ChevronRight className="h-4 w-4 text-muted-foreground" />
                      )}
                      <Sparkles className="h-4 w-4 text-muted-foreground" />
                      <span className="text-sm font-medium">Thinking</span>
                      {displayItem.isThinkingLive ? (
                        <>
                          <ThinkingDots />
                        </>
                      ) : (
                        <Badge variant="secondary" className="text-xs">
                          {thinkingMessages.length} turns
                        </Badge>
                      )}
                    </div>
                  </button>

                  {isThinkingExpanded && (
                    <div className="mt-3 rounded-md border bg-background p-3">
                      {displayItem.incompleteStopReason && (
                        <div className="mb-3 rounded-md border border-amber-300 bg-amber-50 px-3 py-2 text-sm text-amber-900 dark:border-amber-800 dark:bg-amber-950/30 dark:text-amber-200">
                          {displayItem.incompleteStopReason}
                        </div>
                      )}
                      <div className="space-y-3">
                        {thinkingMessages.map((thinkingMessage, thinkingIndex) => (
                          <div
                            key={`${displayItem.turnKey}-${thinkingMessage.source}-${thinkingIndex}`}
                            className="space-y-1"
                          >
                            <div className="flex items-center gap-2 text-xs font-medium text-muted-foreground">
                              <BotMessageSquare className="h-3 w-3" />
                              <span>{thinkingMessage.source}</span>
                            </div>
                            <div className="rounded-md border bg-card px-3 py-2 text-sm">
                              <MessageRenderer message={thinkingMessage} />
                            </div>
                          </div>
                        ))}
                        {displayItem.isThinkingLive && currentAgentSpeaking && (
                          <div className="space-y-1 animate-in fade-in-50 duration-150">
                            <div className="flex items-center gap-2 text-xs font-medium text-muted-foreground">
                              <BotMessageSquare className="h-3 w-3" />
                              <span>{currentAgentSpeaking}</span>
                              <ThinkingDots />
                            </div>
                            <div className="rounded-md border border-dashed bg-card px-3 py-2 text-sm text-muted-foreground">
                              Thinking
                            </div>
                          </div>
                        )}
                      </div>
                    </div>
                  )}
                </div>
              )}

              {!displayItem.isThinkingLive && (
                <div className="w-full rounded bg-muted px-3 py-2 text-sm">
                  <MessageRenderer
                    message={message}
                    isStreaming={isMessageStreaming}
                  />
                </div>
              )}
            </div>

            {usage && (
              <div className="flex items-center gap-2 px-1 text-xs text-muted-foreground">
                <div className="flex items-center gap-1">
                  <ArrowUp className="h-3 w-3" />
                  <span>{usage.tokens_input.toLocaleString()}</span>
                </div>
                <div className="flex items-center gap-1">
                  <ArrowDown className="h-3 w-3" />
                  <span>{usage.tokens_output.toLocaleString()}</span>
                </div>
                {usage.cost_estimate !== undefined && usage.cost_estimate > 0 && (
                  <div className="flex items-center gap-1">
                    <DollarSign className="h-3 w-3" />
                    <span>{formatCost(usage.cost_estimate)}</span>
                  </div>
                )}
              </div>
            )}
          </div>
        </div>
      );
    },
    [currentAgentSpeaking, displayItems, expandedThinkingByTurn, toggleThinking]
  );

  const getOrchestratorTypeColor = (type: string) => {
    switch (type.toLowerCase()) {
      case "round_robin":
      case "roundrobinorchestrator":
        return "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300";
      case "ai":
      case "aiorchestrator":
        return "bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300";
      case "plan":
      case "planorchestrator":
        return "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300";
      case "handoff":
      case "handofforchestrator":
        return "bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-300";
      default:
        return "bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-300";
    }
  };

  return (
    <div className="flex h-full flex-col">
      <div className="border-b">
        <div className="space-y-3 p-4">
          <div className="flex items-center justify-between">
            <div className="flex items-center gap-3">
              <Users className="h-6 w-6 text-blue-600" />
              <div className="flex-1">
                <h2 className="text-lg font-semibold">
                  {selectedOrchestrator.name || selectedOrchestrator.id}
                </h2>
                {selectedOrchestrator.description && (
                  <p className="text-sm text-muted-foreground">
                    {selectedOrchestrator.description}
                  </p>
                )}
              </div>
            </div>
            <Badge className={getOrchestratorTypeColor(selectedOrchestrator.orchestrator_type)}>
              {selectedOrchestrator.orchestrator_type}
            </Badge>
          </div>

          <div className="flex items-center justify-between">
            <div className="flex items-center gap-3">
              <SessionSwitcher
                entityId={selectedOrchestrator.id}
                entityType="orchestrator"
                userId={userId}
                currentSessionId={currentSession?.id}
                onSessionChange={handleLocalSessionChange}
              />
              <div className="h-4 w-px bg-border" />
              <div className="flex flex-wrap gap-2">
                <Badge variant="secondary" className="text-xs">
                  <Users className="mr-1 h-3 w-3" />
                  {selectedOrchestrator.agents.length} agents
                </Badge>
                {selectedOrchestrator.termination_conditions.length > 0 && (
                  <Badge variant="secondary" className="text-xs">
                    <StopCircle className="mr-1 h-3 w-3" />
                    {selectedOrchestrator.termination_conditions.length} conditions
                  </Badge>
                )}
                {showSessionUsage && (
                  <>
                    <Badge variant="outline" className="gap-1 text-xs">
                      <ArrowUp className="h-3 w-3" />
                      {sessionTotalUsage.tokens_input.toLocaleString()}
                      <ArrowDown className="h-3 w-3" />
                      {sessionTotalUsage.tokens_output.toLocaleString()}
                    </Badge>
                    {sessionTotalUsage.cost_estimate > 0 && (
                      <Badge variant="outline" className="gap-1 text-xs">
                        <DollarSign className="h-3 w-3" />
                        {formatCost(sessionTotalUsage.cost_estimate)}
                      </Badge>
                    )}
                    <Button
                      variant="ghost"
                      size="sm"
                      onClick={() => setIsContextInspectorOpen(true)}
                      className="h-7 gap-1 px-2 text-xs"
                      title="Inspect context window"
                    >
                      <Eye className="h-3 w-3" />
                      Inspect
                    </Button>
                  </>
                )}
              </div>
            </div>

            <button
              onClick={() => setIsExpanded(!isExpanded)}
              className="rounded-md p-1 transition-colors hover:bg-accent"
              aria-label={isExpanded ? "Hide details" : "Show details"}
            >
              {isExpanded ? (
                <ChevronUp className="h-4 w-4" />
              ) : (
                <ChevronDown className="h-4 w-4" />
              )}
            </button>
          </div>
        </div>

        {isExpanded && (
          <div className="space-y-2 border-t bg-muted/50 px-4 pb-3">
            <div className="space-y-2 pt-2">
              <div className="flex items-center gap-2 text-sm text-muted-foreground">
                <Bot className="h-4 w-4" />
                <span>Participating Agents ({selectedOrchestrator.agents.length})</span>
              </div>
              <div className="flex flex-wrap gap-2">
                {selectedOrchestrator.agents.map((agentName) => (
                  <Badge
                    key={agentName}
                    variant={currentAgentSpeaking === agentName ? "default" : "outline"}
                    className={currentAgentSpeaking === agentName ? "animate-pulse" : ""}
                  >
                    {agentName}
                    {currentAgentSpeaking === agentName && (
                      <MessageSquare className="ml-1 h-3 w-3" />
                    )}
                  </Badge>
                ))}
              </div>
            </div>

            {selectedOrchestrator.termination_conditions.length > 0 && (
              <div className="space-y-2">
                <div className="flex items-center gap-2 text-sm text-muted-foreground">
                  <StopCircle className="h-4 w-4" />
                  <span>Termination Conditions</span>
                </div>
                <div className="flex flex-wrap gap-2">
                  {selectedOrchestrator.termination_conditions.map((condition) => (
                    <Badge key={condition} variant="secondary">
                      {condition}
                    </Badge>
                  ))}
                </div>
              </div>
            )}

            {currentAgentSpeaking && (
              <Card className="border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-950">
                <CardContent className="p-3">
                  <div className="flex items-center gap-2">
                    <div className="h-2 w-2 rounded-full bg-blue-600 animate-pulse" />
                    <span className="text-sm font-medium">
                      {currentAgentSpeaking} is responding...
                    </span>
                  </div>
                </CardContent>
              </Card>
            )}
          </div>
        )}
      </div>

      <div className="flex-1 min-h-0">
        <ChatBase
          messages={displayMessages}
          onSendMessage={handleSendMessage}
          onClearMessages={handleClearMessages}
          onStop={handleStop}
          isStreaming={isStreaming}
          showTypingIndicator={false}
          renderMessage={renderDisplayMessage}
          placeholder={`Start a conversation with ${selectedOrchestrator.agents.length} agents via ${selectedOrchestrator.orchestrator_type} orchestration...`}
          emptyStateTitle="Multi-Agent Orchestration"
          emptyStateDescription={`This orchestrator will coordinate conversations between ${selectedOrchestrator.agents.join(", ")} using ${selectedOrchestrator.orchestrator_type} pattern.`}
          emptyStateCustom={
            selectedOrchestrator.example_tasks && selectedOrchestrator.example_tasks.length > 0 ? (
              <ExampleTasksDisplay
                tasks={selectedOrchestrator.example_tasks}
                entityName={selectedOrchestrator.name || selectedOrchestrator.id}
                onTaskClick={(task) => {
                  const userMessage: Message = {
                    role: "user",
                    content: task,
                    source: "user",
                  };
                  handleSendMessage([userMessage]);
                }}
              />
            ) : null
          }
        />

        <ContextInspector
          messages={messages}
          isOpen={isContextInspectorOpen}
          onClose={() => setIsContextInspectorOpen(false)}
        />
      </div>
    </div>
  );
}
