/**
 * CodeDiffViewer — Manus-style code diff viewer with tabs:
 * Diff / Original / Modified
 * Used in ActionTree when edit_file or write_file tool calls are shown.
 */

import { useState, useMemo } from "react";
import { cn } from "@/lib/utils";

type DiffTab = "diff" | "original" | "modified";

interface DiffLine {
  type: "added" | "removed" | "context";
  lineOld?: number;
  lineNew?: number;
  content: string;
}

/**
 * Simple unified diff parser.
 * Takes old text and new text, produces a line-by-line diff.
 */
function computeDiff(oldText: string, newText: string): DiffLine[] {
  const oldLines = oldText.split("\n");
  const newLines = newText.split("\n");
  const result: DiffLine[] = [];

  // Simple LCS-based diff
  const m = oldLines.length;
  const n = newLines.length;

  // For large files, fall back to a simpler approach
  if (m * n > 1_000_000) {
    // Just show removed then added for very large files
    oldLines.forEach((line, i) => {
      result.push({ type: "removed", lineOld: i + 1, content: line });
    });
    newLines.forEach((line, i) => {
      result.push({ type: "added", lineNew: i + 1, content: line });
    });
    return result;
  }

  // Build LCS table
  const dp: number[][] = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
  for (let i = 1; i <= m; i++) {
    for (let j = 1; j <= n; j++) {
      if (oldLines[i - 1] === newLines[j - 1]) {
        dp[i][j] = dp[i - 1][j - 1] + 1;
      } else {
        dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
      }
    }
  }

  // Backtrack to produce diff
  const diffLines: DiffLine[] = [];
  let i = m, j = n;
  while (i > 0 || j > 0) {
    if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
      diffLines.unshift({ type: "context", lineOld: i, lineNew: j, content: oldLines[i - 1] });
      i--; j--;
    } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
      diffLines.unshift({ type: "added", lineNew: j, content: newLines[j - 1] });
      j--;
    } else {
      diffLines.unshift({ type: "removed", lineOld: i, content: oldLines[i - 1] });
      i--;
    }
  }

  return diffLines;
}

interface CodeDiffViewerProps {
  oldContent: string;
  newContent: string;
  fileName?: string;
  className?: string;
}

export function CodeDiffViewer({ oldContent, newContent, fileName, className }: CodeDiffViewerProps) {
  const [activeTab, setActiveTab] = useState<DiffTab>("diff");

  const diffLines = useMemo(
    () => computeDiff(oldContent, newContent),
    [oldContent, newContent]
  );

  const stats = useMemo(() => {
    const added = diffLines.filter(l => l.type === "added").length;
    const removed = diffLines.filter(l => l.type === "removed").length;
    return { added, removed };
  }, [diffLines]);

  const tabs: { id: DiffTab; label: string }[] = [
    { id: "diff", label: "Diff" },
    { id: "original", label: "Original" },
    { id: "modified", label: "Modified" },
  ];

  return (
    <div className={cn("flex flex-col rounded-md border border-border overflow-hidden", className)}>
      {/* Header with tabs */}
      <div className="flex items-center justify-between bg-secondary/30 border-b border-border">
        <div className="flex">
          {tabs.map((tab) => (
            <button
              key={tab.id}
              onClick={() => setActiveTab(tab.id)}
              className={cn(
                "px-3 py-1.5 text-[11px] font-medium transition-colors border-b-2 -mb-px",
                activeTab === tab.id
                  ? "border-primary text-foreground bg-background/50"
                  : "border-transparent text-muted-foreground hover:text-foreground"
              )}
            >
              {tab.label}
            </button>
          ))}
        </div>
        <div className="flex items-center gap-2 px-2">
          {fileName && (
            <span className="text-[10px] font-mono text-muted-foreground">
              {fileName}
            </span>
          )}
          <span className="text-[10px] font-mono text-green-500">+{stats.added}</span>
          <span className="text-[10px] font-mono text-red-500">-{stats.removed}</span>
        </div>
      </div>

      {/* Content */}
      <div className="overflow-auto max-h-[400px] bg-[#0d1117]">
        {activeTab === "diff" && (
          <table className="w-full text-[11px] font-mono border-collapse">
            <tbody>
              {diffLines.map((line, idx) => (
                <tr
                  key={idx}
                  className={cn(
                    line.type === "added" && "bg-green-500/10",
                    line.type === "removed" && "bg-red-500/10"
                  )}
                >
                  <td className="w-[1px] px-1 text-right text-muted-foreground/40 select-none border-r border-border/30 whitespace-nowrap">
                    {line.lineOld || ""}
                  </td>
                  <td className="w-[1px] px-1 text-right text-muted-foreground/40 select-none border-r border-border/30 whitespace-nowrap">
                    {line.lineNew || ""}
                  </td>
                  <td className="w-[1px] px-1 select-none font-bold">
                    <span className={cn(
                      line.type === "added" && "text-green-500",
                      line.type === "removed" && "text-red-500",
                      line.type === "context" && "text-muted-foreground/30"
                    )}>
                      {line.type === "added" ? "+" : line.type === "removed" ? "-" : " "}
                    </span>
                  </td>
                  <td className="px-2 whitespace-pre-wrap break-all">
                    <span className={cn(
                      line.type === "added" && "text-green-400/90",
                      line.type === "removed" && "text-red-400/90",
                      line.type === "context" && "text-foreground/60"
                    )}>
                      {line.content}
                    </span>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        )}

        {activeTab === "original" && (
          <pre className="text-[11px] font-mono p-3 whitespace-pre-wrap break-all text-foreground/70">
            {oldContent || "(empty)"}
          </pre>
        )}

        {activeTab === "modified" && (
          <pre className="text-[11px] font-mono p-3 whitespace-pre-wrap break-all text-foreground/70">
            {newContent || "(empty)"}
          </pre>
        )}
      </div>
    </div>
  );
}
