import { useState, useRef, useEffect } from "react";
import type { BodyElement } from "../../lib/api";
import { ChartRenderer } from "../charts/ChartRenderer";

interface BodyRendererProps {
  elements: BodyElement[];
  isEditing?: boolean;
  onUpdate?: (index: number, element: BodyElement) => void;
  onReorder?: (fromIndex: number, toIndex: number) => void;
  onEditingChange?: (isEditing: boolean) => void;
  hasPendingRemoteUpdate?: boolean;
  onOverwrite?: () => void;
}

export function BodyRenderer({ elements, isEditing = false, onUpdate, onReorder, onEditingChange, hasPendingRemoteUpdate, onOverwrite }: BodyRendererProps) {
  const [draggedIndex, setDraggedIndex] = useState<number | null>(null);
  const [dragOverIndex, setDragOverIndex] = useState<number | null>(null);

  if (elements.length === 0) {
    return (
      <div className="text-[#555] font-mono text-sm italic">
        No content yet. Use the CLI below to add content.
      </div>
    );
  }

  const handleDragStart = (index: number) => (e: React.DragEvent) => {
    setDraggedIndex(index);
    e.dataTransfer.effectAllowed = "move";
    e.dataTransfer.setData("text/plain", index.toString());
  };

  const handleDragOver = (index: number) => (e: React.DragEvent) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = "move";
    if (draggedIndex !== null && draggedIndex !== index) {
      setDragOverIndex(index);
    }
  };

  const handleDragLeave = () => {
    setDragOverIndex(null);
  };

  const handleDrop = (toIndex: number) => (e: React.DragEvent) => {
    e.preventDefault();
    const fromIndex = draggedIndex;
    setDraggedIndex(null);
    setDragOverIndex(null);

    if (fromIndex !== null && fromIndex !== toIndex && onReorder) {
      onReorder(fromIndex, toIndex);
    }
  };

  const handleDragEnd = () => {
    setDraggedIndex(null);
    setDragOverIndex(null);
  };

  return (
    <div className="space-y-1">
      {elements.map((element, index) => (
        <div
          key={index}
          className={`group flex items-start gap-2 py-1 transition-all ${
            draggedIndex === index ? "opacity-50" : ""
          } ${
            dragOverIndex === index
              ? "border-t-2 border-[#75aafc] -mt-[2px] pt-[calc(0.25rem+2px)]"
              : ""
          }`}
          onDragOver={handleDragOver(index)}
          onDragLeave={handleDragLeave}
          onDrop={handleDrop(index)}
        >
          {/* Drag handle - only show in edit mode */}
          {isEditing && onReorder && (
            <div
              draggable
              onDragStart={handleDragStart(index)}
              onDragEnd={handleDragEnd}
              className="flex-shrink-0 w-5 h-6 flex items-center justify-center cursor-grab active:cursor-grabbing opacity-0 group-hover:opacity-100 transition-opacity text-[#555] hover:text-[#75aafc]"
              title="Drag to reorder"
            >
              <svg
                width="12"
                height="12"
                viewBox="0 0 12 12"
                fill="currentColor"
              >
                <circle cx="3" cy="2" r="1.5" />
                <circle cx="9" cy="2" r="1.5" />
                <circle cx="3" cy="6" r="1.5" />
                <circle cx="9" cy="6" r="1.5" />
                <circle cx="3" cy="10" r="1.5" />
                <circle cx="9" cy="10" r="1.5" />
              </svg>
            </div>
          )}
          <div className="flex-1">
            <BodyElementRenderer
              element={element}
              onUpdate={isEditing && onUpdate ? (el) => onUpdate(index, el) : undefined}
              onEditingChange={onEditingChange}
              hasPendingRemoteUpdate={hasPendingRemoteUpdate}
              onOverwrite={onOverwrite}
            />
          </div>
        </div>
      ))}
    </div>
  );
}

function BodyElementRenderer({
  element,
  onUpdate,
  onEditingChange,
  hasPendingRemoteUpdate,
  onOverwrite,
}: {
  element: BodyElement;
  onUpdate?: (element: BodyElement) => void;
  onEditingChange?: (isEditing: boolean) => void;
  hasPendingRemoteUpdate?: boolean;
  onOverwrite?: () => void;
}) {
  switch (element.type) {
    case "heading":
      return (
        <HeadingElement
          level={element.level}
          text={element.text}
          onUpdate={
            onUpdate
              ? (text) => onUpdate({ ...element, text })
              : undefined
          }
          onEditingChange={onEditingChange}
          hasPendingRemoteUpdate={hasPendingRemoteUpdate}
          onOverwrite={onOverwrite}
        />
      );
    case "paragraph":
      return (
        <ParagraphElement
          text={element.text}
          onUpdate={
            onUpdate
              ? (text) => onUpdate({ ...element, text })
              : undefined
          }
          onEditingChange={onEditingChange}
          hasPendingRemoteUpdate={hasPendingRemoteUpdate}
          onOverwrite={onOverwrite}
        />
      );
    case "chart":
      return (
        <ChartElement
          chartType={element.chartType}
          data={element.data}
          title={element.title}
          config={element.config}
        />
      );
    case "image":
      return (
        <ImageElement
          src={element.src}
          alt={element.alt}
          caption={element.caption}
        />
      );
    default:
      return null;
  }
}

