"use client";

import { useState, useEffect, useCallback, useRef, useMemo } from "react";
import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import {
  Flag,
  Clock,
  Hash,
  ArrowRight,
  Bot,
  User,
  ChevronDown,
  ChevronUp,
  Info,
} from "lucide-react";
import { useInference } from "@/lib/inference";
import { Label } from "@/components/ui/label";
import { cn } from "@/lib/utils";
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@/components/ui/tooltip";

import { API_BASE } from "@/lib/constants";
import ForceDirectedGraph from "./force-directed-graph";
import qwen3Data from "../../results/qwen3.json"
// Simple Switch component since it's not available in the UI components
const Switch = ({
  checked,
  onCheckedChange,
  disabled,
  id,
}: {
  checked: boolean;
  onCheckedChange: (checked: boolean) => void;
  disabled?: boolean;
  id?: string;
}) => {
  return (
    <button
      id={id}
      type="button"
      role="switch"
      aria-checked={checked}
      data-state={checked ? "checked" : "unchecked"}
      disabled={disabled}
      onClick={() => onCheckedChange(!checked)}
      className={cn(
        "focus-visible:ring-ring/50 peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-50",
        checked ? "bg-primary" : "bg-input"
      )}
    >
      <span
        data-state={checked ? "checked" : "unchecked"}
        className={cn(
          "pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform",
          checked ? "translate-x-4" : "translate-x-0"
        )}
      />
    </button>
  );
};

type Message = {
  role: "user" | "assistant" | "game" | "result" | "error";
  content: string;
  metadata?: {
    page?: string;
    links?: string[];
    status?: "playing" | "won" | "lost";
    path?: string[];
  };
};

const buildPrompt = (
  current: string,
  target: string,
  path_so_far: string[],
  links: string[]
) => {
  const formatted_links = links
    .map((link, index) => `${index + 1}. ${link}`)
    .join("\n");
  const path_so_far_str = path_so_far.join(" -> ");

  return `You are playing WikiRun, trying to navigate from one Wikipedia article to another using only links.

IMPORTANT: You MUST put your final answer in <answer>NUMBER</answer> tags, where NUMBER is the link number.
For example, if you want to choose link 3, output <answer>3</answer>.

Current article: ${current}
Target article: ${target}
You have ${links.length} link(s) to choose from:
${formatted_links}

Your path so far: ${path_so_far_str}

Think about which link is most likely to lead you toward the target article.
First, analyze each link briefly and how it connects to your goal, then select the most promising one.

Remember to format your final answer by explicitly writing out the xml number tags like this: <answer>NUMBER</answer>`;
};

interface GameComponentProps {
  player: "me" | "model";
  model?: string;
  maxHops: number;
  startPage: string;
  targetPage: string;
  onReset: () => void;
  maxTokens: number;
  maxLinks: number;
}

