/**
 * RightPanel — Manus-style tabbed right panel.
 * Tabs: Actions (tool timeline), Files (explorer), Preview (live viewport).
 */

import { useState, useCallback, useEffect, useRef } from "react";
import {
  Activity,
  FolderTree,
  Monitor,
  Folder,
  File,
  ChevronRight,
  ChevronDown,
  RefreshCw,
  Home,
  ArrowUp,
  FileText,
  FileCode,
  FileJson,
  Image as ImageIcon,
  Loader2,
  ExternalLink,
} from "lucide-react";
import { ActionTree } from "./ActionTree";
import type { ChatMessage } from "@/hooks/useChat";
import { cn } from "@/lib/utils";

// ─── Tab definitions ──────────────────────────────────────────────────

type TabId = "actions" | "files" | "preview";

const TABS: { id: TabId; label: string; icon: typeof Activity }[] = [
  { id: "actions", label: "Actions", icon: Activity },
  { id: "files", label: "Files", icon: FolderTree },
  { id: "preview", label: "Preview", icon: Monitor },
];

// ─── File Explorer types ──────────────────────────────────────────────

interface FileNode {
  name: string;
  path: string;
  isDirectory: boolean;
  size?: number;
}

function getFileIcon(name: string) {
  const ext = name.split(".").pop()?.toLowerCase() || "";
  if (["ts", "tsx", "js", "jsx", "py", "rs", "go", "java", "c", "cpp", "rb", "sh"].includes(ext))
    return FileCode;
  if (["json", "yaml", "yml", "toml", "xml", "env"].includes(ext))
    return FileJson;
  if (["png", "jpg", "jpeg", "gif", "svg", "webp", "ico"].includes(ext))
    return ImageIcon;
  if (["md", "txt", "log", "csv"].includes(ext))
    return FileText;
  return File;
}

