import { useState, useRef, useCallback, useEffect } from 'react';
import { ZoomIn, ZoomOut, Maximize2, Download } from 'lucide-react';
import DOMPurify from 'dompurify';

interface EditState {
  component: string;
  rect: { top: number; left: number; width: number; height: number };
  currentValue: string;
}

interface SchematicViewerProps {
  svg: string;
  componentMap?: Record<string, string>;
  onValueChange?: (componentName: string, newValue: string) => void;
}

const ZOOM_STEPS = [0.5, 0.75, 1.0, 1.25, 1.5, 2.0];

// Allow SPICE values: digits, SI prefixes, decimal points, signs, parens, common SPICE chars
const SPICE_VALUE_RE = /^[0-9a-zA-Z._+\-*/(){}=, ]{1,200}$/;

function sanitizeSvg(raw: string): string {
  return DOMPurify.sanitize(raw, {
    USE_PROFILES: { svg: true, svgFilters: true },
    ADD_ATTR: ['data-component', 'data-editable', 'data-raw-value'],
  });
}

export function SchematicViewer({ svg, componentMap, onValueChange }: SchematicViewerProps) {
  const [zoomIndex, setZoomIndex] = useState(2); // Start at 100%
  const [editState, setEditState] = useState<EditState | null>(null);
  const containerRef = useRef<HTMLDivElement>(null);
  const svgWrapperRef = useRef<HTMLDivElement>(null);
  const inputRef = useRef<HTMLInputElement>(null);

  const zoom = ZOOM_STEPS[zoomIndex];

  const zoomIn = useCallback(() => {
    setZoomIndex((i) => Math.min(i + 1, ZOOM_STEPS.length - 1));
  }, []);

  const zoomOut = useCallback(() => {
    setZoomIndex((i) => Math.max(i - 1, 0));
  }, []);

  const fitToWidth = useCallback(() => {
    setZoomIndex(2); // Reset to 100%
  }, []);

  const downloadSvg = useCallback(() => {
    const blob = new Blob([svg], { type: 'image/svg+xml' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'schematic.svg';
    a.click();
    URL.revokeObjectURL(url);
  }, [svg]);

  // Dismiss edit overlay when SVG changes (e.g., after auto-redraw)
  useEffect(() => {
    setEditState(null);
  }, [svg]);

  // Inject sanitized SVG into the DOM and attach interactive handlers
  useEffect(() => {
    const wrapper = svgWrapperRef.current;
    if (!wrapper) return;

    wrapper.innerHTML = sanitizeSvg(svg);

    // Find all editable tspan elements and enhance them
    const editables = wrapper.querySelectorAll<SVGTSpanElement>('tspan[data-editable="true"]');

    // Track all handlers for proper cleanup
    const allHandlers: Array<{ el: SVGTSpanElement; event: string; handler: EventListener }> = [];

    const addHandler = (el: SVGTSpanElement, event: string, handler: EventListener) => {
      el.addEventListener(event, handler);
      allHandlers.push({ el, event, handler });
    };

    editables.forEach((tspan) => {
      tspan.style.cursor = 'pointer';

      addHandler(tspan, 'mouseenter', () => {
        tspan.style.fill = '#60a5fa'; // blue-400
      });
      addHandler(tspan, 'mouseleave', () => {
        tspan.style.fill = '';
      });

      // Click handler for inline editing
      const handleClick = (e: Event) => {
        (e as MouseEvent).stopPropagation();

        const parentText = tspan.closest('text');
        const componentName = parentText?.getAttribute('data-component');
        const rawValue = tspan.getAttribute('data-raw-value');

        if (!componentName || !rawValue) return;

        const container = containerRef.current;
        if (!container) return;

        // Get tspan position relative to the scroll container
        const tspanRect = tspan.getBoundingClientRect();
        const containerRect = container.getBoundingClientRect();

        setEditState({
          component: componentName,
          rect: {
            top: tspanRect.top - containerRect.top + container.scrollTop,
            left: tspanRect.left - containerRect.left + container.scrollLeft,
            width: Math.max(tspanRect.width, 60),
            height: tspanRect.height,
          },
          currentValue: rawValue,
        });
      };

      addHandler(tspan, 'click', handleClick);
    });

    // Cleanup all event listeners on unmount or SVG change
    return () => {
      allHandlers.forEach(({ el, event, handler }) => {
        el.removeEventListener(event, handler);
      });
    };
  }, [svg]);

  // Focus input when edit overlay appears
  useEffect(() => {
    if (editState && inputRef.current) {
      inputRef.current.focus();
      inputRef.current.select();
    }
  }, [editState]);

  const commitEdit = useCallback(() => {
    if (!editState) return;
    const input = inputRef.current;
    if (!input) return;

    const newValue = input.value.trim();
    if (!newValue || newValue === editState.currentValue) {
      setEditState(null);
      return;
    }

    // Validate value against SPICE-safe pattern
    if (!SPICE_VALUE_RE.test(newValue)) {
      setEditState(null);
      return;
    }

    // Optimistically update the tspan text in the live DOM
    const wrapper = svgWrapperRef.current;
    if (wrapper) {
      const escaped = CSS.escape(editState.component);
      const parentText = wrapper.querySelector(`text[data-component="${escaped}"]`);
      const valueTspan = parentText?.querySelector('tspan[data-editable="true"]');
      if (valueTspan) {
        valueTspan.textContent = newValue;
        valueTspan.setAttribute('data-raw-value', newValue);
      }
    }

    onValueChange?.(editState.component, newValue);
    setEditState(null);
  }, [editState, onValueChange]);

  const cancelEdit = useCallback(() => {
    setEditState(null);
  }, []);

  const handleKeyDown = useCallback(
    (e: React.KeyboardEvent<HTMLInputElement>) => {
      if (e.key === 'Enter') {
        e.preventDefault();
        commitEdit();
      } else if (e.key === 'Escape') {
        e.preventDefault();
        cancelEdit();
      }
    },
    [commitEdit, cancelEdit],
  );

  return (
    <div className="relative">
      {/* Toolbar */}
      <div className="flex items-center gap-1 px-3 py-1.5 border-b border-slate-700/50 bg-slate-800/50">
        <button
          onClick={zoomOut}
          disabled={zoomIndex === 0}
          className="p-1 rounded text-slate-400 hover:text-slate-200 hover:bg-slate-700/50 disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
          title="Zoom out"
        >
          <ZoomOut className="w-3.5 h-3.5" />
        </button>
        <span className="text-xs text-slate-500 tabular-nums w-10 text-center">
          {Math.round(zoom * 100)}%
        </span>
        <button
          onClick={zoomIn}
          disabled={zoomIndex === ZOOM_STEPS.length - 1}
          className="p-1 rounded text-slate-400 hover:text-slate-200 hover:bg-slate-700/50 disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
          title="Zoom in"
        >
          <ZoomIn className="w-3.5 h-3.5" />
        </button>
        <button
          onClick={fitToWidth}
          className="p-1 rounded text-slate-400 hover:text-slate-200 hover:bg-slate-700/50 transition-colors"
          title="Reset zoom"
        >
          <Maximize2 className="w-3.5 h-3.5" />
        </button>
        <div className="flex-1" />
        {componentMap && Object.keys(componentMap).length > 0 && (
          <span className="text-[10px] text-slate-600 mr-2">
            click values to edit
          </span>
        )}
        <button
          onClick={downloadSvg}
          className="flex items-center gap-1 px-2 py-1 rounded text-xs text-slate-400 hover:text-slate-200 hover:bg-slate-700/50 transition-colors"
          title="Download SVG"
        >
          <Download className="w-3.5 h-3.5" />
          <span>SVG</span>
        </button>
      </div>

      {/* SVG Canvas */}
      <div
        ref={containerRef}
        className="overflow-auto bg-white rounded-b-lg relative"
        style={{ maxHeight: '500px' }}
      >
        <div
          ref={svgWrapperRef}
          className="p-4"
          style={{
            transform: `scale(${zoom})`,
            transformOrigin: 'top left',
          }}
        />

        {/* Inline edit overlay */}
        {editState && (
          <input
            ref={inputRef}
            type="text"
            defaultValue={editState.currentValue}
            onKeyDown={handleKeyDown}
            onBlur={commitEdit}
            className="absolute z-10 px-1 py-0 text-sm font-mono bg-white border-2 border-blue-500 rounded shadow-lg outline-none text-slate-900"
            style={{
              top: editState.rect.top - 2,
              left: editState.rect.left - 4,
              minWidth: Math.max(editState.rect.width + 16, 72),
              height: editState.rect.height + 6,
              lineHeight: `${editState.rect.height + 2}px`,
            }}
          />
        )}
      </div>
    </div>
  );
}
