import React, { useRef, useState, useEffect, useMemo } from "react";
import { Editor } from "@monaco-editor/react";
import type { editor } from "monaco-editor";
import { Button } from "@/components/ui/button";
import { ChevronUp, ChevronDown } from "lucide-react";

// Add interface for range - export for reuse
export interface Range {
  start: number;
  end: number;
}

interface LineMapping {
  originalLineNumber: number;
  startChar: number;
  endChar: number;
  content: string;
}

interface MonacoEditorWithHighlightsProps {
  numberedLines: string[]; // each already prefixed with <L#>
  highlightRanges: Range[];
  showNavigationControls?: boolean;
  height?: string;
  theme?: string;
  className?: string;
}

export const MonacoEditorWithHighlights: React.FC<
  MonacoEditorWithHighlightsProps
> = ({
  numberedLines,
  highlightRanges,
  showNavigationControls = true,
  height = "100%",
  theme = "vs-dark",
  className = "",
}) => {
  const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null);
  const [currentHighlightIndex, setCurrentHighlightIndex] = useState(0);
  const [decorations, setDecorations] = useState<string[]>([]);

  // Parse numbered lines and reconstruct original content
  const { reconstructedContent, characterRanges } = useMemo(() => {
    const mapping: LineMapping[] = [];

    // Parse each numbered line and extract line numbers
    const parsedLines: {
      lineNumber: number;
      content: string;
      index: number;
    }[] = [];

    for (let i = 0; i < numberedLines.length; i++) {
      const line = numberedLines[i];
      if (!line) continue;

      const match = line.match(/^<L(\d+)>\s*(.*)$/);
      if (!match) continue;

      const [, lineNumber, content] = match;
      if (!lineNumber || content === undefined) continue;

      parsedLines.push({
        lineNumber: parseInt(lineNumber),
        content,
        index: i,
      });
    }

    // Sort by line number to ensure proper order
    parsedLines.sort((a, b) => a.lineNumber - b.lineNumber);

    // Simple concatenation - just join all content together
    let rawContent = "";
    for (let i = 0; i < parsedLines.length; i++) {
      const currentLine = parsedLines[i];
      if (!currentLine) continue;

      // Track character mapping for highlighting
      const startChar = rawContent.length;
      rawContent += currentLine.content;
      const endChar = rawContent.length;

      mapping.push({
        originalLineNumber: currentLine.lineNumber,
        startChar,
        endChar,
        content: currentLine.content,
      });
    }

    // Process the raw content for better formatting
    let processedContent = rawContent;

    // Convert literal \\n to actual line breaks
    processedContent = processedContent.replace(/\\n/g, "\n");

    // Convert literal \\t to actual tabs
    processedContent = processedContent.replace(/\\t/g, "\t");

    // Try to detect and format JSON content (handle multiple JSON objects)
    const jsonRegex = /\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}/g;
    const jsonMatches = processedContent.match(jsonRegex);

    if (jsonMatches) {
      jsonMatches.forEach((jsonStr) => {
        try {
          const parsed = JSON.parse(jsonStr);
          const formatted = JSON.stringify(parsed, null, 2);
          processedContent = processedContent.replace(jsonStr, formatted);
        } catch (e) {
          // If JSON parsing fails, keep original content
        }
      });
    }

    // Clean up excessive whitespace but preserve intentional formatting
    processedContent = processedContent
      .replace(/[ \t]+/g, " ") // Multiple spaces/tabs to single space
      .replace(/\n\s*\n\s*\n/g, "\n\n") // Multiple newlines to double newline max
      .trim(); // Remove leading/trailing whitespace

    // Update character mapping based on content transformation
    const contentLengthDiff = processedContent.length - rawContent.length;

    // Convert line-based ranges to character-based ranges
    const charRanges = highlightRanges
      .map((range) => {
        const startMapping = mapping.find(
          (m) => m.originalLineNumber === range.start + 1
        );
        const endMapping = mapping.find(
          (m) => m.originalLineNumber === range.end + 1
        );

        if (!startMapping || !endMapping) {
          return { startChar: 0, endChar: 0 };
        }

        // Adjust for content transformation
        let adjustedStartChar = startMapping.startChar;
        let adjustedEndChar = endMapping.endChar;

        // Simple adjustment - this might need refinement for complex cases
        if (contentLengthDiff > 0) {
          const adjustmentRatio = processedContent.length / rawContent.length;
          adjustedStartChar = Math.floor(
            startMapping.startChar * adjustmentRatio
          );
          adjustedEndChar = Math.floor(endMapping.endChar * adjustmentRatio);
        }

        return {
          startChar: adjustedStartChar,
          endChar: adjustedEndChar,
        };
      })
      .filter((range) => range.startChar !== range.endChar);

    return {
      reconstructedContent: processedContent,
      characterRanges: charRanges,
    };
  }, [numberedLines, highlightRanges]);

  // Sort ranges by start position for navigation
  const sortedRanges = [...characterRanges].sort(
    (a, b) => a.startChar - b.startChar
  );

  // Scroll to specific highlighted range in Monaco Editor
  const scrollToHighlight = (rangeIndex: number) => {
    if (!editorRef.current || sortedRanges.length === 0) return;

    const range = sortedRanges[rangeIndex];
    if (!range) return;

    try {
      const model = editorRef.current.getModel();
      if (!model) {
        // If model isn't ready, retry after a short delay
        setTimeout(() => scrollToHighlight(rangeIndex), 100);
        return;
      }

      const startPosition = model.getPositionAt(range.startChar);

      // Scroll to the position with animation
      editorRef.current.revealPositionInCenter(startPosition, 1); // 1 = animated

      // Update decorations to highlight current range
      updateHighlightDecorations();
    } catch (error) {
      console.warn("Error scrolling to highlight:", error);
      // Retry once after a delay
      setTimeout(() => {
        try {
          const startPosition = editorRef
            .current!.getModel()!
            .getPositionAt(range.startChar);
          editorRef.current!.revealPositionInCenter(startPosition, 1);
          updateHighlightDecorations();
        } catch (retryError) {
          console.warn("Retry failed for scrolling to highlight:", retryError);
        }
      }, 200);
    }
  };

  // Navigation handlers
  const goToNextHighlight = () => {
    if (sortedRanges.length === 0) return;
    const nextIndex = (currentHighlightIndex + 1) % sortedRanges.length;
    setCurrentHighlightIndex(nextIndex);
    scrollToHighlight(nextIndex);
  };

  const goToPreviousHighlight = () => {
    if (sortedRanges.length === 0) return;
    const prevIndex =
      currentHighlightIndex === 0
        ? sortedRanges.length - 1
        : currentHighlightIndex - 1;
    setCurrentHighlightIndex(prevIndex);
    scrollToHighlight(prevIndex);
  };

  // Keyboard navigation
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (
        e.target instanceof HTMLInputElement ||
        e.target instanceof HTMLTextAreaElement
      ) {
        return; // Don't interfere with input fields
      }

      if (e.key === ">" || (e.key === "ArrowDown" && e.ctrlKey)) {
        e.preventDefault();
        goToNextHighlight();
      } else if (e.key === "<" || (e.key === "ArrowUp" && e.ctrlKey)) {
        e.preventDefault();
        goToPreviousHighlight();
      }
    };

    document.addEventListener("keydown", handleKeyDown);
    return () => document.removeEventListener("keydown", handleKeyDown);
  }, [currentHighlightIndex, sortedRanges.length]);

  // Scroll first highlighted range into view on initial load or when ranges change
  useEffect(() => {
    if (sortedRanges.length > 0) {
      setCurrentHighlightIndex(0);
      // Add a small delay to ensure Monaco editor is fully rendered
      const timeoutId = setTimeout(() => {
        scrollToHighlight(0);
      }, 150);

      return () => clearTimeout(timeoutId);
    }
    // Return undefined when no cleanup is needed
    return undefined;
  }, [highlightRanges]);

  // Update decorations when current highlight changes
  useEffect(() => {
    updateHighlightDecorations();
  }, [currentHighlightIndex, characterRanges]);

  // Handle Monaco Editor mount
  const handleEditorDidMount = (editor: editor.IStandaloneCodeEditor) => {
    editorRef.current = editor;

    // Apply initial decorations for highlights
    updateHighlightDecorations();

    // Configure editor options
    editor.updateOptions({
      readOnly: true,
      minimap: { enabled: false },
      scrollBeyondLastLine: false,
      wordWrap: "on",
      lineNumbers: "on",
      folding: false,
      renderWhitespace: "selection",
      fontSize: 12,
      fontFamily: "'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', monospace",
      lineHeight: 18,
      letterSpacing: 0.5,
      fontWeight: "400",
      renderLineHighlight: "none",
      cursorStyle: "line",
      cursorBlinking: "blink",
      smoothScrolling: true,
    });
  };

  // Update highlight decorations in Monaco Editor
  const updateHighlightDecorations = () => {
    if (!editorRef.current) return;

    // Clear all existing decorations first to prevent old highlights from persisting
    if (decorations.length > 0) {
      editorRef.current.deltaDecorations(decorations, []);
      setDecorations([]);
    }

    const newDecorations: editor.IModelDeltaDecoration[] = [];

    characterRanges.forEach((range, index) => {
      const startPosition = editorRef
        .current!.getModel()!
        .getPositionAt(range.startChar);
      const endPosition = editorRef
        .current!.getModel()!
        .getPositionAt(range.endChar);

      const isCurrentHighlight = index === currentHighlightIndex;

      newDecorations.push({
        range: {
          startLineNumber: startPosition.lineNumber,
          startColumn: startPosition.column,
          endLineNumber: endPosition.lineNumber,
          endColumn: endPosition.column,
        },
        options: {
          className: isCurrentHighlight
            ? "current-highlight-decoration"
            : "highlight-decoration",
          isWholeLine: false,
        },
      });
    });

    // Apply new decorations
    const decorationIds = editorRef.current.deltaDecorations(
      [],
      newDecorations
    );
    setDecorations(decorationIds);
  };

  // Detect language for syntax highlighting
  const detectLanguage = (content: string): string => {
    // Check for JSON content
    if (content.trim().startsWith("{") && content.trim().endsWith("}")) {
      try {
        JSON.parse(content);
        return "json";
      } catch {
        // Not valid JSON, continue checking
      }
    }

    // Check for Python code patterns
    if (/^(import|from|def|class|if __name__|print\()/m.test(content)) {
      return "python";
    }

    // Check for JavaScript/TypeScript patterns
    if (/^(import|export|function|const|let|var|console\.log)/m.test(content)) {
      return "javascript";
    }

    // Check for shell/bash patterns
    if (
      /^(#!\/bin\/|cd |ls |mkdir |rm |pip install|npm install)/m.test(content)
    ) {
      return "shell";
    }

    // Check for SQL patterns
    if (/^(SELECT|INSERT|UPDATE|DELETE|CREATE|DROP|ALTER)/im.test(content)) {
      return "sql";
    }

    // Default to plain text
    return "text";
  };

  const detectedLanguage = useMemo(
    () => detectLanguage(reconstructedContent),
    [reconstructedContent]
  );

  return (
    <div className={`flex flex-col h-full ${className}`}>
      {/* Navigation controls */}
      {showNavigationControls && sortedRanges.length > 0 && (
        <div className="flex items-center justify-center gap-2 p-2 border-b bg-muted/10">
          <Button
            variant="ghost"
            size="sm"
            className="h-6 w-6 p-0"
            onClick={goToPreviousHighlight}
            title="Previous highlight (<)"
          >
            <ChevronUp className="h-3 w-3" />
          </Button>
          <span className="text-xs text-muted-foreground">
            {currentHighlightIndex + 1} / {sortedRanges.length}
          </span>
          <Button
            variant="ghost"
            size="sm"
            className="h-6 w-6 p-0"
            onClick={goToNextHighlight}
            title="Next highlight (>)"
          >
            <ChevronDown className="h-3 w-3" />
          </Button>
        </div>
      )}

      {/* Monaco Editor */}
      <div className="flex-1">
        <Editor
          height={height}
          defaultLanguage={detectedLanguage}
          value={reconstructedContent}
          onMount={handleEditorDidMount}
          theme={theme}
          options={{
            readOnly: true,
            minimap: { enabled: false },
            scrollBeyondLastLine: false,
            wordWrap: "on",
            lineNumbers: "on",
            folding: false,
            renderWhitespace: "selection",
            fontSize: 12,
            fontFamily:
              "'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', monospace",
            padding: { top: 10, bottom: 10 },
          }}
        />
      </div>
    </div>
  );
};
