import { DiffEditor, Monaco } from "@monaco-editor/react";
import React from "react";
import { editor as editor_t } from "monaco-editor";
import { LuFileDiff, LuFileMinus, LuFilePlus } from "react-icons/lu";
import { IconType } from "react-icons/lib";
import { GitChangeStatus } from "#/api/open-hands.types";
import { getLanguageFromPath } from "#/utils/get-language-from-path";
import { cn } from "#/utils/utils";
import ChevronUp from "#/icons/chveron-up.svg?react";
import { useGitDiff } from "#/hooks/query/use-get-diff";

interface LoadingSpinnerProps {
  className?: string;
}

// TODO: Move out of this file and replace the current spinner with this one
function LoadingSpinner({ className }: LoadingSpinnerProps) {
  return (
    <div className="flex items-center justify-center">
      <div
        className={cn(
          "animate-spin rounded-full border-4 border-gray-200 border-t-blue-500",
          className,
        )}
        role="status"
        aria-label="Loading"
      />
    </div>
  );
}

const STATUS_MAP: Record<GitChangeStatus, string | IconType> = {
  A: LuFilePlus,
  D: LuFileMinus,
  M: LuFileDiff,
  R: "Renamed",
  U: "Untracked",
};

export interface FileDiffViewerProps {
  path: string;
  type: GitChangeStatus;
}

export function FileDiffViewer({ path, type }: FileDiffViewerProps) {
  const [isCollapsed, setIsCollapsed] = React.useState(true);
  const [editorHeight, setEditorHeight] = React.useState(400);
  const diffEditorRef = React.useRef<editor_t.IStandaloneDiffEditor>(null);

  const isAdded = type === "A" || type === "U";
  const isDeleted = type === "D";

  const filePath = React.useMemo(() => {
    if (type === "R") {
      const parts = path.split(/\s+/).slice(1);
      return parts[parts.length - 1];
    }

    return path;
  }, [path, type]);

  const {
    data: diff,
    isLoading,
    isSuccess,
    isRefetching,
  } = useGitDiff({
    filePath,
    type,
    enabled: !isCollapsed,
  });

  // Function to update editor height based on content
  const updateEditorHeight = React.useCallback(() => {
    if (diffEditorRef.current) {
      const originalEditor = diffEditorRef.current.getOriginalEditor();
      const modifiedEditor = diffEditorRef.current.getModifiedEditor();

      if (originalEditor && modifiedEditor) {
        // Get the content height from both editors and use the larger one
        const originalHeight = originalEditor.getContentHeight();
        const modifiedHeight = modifiedEditor.getContentHeight();
        const contentHeight = Math.max(originalHeight, modifiedHeight);

        // Add a small buffer to avoid scrollbar
        setEditorHeight(contentHeight + 20);
      }
    }
  }, []);

  const beforeMount = (monaco: Monaco) => {
    monaco.editor.defineTheme("custom-diff-theme", {
      base: "vs-dark",
      inherit: true,
      rules: [
        { token: "comment", foreground: "6a9955" },
        { token: "keyword", foreground: "569cd6" },
        { token: "string", foreground: "ce9178" },
        { token: "number", foreground: "b5cea8" },
      ],
      colors: {
        "diffEditor.insertedTextBackground": "#014b01AA", // Stronger green background
        "diffEditor.removedTextBackground": "#750000AA", // Stronger red background
        "diffEditor.insertedLineBackground": "#003f00AA", // Dark green for added lines
        "diffEditor.removedLineBackground": "#5a0000AA", // Dark red for removed lines
        "diffEditor.border": "#444444", // Border between diff editors

        "editorUnnecessaryCode.border": "#00000000", // No border for unnecessary code
        "editorUnnecessaryCode.opacity": "#00000077", // Slightly faded
      },
    });
  };

  const handleEditorDidMount = (editor: editor_t.IStandaloneDiffEditor) => {
    diffEditorRef.current = editor;
    updateEditorHeight();

    const originalEditor = editor.getOriginalEditor();
    const modifiedEditor = editor.getModifiedEditor();

    originalEditor.onDidContentSizeChange(updateEditorHeight);
    modifiedEditor.onDidContentSizeChange(updateEditorHeight);
  };

  const status = (type === "U" ? STATUS_MAP.A : STATUS_MAP[type]) || "?";

  let statusIcon: React.ReactNode;
  if (typeof status === "string") {
    statusIcon = <span>{status}</span>;
  } else {
    const StatusIcon = status; // now it's recognized as a component
    statusIcon = <StatusIcon className="w-5 h-5" />;
  }

  const isFetchingData = isLoading || isRefetching;

  return (
    <div data-testid="file-diff-viewer-outer" className="w-full flex flex-col">
      <div
        className={cn(
          "flex justify-between items-center px-2.5 py-3.5 border border-neutral-600 rounded-xl hover:cursor-pointer",
          !isCollapsed && !isLoading && "border-b-0 rounded-b-none",
        )}
        onClick={() => setIsCollapsed((prev) => !prev)}
      >
        <span className="text-sm w-full text-content flex items-center gap-2">
          {isFetchingData && <LoadingSpinner className="w-5 h-5" />}
          {!isFetchingData && statusIcon}
          <strong className="w-full truncate">{filePath}</strong>
          <button data-testid="collapse" type="button">
            <ChevronUp
              className={cn(
                "w-4 h-4 transition-transform",
                isCollapsed && "transform rotate-180",
              )}
            />
          </button>
        </span>
      </div>
      {isSuccess && !isCollapsed && (
        <div
          className="w-full border border-neutral-600 overflow-hidden"
          style={{ height: `${editorHeight}px` }}
        >
          <DiffEditor
            data-testid="file-diff-viewer"
            className="w-full h-full"
            language={getLanguageFromPath(filePath)}
            original={isAdded ? "" : diff.original}
            modified={isDeleted ? "" : diff.modified}
            theme="custom-diff-theme"
            onMount={handleEditorDidMount}
            beforeMount={beforeMount}
            options={{
              renderValidationDecorations: "off",
              readOnly: true,
              renderSideBySide: !isAdded && !isDeleted,
              scrollBeyondLastLine: false,
              minimap: {
                enabled: false,
              },
              hideUnchangedRegions: {
                enabled: true,
              },
              automaticLayout: true,
              scrollbar: {
                // Make scrollbar less intrusive
                alwaysConsumeMouseWheel: false,
              },
            }}
          />
        </div>
      )}
    </div>
  );
}