function formatSize(bytes?: number): string {
  if (bytes === undefined) return "";
  if (bytes < 1024) return `${bytes}B`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}K`;
  return `${(bytes / (1024 * 1024)).toFixed(1)}M`;
}

// ─── Inline File Explorer ─────────────────────────────────────────────

function FileExplorer() {
  const [currentPath, setCurrentPath] = useState("/home/user");
  const [files, setFiles] = useState<FileNode[]>([]);
  const [loading, setLoading] = useState(false);
  const [selectedFile, setSelectedFile] = useState<string | null>(null);
  const [fileContent, setFileContent] = useState<string | null>(null);
  const [loadingContent, setLoadingContent] = useState(false);

  const fetchFiles = useCallback(async (dirPath: string) => {
    setLoading(true);
    try {
      const response = await fetch("/api/chat/slash", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ command: "/files", args: `list ${dirPath}` }),
      });
      const data = await response.json();
      if (data.files) {
        setFiles(data.files);
      } else if (data.result) {
        // Parse text listing
        const lines = data.result.split("\n").filter((l: string) => l.trim());
        const parsed: FileNode[] = lines
          .filter((l: string) => !l.startsWith("##") && !l.startsWith("---"))
          .map((l: string) => {
            const isDir = l.includes("[DIR]") || l.endsWith("/");
            const name = l.replace("[DIR]", "").replace(/\/$/, "").trim().split(/\s+/).pop() || l.trim();
            return { name, path: `${dirPath}/${name}`.replace("//", "/"), isDirectory: isDir };
          })
          .filter((f: FileNode) => f.name && f.name !== "." && f.name !== "..");
        setFiles(parsed);
      }
    } catch (err) {
      console.error("Failed to fetch files:", err);
      setFiles([]);
    } finally {
      setLoading(false);
    }
  }, []);

  const fetchFileContent = useCallback(async (filePath: string) => {
    setLoadingContent(true);
    try {
      const response = await fetch("/api/chat/slash", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ command: "/files", args: `read ${filePath}` }),
      });
      const data = await response.json();
      setFileContent(data.content || data.result || "Unable to read file");
    } catch {
      setFileContent("Error reading file");
    } finally {
      setLoadingContent(false);
    }
  }, []);

  useEffect(() => {
    fetchFiles(currentPath);
  }, [currentPath, fetchFiles]);

  const navigateUp = () => {
    const parent = currentPath.split("/").slice(0, -1).join("/") || "/";
    setCurrentPath(parent);
    setSelectedFile(null);
    setFileContent(null);
  };

  const handleClick = (file: FileNode) => {
    if (file.isDirectory) {
      setCurrentPath(file.path);
      setSelectedFile(null);
      setFileContent(null);
    } else {
      setSelectedFile(file.path);
      fetchFileContent(file.path);
    }
  };

  return (
    <div className="h-full flex flex-col">
      {/* Path bar */}
      <div className="flex items-center gap-1 px-2 py-1.5 border-b border-border bg-secondary/20">
        <button
          onClick={() => { setCurrentPath("/home/user"); setSelectedFile(null); setFileContent(null); }}
          className="p-1 rounded hover:bg-accent/50"
          title="Home"
        >
          <Home className="size-3 text-muted-foreground" />
        </button>
        <button
          onClick={navigateUp}
          className="p-1 rounded hover:bg-accent/50"
          title="Up"
        >
          <ArrowUp className="size-3 text-muted-foreground" />
        </button>
        <div className="flex-1 text-[10px] font-mono text-muted-foreground truncate px-1">
          {currentPath}
        </div>
        <button
          onClick={() => fetchFiles(currentPath)}
          className="p-1 rounded hover:bg-accent/50"
          title="Refresh"
        >
          <RefreshCw className={cn("size-3 text-muted-foreground", loading && "animate-spin")} />
        </button>
      </div>

      {/* File list or content preview */}
      {selectedFile && fileContent !== null ? (
        <div className="flex-1 flex flex-col overflow-hidden">
          <div className="flex items-center gap-1 px-2 py-1 border-b border-border bg-secondary/10">
            <button
              onClick={() => { setSelectedFile(null); setFileContent(null); }}
              className="text-[10px] text-primary hover:underline"
            >
              Back
            </button>
            <span className="text-[10px] text-muted-foreground truncate">
              {selectedFile.split("/").pop()}
            </span>
          </div>
          <div className="flex-1 overflow-auto">
            {loadingContent ? (
              <div className="flex items-center justify-center h-full">
                <Loader2 className="size-4 animate-spin text-muted-foreground" />
              </div>
            ) : (
              <pre className="text-[11px] font-mono p-2 whitespace-pre-wrap break-all text-foreground/80">
                {fileContent.length > 10000
                  ? fileContent.slice(0, 10000) + "\n\n[...truncated]"
                  : fileContent}
              </pre>
            )}
          </div>
        </div>
      ) : (
        <div className="flex-1 overflow-y-auto">
          {loading ? (
            <div className="flex items-center justify-center h-32">
              <Loader2 className="size-4 animate-spin text-muted-foreground" />
            </div>
          ) : files.length === 0 ? (
            <div className="flex items-center justify-center h-32 text-[11px] text-muted-foreground">
              Empty directory
            </div>
          ) : (
            <div className="py-0.5">
              {files
                .sort((a, b) => {
                  if (a.isDirectory !== b.isDirectory) return a.isDirectory ? -1 : 1;
                  return a.name.localeCompare(b.name);
                })
                .map((file) => {
                  const Icon = file.isDirectory ? Folder : getFileIcon(file.name);
                  return (
                    <button
                      key={file.path}
                      onClick={() => handleClick(file)}
                      className={cn(
                        "flex items-center gap-1.5 w-full px-2 py-1 text-left hover:bg-accent/50 transition-colors",
                        selectedFile === file.path && "bg-accent"
                      )}
                    >
                      <Icon
                        className={cn(
                          "size-3.5 shrink-0",
                          file.isDirectory ? "text-amber-400" : "text-muted-foreground"
                        )}
                      />
                      <span className="text-[11px] truncate flex-1">{file.name}</span>
                      {!file.isDirectory && file.size !== undefined && (
                        <span className="text-[9px] text-muted-foreground/50 font-mono">
                          {formatSize(file.size)}
                        </span>
                      )}
                      {file.isDirectory && (
                        <ChevronRight className="size-3 text-muted-foreground/30" />
                      )}
                    </button>
                  );
                })}
            </div>
          )}
        </div>
      )}
    </div>
  );
}

// ─── Preview Panel ────────────────────────────────────────────────────

function PreviewPanel({ messages }: { messages: ChatMessage[] }) {
  // Extract the latest tool output that could be previewed
  // (bash output, web fetch results, file contents)
  const latestPreviewable = (() => {
    for (let i = messages.length - 1; i >= 0; i--) {
      const msg = messages[i];
      if (msg.role === "assistant" && msg.toolCalls) {
        for (let j = msg.toolCalls.length - 1; j >= 0; j--) {
          const tc = msg.toolCalls[j];
          if (tc.result && !tc.isError) {
            if (tc.name === "bash" || tc.name === "PowerShell") {
              return { type: "terminal" as const, name: tc.name, content: tc.result, command: (() => { try { return JSON.parse(tc.arguments).command; } catch { return ""; } })() };
            }
            if (tc.name === "WebFetch" || tc.name === "WebSearch") {
              return { type: "web" as const, name: tc.name, content: tc.result, url: (() => { try { return JSON.parse(tc.arguments).url || JSON.parse(tc.arguments).query; } catch { return ""; } })() };
            }
            if (tc.name === "read_file") {
              return { type: "file" as const, name: tc.name, content: tc.result, path: (() => { try { return JSON.parse(tc.arguments).path; } catch { return ""; } })() };
            }
          }
        }
      }
    }
    return null;
  })();

  if (!latestPreviewable) {
    return (
      <div className="h-full flex flex-col items-center justify-center text-muted-foreground/40 gap-2 p-4">
        <Monitor className="size-8" />
        <p className="text-xs text-center">
          Live preview will appear here when the agent runs commands or fetches content
        </p>
      </div>
    );
  }

  return (
    <div className="h-full flex flex-col">
      {/* Preview header */}
      <div className="flex items-center gap-2 px-3 py-1.5 border-b border-border bg-secondary/20">
        {latestPreviewable.type === "terminal" && (
          <>
            <div className="flex gap-1">
              <div className="size-2 rounded-full bg-red-500/70" />
              <div className="size-2 rounded-full bg-yellow-500/70" />
              <div className="size-2 rounded-full bg-green-500/70" />
            </div>
            <span className="text-[10px] font-mono text-muted-foreground truncate">
              $ {latestPreviewable.command?.slice(0, 60)}
            </span>
          </>
        )}
        {latestPreviewable.type === "web" && (
          <>
            <ExternalLink className="size-3 text-muted-foreground" />
            <span className="text-[10px] font-mono text-muted-foreground truncate">
              {latestPreviewable.url}
            </span>
          </>
        )}
        {latestPreviewable.type === "file" && (
          <>
            <FileText className="size-3 text-muted-foreground" />
            <span className="text-[10px] font-mono text-muted-foreground truncate">
              {latestPreviewable.path}
            </span>
          </>
        )}
      </div>

      {/* Preview content */}
      <div className="flex-1 overflow-auto bg-[#0d1117]">
        <pre className="text-[11px] font-mono p-3 whitespace-pre-wrap break-all text-green-400/90">
          {latestPreviewable.content.length > 15000
            ? latestPreviewable.content.slice(0, 15000) + "\n\n[...truncated]"
            : latestPreviewable.content}
        </pre>
      </div>
    </div>
  );
}

// ─── Main RightPanel ──────────────────────────────────────────────────

interface RightPanelProps {
  messages: ChatMessage[];
  isStreaming: boolean;
}

export function RightPanel({ messages, isStreaming }: RightPanelProps) {
  const [activeTab, setActiveTab] = useState<TabId>("actions");

  return (
    <div className="h-full flex flex-col bg-background">
      {/* Tab bar */}
      <div className="flex border-b border-border bg-secondary/10">
        {TABS.map((tab) => {
          const Icon = tab.icon;
          const isActive = activeTab === tab.id;
          return (
            <button
              key={tab.id}
              onClick={() => setActiveTab(tab.id)}
              className={cn(
                "flex items-center gap-1.5 px-3 py-2 text-[11px] font-medium transition-colors border-b-2 -mb-px",
                isActive
                  ? "border-primary text-foreground"
                  : "border-transparent text-muted-foreground hover:text-foreground hover:border-border"
              )}
            >
              <Icon className="size-3.5" />
              {tab.label}
            </button>
          );
        })}
      </div>

      {/* Tab content */}
      <div className="flex-1 overflow-hidden">
        {activeTab === "actions" && (
          <ActionTree messages={messages} isStreaming={isStreaming} />
        )}
        {activeTab === "files" && (
          <FileExplorer />
        )}
        {activeTab === "preview" && (
          <PreviewPanel messages={messages} />
        )}
      </div>
    </div>
  );
}
