import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { OrganigramaUnitCard } from './OrganigramaUnitCard';
import { OrganigramaZoomControls } from './OrganigramaZoomControls';
import { layoutOrganigramaTree } from './organigramaLayout';
import { ORGANIGRAMA_DEFAULT_TREE } from './organigramaDefaults';
import {
  ORGANIGRAMA_CANVAS_BG,
  ORGANIGRAMA_CANVAS_DOT_COLOR,
  ORGANIGRAMA_DEFAULT_ZOOM,
  ORGANIGRAMA_EDGE_COLOR,
  ORGANIGRAMA_ZOOM_MAX,
  ORGANIGRAMA_ZOOM_MIN,
  ORGANIGRAMA_ZOOM_STEP,
} from './organigramaStyles';

function clampZoom(value) {
  return Math.min(ORGANIGRAMA_ZOOM_MAX, Math.max(ORGANIGRAMA_ZOOM_MIN, value));
}

export const Organigrama = ({
  tree = ORGANIGRAMA_DEFAULT_TREE,
  zoom: controlledZoom,
  onZoomChange,
  defaultZoom = ORGANIGRAMA_DEFAULT_ZOOM,
  height = 640,
  className = '',
  style,
  onCreateSubunit,
  onEditUnit,
  onAssignPerson,
  onDeleteUnit,
  onUnitClick,
  onAssignMembersClick,
}) => {
  const viewportRef = useRef(null);
  const [internalZoom, setInternalZoom] = useState(defaultZoom);
  const [pan, setPan] = useState({ x: 48, y: 48 });
  const [isPanning, setIsPanning] = useState(false);
  const panStartRef = useRef({ x: 0, y: 0, panX: 0, panY: 0 });

  const isControlled = typeof controlledZoom === 'number';
  const zoom = isControlled ? controlledZoom : internalZoom;

  const setZoom = useCallback(
    (nextZoom) => {
      const clamped = clampZoom(nextZoom);
      if (!isControlled) setInternalZoom(clamped);
      onZoomChange?.(clamped);
    },
    [isControlled, onZoomChange]
  );

  const layout = useMemo(() => layoutOrganigramaTree(tree), [tree]);

  const handleWheel = useCallback(
    (event) => {
      if (!event.ctrlKey && !event.metaKey) return;
      event.preventDefault();
      const delta = event.deltaY > 0 ? -ORGANIGRAMA_ZOOM_STEP : ORGANIGRAMA_ZOOM_STEP;
      setZoom(zoom + delta);
    },
    [setZoom, zoom]
  );

  useEffect(() => {
    const viewport = viewportRef.current;
    if (!viewport) return undefined;
    viewport.addEventListener('wheel', handleWheel, { passive: false });
    return () => viewport.removeEventListener('wheel', handleWheel);
  }, [handleWheel]);

  const handlePointerDown = (event) => {
    if (event.button !== 0) return;
    const target = event.target;
    if (target?.closest?.('[data-organigrama-card]')) return;
    setIsPanning(true);
    panStartRef.current = {
      x: event.clientX,
      y: event.clientY,
      panX: pan.x,
      panY: pan.y,
    };
  };

  const handlePointerMove = (event) => {
    if (!isPanning) return;
    const dx = event.clientX - panStartRef.current.x;
    const dy = event.clientY - panStartRef.current.y;
    setPan({
      x: panStartRef.current.panX + dx,
      y: panStartRef.current.panY + dy,
    });
  };

  const handlePointerUp = () => setIsPanning(false);

  const handleFitView = useCallback(() => {
    const viewport = viewportRef.current;
    if (!viewport || layout.width === 0 || layout.height === 0) return;
    const padding = 48;
    const availableW = viewport.clientWidth - padding * 2;
    const availableH = viewport.clientHeight - padding * 2;
    const scaleX = availableW / layout.width;
    const scaleY = availableH / layout.height;
    const nextZoom = clampZoom(Math.min(scaleX, scaleY, 1));
    setZoom(nextZoom);
    setPan({
      x: (viewport.clientWidth - layout.width * nextZoom) / 2,
      y: (viewport.clientHeight - layout.height * nextZoom) / 2,
    });
  }, [layout.height, layout.width, setZoom]);

  const canvasBackground = {
    backgroundColor: ORGANIGRAMA_CANVAS_BG,
    backgroundImage: `radial-gradient(${ORGANIGRAMA_CANVAS_DOT_COLOR} 1px, transparent 1px)`,
    backgroundSize: '20px 20px',
  };

  return (
    <div
      className={className}
      style={{
        position: 'relative',
        width: '100%',
        height,
        borderRadius: 12,
        overflow: 'hidden',
        border: '1px solid #E5E7EB',
        ...canvasBackground,
        ...style,
      }}
    >
      <div
        ref={viewportRef}
        role="application"
        aria-label="Organigrama organizacional"
        style={{
          width: '100%',
          height: '100%',
          overflow: 'hidden',
          cursor: isPanning ? 'grabbing' : 'grab',
          position: 'relative',
        }}
        onPointerDown={handlePointerDown}
        onPointerMove={handlePointerMove}
        onPointerUp={handlePointerUp}
        onPointerLeave={handlePointerUp}
      >
        <div
          style={{
            position: 'absolute',
            left: 0,
            top: 0,
            width: layout.width,
            height: layout.height,
            transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})`,
            transformOrigin: '0 0',
          }}
        >
          <svg
            width={layout.width}
            height={layout.height}
            style={{
              position: 'absolute',
              left: 0,
              top: 0,
              pointerEvents: 'none',
              overflow: 'visible',
            }}
            aria-hidden
          >
            {layout.edges.map((edge) => (
              <path
                key={`${edge.fromId}-${edge.toId}`}
                d={edge.path}
                fill="none"
                stroke={ORGANIGRAMA_EDGE_COLOR}
                strokeWidth={2}
              />
            ))}
          </svg>

          {layout.nodes.map(({ unit, x, y }) => (
            <div
              key={unit.id}
              data-organigrama-card
              style={{
                position: 'absolute',
                left: x,
                top: y,
              }}
            >
              <OrganigramaUnitCard
                unit={unit}
                onCreateSubunit={onCreateSubunit}
                onEditUnit={onEditUnit}
                onAssignPerson={onAssignPerson}
                onDeleteUnit={onDeleteUnit}
                onUnitClick={onUnitClick}
                onAssignMembersClick={onAssignMembersClick ?? onAssignPerson}
              />
            </div>
          ))}
        </div>
      </div>

      <OrganigramaZoomControls
        zoom={zoom}
        onZoomIn={() => setZoom(zoom + ORGANIGRAMA_ZOOM_STEP)}
        onZoomOut={() => setZoom(zoom - ORGANIGRAMA_ZOOM_STEP)}
        onFitView={handleFitView}
      />
    </div>
  );
};

export default Organigrama;
