import { type CSSProperties, useMemo } from "react";
import {
  DEFAULT_COLOR_NAME,
  DEFAULT_STROKE_COLOR,
  DEFAULT_STROKE_WIDTH,
  TRANSITION_STYLE,
} from "./constants";
import { ORGAN_COMPONENTS } from "./svg";
import type { OrganConfig, OrganId, OrganStyle, StrictColorPalette } from "./types";

export interface OrganSvgWrapperProps {
  /** Organ identifier */
  organId: OrganId;
  /** Organ configuration */
  config?: OrganConfig;
  /** Color palette to use for this organ (with guaranteed alpha values) */
  colorPalette: StrictColorPalette;
  /** Whether the organ is currently hovered */
  isHovered: boolean;
  /** Whether the organ is currently selected */
  isSelected: boolean;
  /** Mouse enter handler */
  onMouseEnter: () => void;
  /** Mouse leave handler */
  onMouseLeave: () => void;
  /** Click handler */
  onClick: () => void;
  /** X position in parent viewBox coordinate system */
  x: number;
  /** Y position in parent viewBox coordinate system */
  y: number;
  /** Width of the organ SVG viewport in viewBox units */
  width: number;
  /** Height of the organ SVG viewport in viewBox units */
  height: number;
  /** ViewBox for the organ SVG (local coordinate system) */
  viewBox: string;
  /** Show red outline around this organ */
  showOutline?: boolean;
  /** Whether the organ is visible (controls opacity for animation) */
  isVisible?: boolean;
}

/**
 * Merge multiple OrganStyle objects with priority (later objects override earlier)
 */
function mergeStyles(...styles: (OrganStyle | undefined)[]): OrganStyle {
  const result: OrganStyle = {};
  for (const style of styles) {
    if (style) {
      if (style.fill !== undefined) result.fill = style.fill;
      if (style.stroke !== undefined) result.stroke = style.stroke;
      if (style.strokeWidth !== undefined) result.strokeWidth = style.strokeWidth;
      if (style.opacity !== undefined) result.opacity = style.opacity;
      if (style.visible !== undefined) result.visible = style.visible;
      if (style.blur !== undefined) result.blur = style.blur;
    }
  }
  return result;
}

/**
 * Wrapper component for organ SVG with interaction handling
 */
export function OrganSvg({
  organId,
  config,
  colorPalette,
  isHovered,
  isSelected,
  onMouseEnter,
  onMouseLeave,
  onClick,
  x,
  y,
  width,
  height,
  viewBox,
  showOutline = false,
  isVisible = true,
}: OrganSvgWrapperProps) {
  const OrganComponent = ORGAN_COMPONENTS[organId];
  const isActive = isHovered || isSelected;

  // Compute the final style based on state and colorScheme
  const computedStyle = useMemo((): OrganStyle => {
    const userStyle = config?.style;
    const strokeStyle = {
      stroke: DEFAULT_STROKE_COLOR,
      strokeWidth: showOutline ? DEFAULT_STROKE_WIDTH : 0,
    };

    return mergeStyles(userStyle, strokeStyle);
  }, [config?.style, showOutline]);

  const [minX = 0, minY = 0, viewBoxWidth, viewBoxHeight] = viewBox.split(" ").map(Number);
  const scaleX = viewBoxWidth ? width / viewBoxWidth : 1;
  const scaleY = viewBoxHeight ? height / viewBoxHeight : 1;
  const transform = `translate(${x} ${y}) scale(${scaleX} ${scaleY}) translate(${-minX} ${-minY})`;
  const groupStyle: CSSProperties = {
    transition: `${TRANSITION_STYLE}, visibility 0s`,
  };
  const filter = isActive ? "blur(1px)" : undefined;

  return (
    <g
      transform={transform}
      style={groupStyle}
      filter={filter}
      aria-label={organId}
      opacity={isVisible ? 1 : 0}
      visibility={isVisible ? "visible" : "hidden"}
    >
      <title>{organId}</title>
      <g
        role="menuitem"
        onMouseEnter={onMouseEnter}
        onMouseLeave={onMouseLeave}
        onClick={onClick}
        onKeyDown={(e) => {
          if (e.key === "Enter" || e.key === " ") {
            e.preventDefault();
            onClick();
          }
        }}
        cursor="pointer"
        pointerEvents="auto"
      >
        <OrganComponent
          isActive={isActive}
          style={computedStyle}
          colorScale={colorPalette[config?.colorName ?? DEFAULT_COLOR_NAME]}
        />
      </g>
    </g>
  );
}
