import { StopCircle, Terminal, Zap } from "lucide-react";
import { memo, useState, type JSX } from "react";
import ReactMarkdown from "react-markdown";
import type { OpenAIResponse, OpenAIToolCall } from "../../../../proxy/schemas";
import { formatTokens } from "../../../../lib/utils";
import { Badge } from "../../../ui/badge";
import { JsonViewer } from "../../../ui/json-viewer";
import { safeJsonValue } from "../../../ui/json-viewer-bulk";
import { ScrollArea } from "../../../ui/scroll-area";
import { Separator } from "../../../ui/separator";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../../../ui/collapsible";
import { ChevronDown, ChevronRight } from "lucide-react";
import { ThinkingBlock } from "../anthropic/ContentBlocks";
import { extractThinkingFromContent } from "../anthropic/thinkingExtract";

// Re-export for use in other components
export { extractThinkingFromContent } from "../anthropic/thinkingExtract";

/** Best-effort JSON parse of an OpenAI `function.arguments` string. Returns
 *  the parsed object, or `null` on parse failure so the renderer can fall
 *  back to showing the raw string. */
function parseToolArguments(raw: string | undefined): unknown {
  if (raw === undefined || raw === "") return {};
  try {
    return JSON.parse(raw);
  } catch {
    return null;
  }
}

/** One collapsible tool_use row, mirroring the Anthropic ToolUseBlock visual
 *  treatment (Terminal icon, blue accent, name as a Badge, JSON input in a
 *  scrollable JsonViewer). */
function OpenAIToolCallBlock({ call }: { call: OpenAIToolCall }): JSX.Element {
  const [open, setOpen] = useState(false);
  const name = call.function.name ?? "(unnamed tool)";
  const parsed = parseToolArguments(call.function.arguments);

  return (
    <Collapsible open={open} onOpenChange={setOpen}>
      <div className="border-l-2 border-blue-500/40 my-1">
        <CollapsibleTrigger className="flex items-center gap-1.5 px-3 py-1 w-full text-left cursor-pointer hover:bg-blue-500/5 transition-colors rounded-r-sm group">
          <Terminal className="size-3.5 text-blue-400 shrink-0" />
          <Badge variant="outline" className="text-[10px] font-mono px-1.5 py-0 h-4">
            {name}
          </Badge>
          {call.id !== undefined && call.id !== "" && (
            <span className="text-[10px] font-mono text-muted-foreground/60 truncate">
              {call.id}
            </span>
          )}
          <span className="flex-1" />
          {open ? (
            <ChevronDown className="size-3 text-muted-foreground" />
          ) : (
            <ChevronRight className="size-3 text-muted-foreground" />
          )}
        </CollapsibleTrigger>
        <CollapsibleContent>
          <div className="px-3 pb-2">
            <ScrollArea className="max-h-[60vh]">
              {parsed === null ? (
                // JSON.parse failed — show the raw string so the user can
                // still see what the model tried to call.
                <pre className="font-mono text-xs whitespace-pre-wrap break-words text-rose-300/90">
                  {call.function.arguments}
                </pre>
              ) : (
                <JsonViewer data={safeJsonValue(parsed)} defaultExpandDepth={0} />
              )}
            </ScrollArea>
          </div>
        </CollapsibleContent>
      </div>
    </Collapsible>
  );
}

export const OpenAIResponseView = memo(function OpenAIResponseView({
  response,
}: {
  response: OpenAIResponse;
}): JSX.Element {
  const choice = response.choices[0];
  const message = choice?.message;
  const toolCalls = message?.tool_calls ?? [];

  return (
    <div className="space-y-3">
      <div className="flex items-center gap-2 flex-wrap">
        <Badge variant="secondary" className="text-[10px] px-1.5 py-0 h-5 font-mono">
          {response.model}
        </Badge>

        {choice?.finish_reason !== null && choice?.finish_reason !== undefined && (
          <Badge
            variant="outline"
            className="text-[10px] px-1.5 py-0 h-5 font-mono flex items-center gap-1"
          >
            <StopCircle className="size-2.5" />
            {choice.finish_reason}
          </Badge>
        )}

        <span className="flex items-center gap-1 text-muted-foreground text-xs">
          <Zap className="size-3" />
          <span className="font-mono tabular-nums">
            {formatTokens(response.usage.prompt_tokens ?? 0)} in /{" "}
            {formatTokens(response.usage.completion_tokens ?? 0)} out
          </span>
        </span>
      </div>

      <Separator className="opacity-50" />

      <div className="space-y-2">
        {message?.reasoning_content !== null &&
          message?.reasoning_content !== undefined &&
          message.reasoning_content.length > 0 && (
            <ThinkingBlock thinking={message.reasoning_content} />
          )}
        {message?.content !== null &&
          message?.content !== undefined &&
          message.content.length > 0 &&
          (() => {
            // Extract thinking content from tag-wrapped content if no reasoning_content field
            const hasReasoningField =
              message.reasoning_content !== null &&
              message.reasoning_content !== undefined &&
              message.reasoning_content.length > 0;
            const { thinking, remainingText } = extractThinkingFromContent(message.content);
            return (
              <div className="space-y-2">
                {/* Show thinking from tags only if no reasoning_content field */}
                {thinking !== null && !hasReasoningField && <ThinkingBlock thinking={thinking} />}
                {remainingText.length > 0 && (
                  <div className="prose prose-sm dark:prose-invert max-w-none [&_pre]:bg-muted [&_pre]:text-foreground [&_code]:text-[0.8em] [&_p]:my-1 [&_ul]:my-1 [&_ol]:my-1">
                    <ReactMarkdown>{remainingText}</ReactMarkdown>
                  </div>
                )}
              </div>
            );
          })()}
        {toolCalls.map((call, i) => (
          // biome-ignore lint/suspicious/noArrayIndexKey: tool_calls is the positionally stable list from the response
          <OpenAIToolCallBlock key={call.id ?? `tc-${i}`} call={call} />
        ))}
        {message?.function_call !== null && message?.function_call !== undefined && (
          <div className="border border-blue-500/30 rounded-md p-3 bg-blue-500/5">
            <div className="text-xs text-blue-400 font-mono mb-1">function_call</div>
            <div className="font-mono text-xs">
              <span className="text-blue-300">{message.function_call.name}</span>
              <span className="text-muted-foreground">({message.function_call.arguments})</span>
            </div>
          </div>
        )}
        {(message?.content === null ||
          message?.content === undefined ||
          message.content.length === 0) &&
          (message?.reasoning_content === null ||
            message?.reasoning_content === undefined ||
            message.reasoning_content.length === 0) &&
          (message?.function_call === null || message?.function_call === undefined) &&
          toolCalls.length === 0 && (
            <p className="text-xs text-muted-foreground italic">Empty response content</p>
          )}
      </div>
    </div>
  );
});