function HeadingElement({
  level,
  text,
  onUpdate,
  onEditingChange,
  hasPendingRemoteUpdate,
  onOverwrite,
}: {
  level: number;
  text: string;
  onUpdate?: (text: string) => void;
  onEditingChange?: (isEditing: boolean) => void;
  hasPendingRemoteUpdate?: boolean;
  onOverwrite?: () => void;
}) {
  const [isEditing, setIsEditing] = useState(false);
  const [editText, setEditText] = useState(text);
  const inputRef = useRef<HTMLInputElement>(null);

  useEffect(() => {
    // Only update editText if not currently editing
    if (!isEditing) {
      setEditText(text);
    }
  }, [text, isEditing]);

  useEffect(() => {
    if (isEditing && inputRef.current) {
      inputRef.current.focus();
      inputRef.current.select();
    }
  }, [isEditing]);

  const startEditing = () => {
    setIsEditing(true);
    onEditingChange?.(true);
  };

  const stopEditing = () => {
    setIsEditing(false);
    onEditingChange?.(false);
  };

  const handleSave = () => {
    // Don't auto-save if there's a pending remote update
    if (hasPendingRemoteUpdate) return;

    if (onUpdate && editText.trim() !== text) {
      onUpdate(editText.trim());
    }
    stopEditing();
  };

  const handleOverwrite = () => {
    if (onUpdate && editText.trim() !== text) {
      onUpdate(editText.trim());
    }
    onOverwrite?.();
    stopEditing();
  };

  const handleCancel = () => {
    setEditText(text);
    stopEditing();
  };

  const handleKeyDown = (e: React.KeyboardEvent) => {
    // Disable Enter save if there's a pending remote update
    if (e.key === "Enter" && !hasPendingRemoteUpdate) {
      handleSave();
    } else if (e.key === "Escape") {
      handleCancel();
    }
  };

  const handleBlur = () => {
    // Don't auto-save on blur if there's a pending remote update
    if (!hasPendingRemoteUpdate) {
      handleSave();
    }
  };

  const baseClassName = "font-mono text-[#9bc3ff]";
  const sizeClasses: Record<number, string> = {
    1: "text-2xl font-bold",
    2: "text-xl font-bold",
    3: "text-lg font-semibold",
    4: "text-base font-semibold",
    5: "text-sm font-semibold",
    6: "text-xs font-semibold",
  };
  const sizeClass = sizeClasses[level] || sizeClasses[3];

  if (isEditing && onUpdate) {
    return (
      <div>
        <input
          ref={inputRef}
          type="text"
          value={editText}
          onChange={(e) => setEditText(e.target.value)}
          onBlur={handleBlur}
          onKeyDown={handleKeyDown}
          className={`${baseClassName} ${sizeClass} w-full bg-transparent border-b border-[#3f6fb3] outline-none`}
        />
        {hasPendingRemoteUpdate && (
          <div className="flex items-center gap-2 mt-2">
            <span className="text-yellow-500 text-xs font-mono">Remote update pending</span>
            <button
              onClick={handleOverwrite}
              onMouseDown={(e) => e.preventDefault()}
              className="px-2 py-1 font-mono text-xs text-yellow-500 border border-yellow-500/50 hover:border-yellow-500 transition-colors"
            >
              Overwrite
            </button>
            <button
              onClick={handleCancel}
              onMouseDown={(e) => e.preventDefault()}
              className="px-2 py-1 font-mono text-xs text-[#555] hover:text-white/70 transition-colors"
            >
              Cancel
            </button>
          </div>
        )}
      </div>
    );
  }

  const HeadingTag = `h${level}` as "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
  return (
    <HeadingTag
      className={`${baseClassName} ${sizeClass} ${onUpdate ? "cursor-text hover:bg-[rgba(117,170,252,0.05)] px-1 -mx-1 rounded" : ""}`}
      onClick={() => onUpdate && startEditing()}
    >
      {text}
    </HeadingTag>
  );
}