export default function GameComponent({
  player,
  model,
  maxHops,
  startPage,
  targetPage,
  onReset,
  maxTokens,
  maxLinks,
}: GameComponentProps) {
  const [currentPage, setCurrentPage] = useState<string>(startPage);
  const [currentPageLinks, setCurrentPageLinks] = useState<string[]>([]);
  const [linksLoading, setLinksLoading] = useState<boolean>(false);
  const [hops, setHops] = useState<number>(0);
  const [timeElapsed, setTimeElapsed] = useState<number>(0);
  const [visitedNodes, setVisitedNodes] = useState<string[]>([startPage]);
  const [gameStatus, setGameStatus] = useState<"playing" | "won" | "lost">(
    "playing"
  );
  const [continuousPlay, setContinuousPlay] = useState<boolean>(true);
  const [autoRunning, setAutoRunning] = useState<boolean>(true);
  const [convo, setConvo] = useState<Message[]>([]);
  const [expandedMessages, setExpandedMessages] = useState<
    Record<number | string, boolean>
  >({ game: false });
  const messagesEndRef = useRef<HTMLDivElement>(null);

  const {
    status: modelStatus,
    partialText,
    inference
  } = useInference({
    apiKey:
      window.localStorage.getItem("huggingface_access_token") || undefined,
  });

  const fetchCurrentPageLinks = useCallback(async () => {
    setLinksLoading(true);
    const response = await fetch(
      `${API_BASE}/get_article_with_links/${currentPage}`
    );
    const data = await response.json();
    setCurrentPageLinks(data.links.slice(0, maxLinks));
    setLinksLoading(false);
  }, [currentPage, maxLinks]);

  useEffect(() => {
    fetchCurrentPageLinks();
  }, [fetchCurrentPageLinks]);

  useEffect(() => {
    if (gameStatus === "playing") {
      const timer = setInterval(() => {
        setTimeElapsed((prev) => prev + 1);
      }, 1000);

      return () => clearInterval(timer);
    }
  }, [gameStatus]);

  // Check win condition
  useEffect(() => {
    if (currentPage === targetPage) {
      setGameStatus("won");
    } else if (hops >= maxHops) {
      setGameStatus("lost");
    }
  }, [currentPage, targetPage, hops, maxHops]);

  const handleLinkClick = (link: string) => {
    if (gameStatus !== "playing") return;

    setCurrentPage(link);
    setHops((prev) => prev + 1);
    setVisitedNodes((prev) => [...prev, link]);
  };

  const currentRuns = useMemo(() => {
    const q3runs = qwen3Data.runs.filter((run) => run.result === "win");

    if (visitedNodes.length === 0) {
      return q3runs;
    }

    return [
      {
        steps: [
          {
            type: "start",
            article: startPage,
          },
          ...visitedNodes.map((node) => ({ type: "move", article: node })),
        ],
        start_article: startPage,
        destination_article: targetPage,
      },
      ...q3runs,
    ];
  }, [visitedNodes, startPage, targetPage]);

  const makeModelMove = async () => {
    const prompt = buildPrompt(
      currentPage,
      targetPage,
      visitedNodes,
      currentPageLinks
    );

    pushConvo({
      role: "user",
      content: prompt,
    });

    const {status, result: modelResponse} = await inference({
      model: model,
      prompt,
      maxTokens: maxTokens,
    });

    if (status === "error") {
      pushConvo({
        role: "error",
        content: "Error during inference: " + modelResponse,
      });

      setAutoRunning(false);
      return;
    }

    pushConvo({
      role: "assistant",
      content: modelResponse,
    });

    console.log("Model response", modelResponse);

    const answer = modelResponse.match(/<answer>(.*?)<\/answer>/)?.[1];
    if (!answer) {
      console.error("No answer found in model response");
      return;
    }

    // try parsing the answer as an integer
    const answerInt = parseInt(answer);
    if (isNaN(answerInt)) {
      console.error("Invalid answer found in model response");
      return;
    }

    if (answerInt < 1 || answerInt > currentPageLinks.length) {
      console.error(
        "Selected link out of bounds",
        answerInt,
        "from ",
        currentPageLinks.length,
        "links"
      );
      return;
    }

    const selectedLink = currentPageLinks[answerInt - 1];

    // Add a game status message after each move
    pushConvo({
      role: "game",
      content: `Model selected link ${answerInt}: ${selectedLink}`,
      metadata: {
        page: currentPage,
        links: [...currentPageLinks],
      },
    });

    console.log(
      "Model picked selectedLink",
      selectedLink,
      "from ",
      currentPageLinks
    );

    handleLinkClick(selectedLink);
  };

  const handleGiveUp = () => {
    setGameStatus("lost");
  };

  const formatTime = (seconds: number) => {
    const mins = Math.floor(seconds / 60);
    const secs = seconds % 60;
    return `${mins}:${secs < 10 ? "0" : ""}${secs}`;
  };

  const pushConvo = (message: Message) => {
    setConvo((prev) => [...prev, message]);
  };

  const scrollToBottom = () => {
    messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
  };

  useEffect(() => {
    scrollToBottom();
  }, [convo, partialText]);

  const toggleMessageExpand = (index: number | string) => {
    setExpandedMessages((prev) => ({
      ...prev,
      [index]: !prev[index],
    }));
  };

  // Effect for continuous play mode
  useEffect(() => {
    if (
      continuousPlay &&
      autoRunning &&
      player === "model" &&
      gameStatus === "playing" &&
      modelStatus !== "thinking" &&
      !linksLoading
    ) {
      const timer = setTimeout(() => {
        makeModelMove();
      }, 1000);

      return () => clearTimeout(timer);
    }
  }, [
    continuousPlay,
    autoRunning,
    player,
    gameStatus,
    modelStatus,
    linksLoading,
    currentPage,
  ]);

  // Add a result message when the game ends
  useEffect(() => {
    if (gameStatus !== "playing" && convo.length > 0 && convo[convo.length - 1].role !== "result") {
      pushConvo({
        role: "result",
        content: gameStatus === "won" 
          ? `${model} successfully navigated from ${visitedNodes[0]} to ${targetPage} in ${hops} moves!`
          : `${model} failed to reach ${targetPage} within the ${maxHops} hop limit.`,
        metadata: {
          status: gameStatus,
          path: [...visitedNodes],
        },
      });
    }
  }, [gameStatus]);

  return (
    <div className="grid grid-cols-1 md:grid-cols-12 gap-2 h-[calc(100vh-200px)] grid-rows-[auto_1fr_1fr]">
      {/* Condensed Game Status Card */}
      <Card className="p-2 col-span-12 h-12 row-start-1">
        <div className="flex items-center justify-between h-full">
          <div className="flex items-center gap-4">
            <div className="flex items-center gap-1">
              <ArrowRight className="h-4 w-4 text-muted-foreground" />
              <span className="text-sm font-medium">{currentPage}</span>
            </div>
            <div className="flex items-center gap-1">
              <Flag className="h-4 w-4 text-muted-foreground" />
              <span className="text-sm font-medium">{targetPage}</span>
            </div>
            <div
              className="flex items-center gap-1 cursor-help relative group"
              title="Path history"
            >
              <Hash className="h-4 w-4 text-muted-foreground" />
              <span className="text-sm font-medium">
                {hops} / {maxHops}
              </span>
              <div className="invisible absolute bottom-full left-0 mb-2 p-2 bg-popover border rounded-md shadow-md text-xs max-w-[300px] z-50 group-hover:visible whitespace-pre-wrap">
                Path: {visitedNodes.join(" → ")}
              </div>
            </div>
            <div className="flex items-center gap-1">
              <Clock className="h-4 w-4 text-muted-foreground" />
              <span className="text-sm font-medium">
                {formatTime(timeElapsed)}
              </span>
            </div>
          </div>

          <div className="flex items-center gap-2">
            {gameStatus === "playing" && (
              <>
                {player === "model" && (
                  <>
                    {continuousPlay ? (
                      <Button
                        onClick={() => setAutoRunning(!autoRunning)}
                        size="sm"
                        className="h-8"
                      >
                        {autoRunning ? "Stop" : "Start"}
                      </Button>
                    ) : (
                      <Button
                        onClick={makeModelMove}
                        disabled={modelStatus === "thinking" || linksLoading}
                        size="sm"
                        className="h-8"
                      >
                        Next Move
                      </Button>
                    )}

                    <div className="flex items-center gap-1 ml-1">
                      <Switch
                        id="continuous-play"
                        checked={continuousPlay}
                        onCheckedChange={(checked) => {
                          setContinuousPlay(checked);
                          if (!checked) setAutoRunning(false);
                        }}
                        disabled={
                          modelStatus === "thinking" ||
                          linksLoading ||
                          (continuousPlay && autoRunning)
                        }
                      />
                      <Label htmlFor="continuous-play" className="text-xs">
                        Auto
                      </Label>
                    </div>
                  </>
                )}

                {player === "me" && (
                  <Button
                    onClick={handleGiveUp}
                    variant="destructive"
                    size="sm"
                    className="h-8"
                  >
                    Give Up
                  </Button>
                )}
              </>
            )}

            {gameStatus !== "playing" && (
              <Button
                onClick={onReset}
                variant="outline"
                size="sm"
                className="h-8"
              >
                New Game
              </Button>
            )}
          </div>
        </div>
      </Card>

      {/* Links panel - larger now */}
      {player === "me" && (
        <Card className="p-3 md:col-span-6 h-full overflow-hidden row-span-2 row-start-2">
          <h2 className="text-lg font-bold mb-2">
            Available Links
            <TooltipProvider>
              <Tooltip>
                <TooltipTrigger asChild>
                  <span className="ml-2 text-xs text-muted-foreground cursor-help inline-flex items-center">
                    <Info className="h-3 w-3 mr-1" />
                    Why are some links missing?
                  </span>
                </TooltipTrigger>
                <TooltipContent className="max-w-[300px] p-3">
                  <p>
                    We're playing on a pruned version of Simple Wikipedia so
                    that every path between articles is possible. See dataset
                    details{" "}
                    <a
                      href="https://huggingface.co/datasets/HuggingFaceTB/simplewiki-pruned-350k"
                      target="_blank"
                      rel="noopener noreferrer"
                      className="text-blue-600 underline hover:text-blue-800"
                    >
                      here
                    </a>
                    .
                  </p>
                </TooltipContent>
              </Tooltip>
            </TooltipProvider>
          </h2>

          {gameStatus === "playing" ? (
            <div className="flex flex-wrap content-start overflow-y-auto h-[calc(100%-2.5rem)]">
              {currentPageLinks
                .sort((a, b) => a.localeCompare(b))
                .map((link) => (
                  <Button
                    key={link}
                    variant="outline"
                    size="sm"
                    className="justify-start overflow-hidden text-ellipsis whitespace-nowrap w-[calc(33.333%-0.5rem)] m-[0.25rem]"
                    onClick={() => handleLinkClick(link)}
                  >
                    {link}
                  </Button>
                ))}
            </div>
          ) : (
            <div className="flex items-center justify-center h-[calc(100%-2.5rem)]">
              {gameStatus === "won" ? (
                <div className="bg-gradient-to-r from-green-50 to-emerald-50 border border-green-200 p-6 rounded-lg w-full shadow-sm">
                  <div className="flex flex-col items-center text-center">
                    <div className="mb-3 bg-green-100 p-3 rounded-full">
                      <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="text-green-600"><polyline points="20 6 9 17 4 12"></polyline></svg>
                    </div>
                    <h3 className="font-bold text-xl text-green-800 mb-2">
                      You won!
                    </h3>
                    <p className="text-green-700 mb-4">
                      You reached <span className="font-bold">{targetPage}</span> in <span className="font-bold">{hops}</span> {hops === 1 ? 'hop' : 'hops'} in {formatTime(timeElapsed)}
                    </p>
                    
                    <div className="bg-white rounded-md p-4 my-3 w-full max-w-md border border-green-100">
                      <h4 className="font-medium text-sm text-green-800 mb-2">Your Path:</h4>
                      <div className="flex flex-wrap items-center gap-2 justify-center text-sm">
                        {visitedNodes.map((node, index) => (
                          <div key={`path-${index}`} className="flex items-center">
                            <span className="bg-green-50 px-2 py-1 rounded border border-green-100 font-medium">{node}</span>
                            {index < visitedNodes.length - 1 && (
                              <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="mx-1 text-green-400"><path d="M5 12h14"></path><path d="m12 5 7 7-7 7"></path></svg>
                            )}
                          </div>
                        ))}
                      </div>
                    </div>
                    
                    <div className="flex gap-2 mt-2">
                      <Button
                        onClick={onReset}
                        variant="outline"
                        size="sm"
                        className="bg-white"
                      >
                        New Game
                      </Button>
                    </div>
                  </div>
                </div>
              ) : (
                <div className="bg-red-100 text-red-800 p-4 rounded-md w-full">
                  <h3 className="font-bold">Game Over</h3>
                  <p>
                    You didn't reach {targetPage} within {maxHops} hops.
                  </p>
                  <Button
                    onClick={onReset}
                    variant="outline"
                    size="sm"
                    className="mt-2"
                  >
                    New Game
                  </Button>
                </div>
              )}
            </div>
          )}
        </Card>
      )}

      {/* Reasoning panel - spans full height on left side */}
      {player === "model" && (
        <Card className="p-3 md:col-span-6 h-full overflow-hidden row-span-2 row-start-2">
          <h2 className="text-lg font-bold mb-2">LLM Reasoning</h2>
          <div className="overflow-y-auto h-[calc(100%-2.5rem)] space-y-2 pr-2">
            {convo.map((message, index) => {
              const isExpanded = expandedMessages[index] || false;
              
              if (message.role === "user" || message.role === "assistant") {
                const isLongUserMessage =
                  message.role === "user" && message.content.length > 300;
                const shouldTruncate = isLongUserMessage && !isExpanded;
                
                return (
                  <div
                    key={`message-${index}`}
                    className={`p-2 rounded-lg text-xs ${
                      message.role === "assistant"
                        ? "bg-blue-50 border border-blue-100"
                        : "bg-gray-50 border border-gray-100"
                    }`}
                  >
                    <div className="flex items-center gap-1 mb-1 text-xs font-medium text-muted-foreground">
                      {message.role === "assistant" ? (
                        <>
                          <Bot className="h-3 w-3" />
                          <span>Assistant</span>
                        </>
                      ) : (
                        <>
                          <User className="h-3 w-3" />
                          <span>User</span>
                        </>
                      )}
                    </div>

                    <div>
                      <p className="whitespace-pre-wrap text-xs">
                        {shouldTruncate
                          ? message.content.substring(0, 300) + "..."
                          : message.content}
                      </p>

                      {isLongUserMessage && (
                        <Button
                          variant="ghost"
                          size="sm"
                          className="mt-1 h-5 text-xs flex items-center gap-1 text-muted-foreground hover:text-foreground"
                          onClick={() => toggleMessageExpand(index)}
                        >
                          {isExpanded ? (
                            <>
                              <ChevronUp className="h-3 w-3" /> Show less
                            </>
                          ) : (
                            <>
                              <ChevronDown className="h-3 w-3" /> Show more
                            </>
                          )}
                        </Button>
                      )}
                    </div>
                  </div>
                );
              } else if (message.role === "game") {
                // Game status block
                return (
                  <div 
                    key={`game-${index}`}
                    className="p-2 rounded-lg bg-yellow-50 border border-yellow-100 text-xs"
                  >
                    <div className="flex items-center justify-between mb-1">
                      <div className="flex items-center gap-1 text-xs font-medium text-muted-foreground">
                        <Info className="h-3 w-3" />
                        <span>Game Status</span>
                      </div>
                      <Button
                        variant="ghost"
                        size="sm"
                        className="h-5 text-xs flex items-center gap-1 text-muted-foreground hover:text-foreground p-0"
                        onClick={() => toggleMessageExpand(index)}
                      >
                        {expandedMessages[index] ? (
                          <ChevronUp className="h-3 w-3" />
                        ) : (
                          <ChevronDown className="h-3 w-3" />
                        )}
                      </Button>
                    </div>
                    
                    <div>
                      <p className="font-medium">{message.content}</p>
                      {message.metadata?.page && (
                        <p className="mt-1">Current page: {message.metadata.page}</p>
                      )}
                      {message.metadata?.links && (
                        <p className="mt-1">
                          Available links: {message.metadata.links.length} 
                          {!isExpanded && message.metadata.links.length > 0 && (
                            <span className="text-muted-foreground">
                              {" "}({message.metadata.links.slice(0, 3).join(", ")}
                              {message.metadata.links.length > 3 ? "..." : ""})
                            </span>
                          )}
                        </p>
                      )}
                      
                      {isExpanded && message.metadata?.links && (
                        <div className="mt-2 space-y-1">
                          {message.metadata.links.map((link, i) => (
                            <div key={i} className="text-xs text-muted-foreground">
                              {i+1}. {link}
                            </div>
                          ))}
                        </div>
                      )}
                    </div>
                  </div>
                );
              } else if (message.role === "result") {
                // Result block
                const isWon = message.metadata?.status === "won";
                return (
                  <div 
                    key={`result-${index}`}
                    className={`p-2 rounded-lg text-xs ${
                      isWon
                        ? "bg-gradient-to-r from-green-50 to-emerald-50 border border-green-200" 
                        : "bg-red-50 border border-red-100"
                    }`}
                  >
                    {isWon ? (
                      <div className="flex flex-col items-center text-center">
                        <div className="mb-2 bg-green-100 p-2 rounded-full">
                          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="text-green-600"><polyline points="20 6 9 17 4 12"></polyline></svg>
                        </div>
                        <h3 className="font-bold text-sm text-green-800 mb-1">{message.content}</h3>
                        
                        {message.metadata?.path && (
                          <div className="bg-white rounded p-2 my-2 w-full border border-green-100">
                            <h4 className="font-medium text-xs text-green-800 mb-1">Path:</h4>
                            <div className="flex flex-wrap items-center gap-1 justify-center text-xs">
                              {message.metadata.path.map((node, index) => (
                                <div key={`result-path-${index}`} className="flex items-center">
                                  <span className="bg-green-50 px-1.5 py-0.5 rounded border border-green-100 font-medium">{node}</span>
                                  {index < message.metadata.path.length - 1 && (
                                    <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="mx-1 text-green-400"><path d="M5 12h14"></path><path d="m12 5 7 7-7 7"></path></svg>
                                  )}
                                </div>
                              ))}
                            </div>
                          </div>
                        )}
                      </div>
                    ) : (
                      <div>
                        <div className="flex items-center gap-1 mb-1 text-xs font-medium text-muted-foreground">
                          <Flag className="h-3 w-3" />
                          <span>Game Over</span>
                        </div>
                        <p>{message.content}</p>
                        
                        {message.metadata?.path && (
                          <p className="mt-1 text-xs text-muted-foreground">
                            Path: {message.metadata.path.join(" → ")}
                          </p>
                        )}
                      </div>
                    )}
                  </div>
                );
              } else if (message.role === "error") {
                return (
                  <div className="p-2 rounded-lg bg-red-50 border border-red-100 text-xs">
                    <p>{message.content}</p>
                  </div>
                );
              }
              
              return null;
            })}

            {modelStatus === "thinking" && (
              <div className="p-2 rounded-lg bg-blue-50 border border-blue-100 text-xs">
                <div className="flex items-center gap-1 mb-1 text-xs font-medium text-muted-foreground">
                  <Bot className="h-3 w-3" />
                  <span className="animate-pulse">Thinking...</span>
                </div>
                <p className="whitespace-pre-wrap text-xs">{partialText}</p>
              </div>
            )}
            
            <div ref={messagesEndRef} />
          </div>
        </Card>
      )}

      {/* Wikipedia view - top right quadrant */}
      <Card className="p-3 md:col-span-6 h-full overflow-hidden row-start-2">
        <h2 className="text-lg font-bold mb-2">Wikipedia View</h2>
        <div className="relative w-full h-[calc(100%-2.5rem)] overflow-hidden">
          <iframe
            style={{
              transform: "scale(0.5, 0.5)",
              width: "calc(100% * 2)",
              height: "calc(100% * 2)",
              transformOrigin: "top left",
              position: "absolute",
              top: 0,
              left: 0,
            }}
            src={`https://simple.wikipedia.org/wiki/${currentPage.replace(
              " ",
              "_"
            )}`}
            className="border-0"
          />
        </div>
      </Card>

      {/* Force directed graph - bottom right quadrant */}
      <Card className="p-3 md:col-span-6 h-full overflow-hidden row-start-3">
        <ForceDirectedGraph runs={currentRuns} runId={0} />
      </Card>
    </div>
  );
}