function ParagraphElement({
  text,
  onUpdate,
  onEditingChange,
  hasPendingRemoteUpdate,
  onOverwrite,
}: {
  text: string;
  onUpdate?: (text: string) => void;
  onEditingChange?: (isEditing: boolean) => void;
  hasPendingRemoteUpdate?: boolean;
  onOverwrite?: () => void;
}) {
  const [isEditing, setIsEditing] = useState(false);
  const [editText, setEditText] = useState(text);
  const textareaRef = useRef<HTMLTextAreaElement>(null);

  useEffect(() => {
    // Only update editText if not currently editing
    if (!isEditing) {
      setEditText(text);
    }
  }, [text, isEditing]);

  useEffect(() => {
    if (isEditing && textareaRef.current) {
      textareaRef.current.focus();
      // Auto-resize textarea
      textareaRef.current.style.height = "auto";
      textareaRef.current.style.height = textareaRef.current.scrollHeight + "px";
    }
  }, [isEditing]);

  const startEditing = () => {
    setIsEditing(true);
    onEditingChange?.(true);
  };

  const stopEditing = () => {
    setIsEditing(false);
    onEditingChange?.(false);
  };

  const handleSave = () => {
    // Don't auto-save if there's a pending remote update
    if (hasPendingRemoteUpdate) return;

    if (onUpdate && editText.trim() !== text) {
      onUpdate(editText.trim());
    }
    stopEditing();
  };

  const handleOverwrite = () => {
    if (onUpdate && editText.trim() !== text) {
      onUpdate(editText.trim());
    }
    onOverwrite?.();
    stopEditing();
  };

  const handleCancel = () => {
    setEditText(text);
    stopEditing();
  };

  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (e.key === "Escape") {
      handleCancel();
    }
    // Ctrl/Cmd + Enter to save - disabled if there's a pending remote update
    if (e.key === "Enter" && (e.ctrlKey || e.metaKey) && !hasPendingRemoteUpdate) {
      handleSave();
    }
  };

  const handleBlur = () => {
    // Don't auto-save on blur if there's a pending remote update
    if (!hasPendingRemoteUpdate) {
      handleSave();
    }
  };

  const handleInput = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
    setEditText(e.target.value);
    // Auto-resize
    e.target.style.height = "auto";
    e.target.style.height = e.target.scrollHeight + "px";
  };

  if (isEditing && onUpdate) {
    return (
      <div className="relative">
        <textarea
          ref={textareaRef}
          value={editText}
          onChange={handleInput}
          onBlur={handleBlur}
          onKeyDown={handleKeyDown}
          className="font-mono text-sm text-white/80 leading-relaxed w-full bg-transparent border border-[#3f6fb3] outline-none p-2 resize-none min-h-[60px]"
        />
        {hasPendingRemoteUpdate ? (
          <div className="flex items-center gap-2 mt-2">
            <span className="text-yellow-500 text-xs font-mono">Remote update pending</span>
            <button
              onClick={handleOverwrite}
              onMouseDown={(e) => e.preventDefault()}
              className="px-2 py-1 font-mono text-xs text-yellow-500 border border-yellow-500/50 hover:border-yellow-500 transition-colors"
            >
              Overwrite
            </button>
            <button
              onClick={handleCancel}
              onMouseDown={(e) => e.preventDefault()}
              className="px-2 py-1 font-mono text-xs text-[#555] hover:text-white/70 transition-colors"
            >
              Cancel
            </button>
          </div>
        ) : (
          <div className="text-[10px] text-[#555] font-mono mt-1">
            Ctrl+Enter to save, Esc to cancel
          </div>
        )}
      </div>
    );
  }

  return (
    <p
      className={`font-mono text-sm text-white/80 leading-relaxed ${onUpdate ? "cursor-text hover:bg-[rgba(117,170,252,0.05)] px-1 -mx-1 rounded" : ""}`}
      onClick={() => onUpdate && startEditing()}
    >
      {text}
    </p>
  );
}

function ChartElement({
  chartType,
  data,
  title,
  config,
}: {
  chartType: "line" | "bar" | "pie" | "area";
  data: Record<string, unknown>[];
  title?: string;
  config?: Record<string, unknown>;
}) {
  return (
    <div className="border border-[#333] p-4 bg-black/30">
      <ChartRenderer
        chartType={chartType}
        data={data}
        title={title}
        config={config}
      />
    </div>
  );
}

function ImageElement({
  src,
  alt,
  caption,
}: {
  src: string;
  alt?: string;
  caption?: string;
}) {
  return (
    <figure className="space-y-2">
      <img
        src={src}
        alt={alt || ""}
        className="max-w-full border border-[#333]"
      />
      {caption && (
        <figcaption className="text-[#555] font-mono text-xs italic">
          {caption}
        </figcaption>
      )}
    </figure>
  );
}
