import React from 'react';
import type { 
  RungElement, Contact, Coil, Timer, Counter, LogicGate, MathElement, Branch,
  OneShot, MoveElement, ScaleElement, NoOp, CompareElement
} from '../../engine/types';

interface ElementProps {
  element: RungElement;
  x: number;
  y: number;
  width: number;
  height: number;
  isActive?: boolean;
  isEnergized?: boolean;
  isRunning?: boolean;
  isSelected?: boolean;
  onClick: (e: React.MouseEvent) => void;
  onDragStart?: (e: React.DragEvent) => void;
}

// Wrapper to enable drag on SVG groups (SVG <g> doesn't natively support draggable)
const DraggableGroup: React.FC<{
  className?: string;
  onClick: (e: React.MouseEvent) => void;
  onDragStart?: (e: React.DragEvent) => void;
  children: React.ReactNode;
}> = ({ className, onClick, onDragStart, children }) => {
  const groupRef = React.useRef<SVGGElement>(null);

  React.useEffect(() => {
    const el = groupRef.current;
    if (!el) return;
    el.setAttribute('draggable', 'true');
  }, []);

  return (
    <g
      ref={groupRef}
      className={className}
      onClick={onClick}
      onDragStart={onDragStart}
      style={{ cursor: 'pointer' }}
    >
      {children}
    </g>
  );
};

export const Element: React.FC<ElementProps> = ({ 
  element, x, y, width, height, isActive, isEnergized, isRunning, isSelected, onClick, onDragStart 
}) => {
  const plateActive = isActive || isEnergized || isRunning;
  const plateClass = ['element-plate'];
  if (plateActive) plateClass.push('active');
  if (isSelected) plateClass.push('selected');

  // Plate background with rounded corners and padding
  const PAD = 4;
  const plateX = x - PAD;
  const plateY = y - PAD;
  const plateW = width + PAD * 2;
  const plateH = height + PAD * 2;

  const cx = x + width / 2;
  const cy = y + height / 2;

  // Color shortcuts
  const activeColor = 'var(--success)';
  const inactiveColor = 'var(--text-primary)';
  const symColor = (plateActive && (isActive || isEnergized)) ? activeColor : inactiveColor;
  const labelColor = (plateActive && (isActive || isEnergized)) ? activeColor : 'var(--text-secondary)';

  const plate = (
    <rect
      className="element-bg"
      x={plateX} y={plateY} width={plateW} height={plateH}
      rx={4}
    />
  );

  // Common label above the plate (address)
  const labelAbove = (text: string, offset = -8) => (
    <text
      className="element-label-above"
      x={cx} y={plateY + offset}
      textAnchor="middle"
      fontSize="9"
      fill={labelColor}
    >
      {text}
    </text>
  );

  // Common label below the plate (type mnemonic)
  const labelBelow = (text: string) => (
    <text
      className="element-label"
      x={cx} y={plateY + plateH + 12}
      textAnchor="middle"
      fontSize="9"
      fill={labelColor}
    >
      {text}
    </text>
  );

  switch (element.type) {
    case 'contact': {
      const contact = element as Contact;
      const isNO = contact.contactType === 'NO';
      
      // Contact bars at ±13px from center for clear visibility
      const barOffset = 13;
      const barX1 = cx - barOffset;
      const barX2 = cx + barOffset;
      const barY1 = cy - 11;
      const barY2 = cy + 11;

      // Edge type label
      const edgeLabelMap: Record<string, string> = {
        RISING: 'OSR', FALLING: 'OSF', CHANGE: 'OSC',
      };
      const edgeLabel = contact.edgeType ? edgeLabelMap[contact.edgeType] ?? '' : '';

      return (
        <DraggableGroup className={plateClass.join(' ')} onClick={onClick} onDragStart={onDragStart}>
          {plate}

          {/* Left contact bar */}
          <line
            x1={barX1} y1={barY1} x2={barX1} y2={barY2}
            stroke={symColor} strokeWidth={2.5} strokeLinecap="round"
          />
          {/* Right contact bar */}
          <line
            x1={barX2} y1={barY1} x2={barX2} y2={barY2}
            stroke={symColor} strokeWidth={2.5} strokeLinecap="round"
          />

          {/* NC diagonal — top-left to bottom-right, only on Normally Closed */}
          {!isNO && (
            <line
              x1={barX1} y1={barY1 + 2}
              x2={barX2} y2={barY2 - 2}
              stroke={symColor} strokeWidth={1.5} strokeLinecap="round"
            />
          )}

          {/* Address — between the bars, centered */}
          <text
            className="element-label-above"
            x={cx} y={cy + 4}
            textAnchor="middle"
            fontSize="9"
            fontWeight="700"
            fill={symColor}
          >
            {contact.address}
          </text>

          {/* Edge type indicator above plate */}
          {edgeLabel && (
            <text
              x={cx} y={plateY - 3}
              textAnchor="middle"
              fontSize="7.5"
              fontWeight="700"
              fill={labelColor}
              fontFamily="'SF Mono', 'Consolas', monospace"
            >
              [{edgeLabel}]
            </text>
          )}

          {/* Type label below */}
          {labelBelow(isNO ? 'XIC' : 'XIO')}
        </DraggableGroup>
      );
    }

    case 'coil': {
      const coil = element as Coil;
      const latchIndicator = coil.coilType === 'LATCH' ? 'L' : coil.coilType === 'UNLATCH' ? 'U' : '';
      
      // Coil circle — slightly larger and cleaner
      const r = Math.min(width, height) / 2 - 1;

      const coilTypeLabel: Record<string, string> = {
        OUT: 'OTE', LATCH: 'OTL', UNLATCH: 'OTU',
      };
      const coilLabel = coilTypeLabel[coil.coilType ?? 'OUT'] ?? coil.coilType ?? 'OTE';

      return (
        <DraggableGroup className={plateClass.join(' ')} onClick={onClick} onDragStart={onDragStart}>
          {plate}

          {/* Coil circle */}
          <circle
            cx={cx} cy={cy}
            r={r}
            fill="none"
            stroke={symColor}
            strokeWidth={2.5}
          />

          {/* Latch/Unlatch interior marker */}
          {latchIndicator ? (
            <text
              x={cx} y={cy + 4}
              textAnchor="middle"
              fontSize="10"
              fontWeight="900"
              fill={symColor}
            >
              {latchIndicator}
            </text>
          ) : (
            /* Address label above for standard OTE */
            labelAbove(coil.address, -3)
          )}

          {/* Address below for latch types */}
          {latchIndicator && (
            <text
              className="element-label-above"
              x={cx} y={plateY - 3}
              textAnchor="middle"
              fontSize="9"
              fontWeight="700"
              fill={labelColor}
            >
              {coil.address}
            </text>
          )}

          {/* Type label below */}
          {labelBelow(coilLabel)}
        </DraggableGroup>
      );
    }

    case 'timer': {
      const timer = element as Timer;
      const boxX = x + 1;
      const boxY = y;
      const boxW = width - 2;
      const boxH = height;

      return (
        <DraggableGroup className={plateClass.join(' ')} onClick={onClick} onDragStart={onDragStart}>
          {plate}

          {/* Timer box — full height rect */}
          <rect
            x={boxX} y={boxY} width={boxW} height={boxH}
            fill={plateActive && isActive ? 'rgba(26,138,60,0.07)' : 'rgba(0,0,0,0.02)'}
            stroke={symColor}
            strokeWidth={1.5}
            rx={2}
          />

          {/* Header divider line */}
          <line
            x1={boxX + 1} y1={boxY + 16}
            x2={boxX + boxW - 1} y2={boxY + 16}
            stroke={symColor} strokeWidth={0.75} opacity={0.4}
          />

          {/* Timer type — bold header */}
          <text
            x={cx} y={boxY + 11}
            textAnchor="middle"
            fontSize="10"
            fontWeight="800"
            fill={symColor}
          >
            {timer.timerType}
          </text>

          {/* Instance ID */}
          <text
            x={cx} y={boxY + 26}
            textAnchor="middle"
            fontSize="8"
            fill={labelColor}
            fontFamily="'SF Mono', 'Consolas', monospace"
          >
            {timer.instanceId}
          </text>

          {/* PRE (Preset) */}
          <text
            x={cx} y={boxY + 37}
            textAnchor="middle"
            fontSize="8"
            fill={labelColor}
            fontFamily="'SF Mono', 'Consolas', monospace"
          >
            PRE: {(timer.preset / 1000).toFixed(1)}s
          </text>

          {/* ACC (Accumulated) */}
          <text
            x={cx} y={boxY + 48}
            textAnchor="middle"
            fontSize="8"
            fontWeight={isActive ? '700' : '400'}
            fill={isActive ? activeColor : labelColor}
            fontFamily="'SF Mono', 'Consolas', monospace"
          >
            ACC: {(timer.accumulated / 1000).toFixed(1)}s
          </text>

          {/* DN bit indicator — small dot when done */}
          {timer.accumulated >= timer.preset && timer.preset > 0 && (
            <circle cx={boxX + boxW - 5} cy={boxY + 5} r={3}
              fill={activeColor} opacity={0.9}
            />
          )}
        </DraggableGroup>
      );
    }

    case 'counter': {
      const counter = element as Counter;
      const boxX = x + 1;
      const boxY = y;
      const boxW = width - 2;
      const boxH = height;
      const isDone = counter.current !== undefined && counter.preset !== undefined &&
        (counter.counterType === 'CTD' ? counter.current <= 0 : counter.current >= counter.preset);

      return (
        <DraggableGroup className={plateClass.join(' ')} onClick={onClick} onDragStart={onDragStart}>
          {plate}

          <rect
            x={boxX} y={boxY} width={boxW} height={boxH}
            fill={plateActive && isActive ? 'rgba(26,138,60,0.07)' : 'rgba(0,0,0,0.02)'}
            stroke={symColor}
            strokeWidth={1.5}
            rx={2}
          />

          {/* Header divider */}
          <line
            x1={boxX + 1} y1={boxY + 16}
            x2={boxX + boxW - 1} y2={boxY + 16}
            stroke={symColor} strokeWidth={0.75} opacity={0.4}
          />

          {/* Counter type */}
          <text
            x={cx} y={boxY + 11}
            textAnchor="middle"
            fontSize="10"
            fontWeight="800"
            fill={symColor}
          >
            {counter.counterType}
          </text>

          {/* Instance ID */}
          <text
            x={cx} y={boxY + 26}
            textAnchor="middle"
            fontSize="8"
            fill={labelColor}
            fontFamily="'SF Mono', 'Consolas', monospace"
          >
            {counter.instanceId}
          </text>

          {/* PV */}
          <text
            x={cx} y={boxY + 37}
            textAnchor="middle"
            fontSize="8"
            fill={labelColor}
            fontFamily="'SF Mono', 'Consolas', monospace"
          >
            PV: {counter.preset}
          </text>

          {/* ACC */}
          <text
            x={cx} y={boxY + 48}
            textAnchor="middle"
            fontSize="8"
            fontWeight={isDone ? '700' : '400'}
            fill={isDone ? activeColor : labelColor}
            fontFamily="'SF Mono', 'Consolas', monospace"
          >
            ACC: {counter.current ?? 0}
          </text>

          {/* DN bit dot */}
          {isDone && (
            <circle cx={boxX + boxW - 5} cy={boxY + 5} r={3}
              fill={activeColor} opacity={0.9}
            />
          )}
        </DraggableGroup>
      );
    }

    case 'gate': {
      const gate = element as LogicGate;
      return (
        <DraggableGroup className={plateClass.join(' ')} onClick={onClick} onDragStart={onDragStart}>
          {plate}
          <rect
            x={x + 2} y={y} width={width - 4} height={height}
            fill="none" stroke={symColor} strokeWidth={1.5} rx={2}
          />
          <text x={cx} y={cy + 4} textAnchor="middle" fontSize="9" fontWeight="800" fill={symColor}>
            {gate.gateType}
          </text>
          {labelBelow(gate.outputAddress)}
        </DraggableGroup>
      );
    }

    case 'math': {
      const math = element as MathElement;
      const mnemonicMap: Record<string, string> = {
        '+': 'ADD', '-': 'SUB', '*': 'MUL', '/': 'DIV',
      };
      const mnemonic = mnemonicMap[math.operator] ?? math.operator;
      return (
        <DraggableGroup className={plateClass.join(' ')} onClick={onClick} onDragStart={onDragStart}>
          {plate}
          <rect
            x={x + 2} y={y} width={width - 4} height={height}
            fill="none" stroke={symColor} strokeWidth={1.5} rx={2}
          />
          <text x={cx} y={cy - 1} textAnchor="middle" fontSize="10" fontWeight="800" fill={symColor}>
            {mnemonic}
          </text>
          <text x={cx} y={cy + 11} textAnchor="middle" fontSize="7.5" fill={labelColor}
            fontFamily="'SF Mono', 'Consolas', monospace">
            {math.outputAddress}
          </text>
        </DraggableGroup>
      );
    }

    case 'branch': {
      const branch = element as Branch;
      const pathCount = branch.paths.length;
      const pathSlotH = 40;
      const branchHeight = pathCount * pathSlotH;

      return (
        <g className={plateClass.join(' ')} onClick={onClick}>
          <rect
            x={x - 4} y={y - 4}
            width={width + 8} height={branchHeight + 8}
            fill="rgba(0,0,0,0.02)"
            stroke="rgba(0,0,0,0.12)"
            strokeWidth={0.75}
            rx={4}
            strokeDasharray="5,3"
          />
          {/* Left vertical bus bar */}
          <line
            x1={x} y1={y} x2={x} y2={y + branchHeight}
            stroke="var(--wire-inactive)" strokeWidth={2.5} strokeLinecap="round"
          />
          {/* Right vertical bus bar */}
          <line
            x1={x + width} y1={y} x2={x + width} y2={y + branchHeight}
            stroke="var(--wire-inactive)" strokeWidth={2.5} strokeLinecap="round"
          />
          {branch.paths.map((_, pathIdx) => {
            const pathY = y + pathIdx * pathSlotH + pathSlotH / 2;
            return (
              <line
                key={pathIdx}
                x1={x} y1={pathY} x2={x + width} y2={pathY}
                stroke="var(--wire-inactive)" strokeWidth={1}
                strokeDasharray="4,3" opacity={0.45}
              />
            );
          })}
          {/* Logic badge */}
          <rect
            x={cx - 14} y={y - 15}
            width={28} height={12}
            fill="var(--text-secondary)" rx={6} opacity={0.8}
          />
          <text
            x={cx} y={y - 7}
            textAnchor="middle" fontSize="7.5" fontWeight="700" fill="#fff"
            fontFamily="'Segoe UI', system-ui, sans-serif"
          >
            {branch.logic}
          </text>
        </g>
      );
    }

    case 'oneshot': {
      const os = element as OneShot;
      const barOffset = 13;
      const barX1 = cx - barOffset;
      const barX2 = cx + barOffset;
      const barY1 = cy - 11;
      const barY2 = cy + 11;
      const isRising = os.edgeType === 'RISING';

      // Step marker geometry
      const smTop = cy - 5;
      const smBot = cy + 5;
      const smMid = cx;
      const smL = cx - 7;
      const smR = cx + 7;

      const stepPoints = isRising
        ? `${smL},${smBot} ${smL},${smTop} ${smMid},${smTop} ${smMid},${smBot} ${smR},${smBot}`
        : `${smL},${smTop} ${smL},${smBot} ${smMid},${smBot} ${smMid},${smTop} ${smR},${smTop}`;

      return (
        <DraggableGroup className={plateClass.join(' ')} onClick={onClick} onDragStart={onDragStart}>
          {plate}
          {/* Contact bars */}
          <line x1={barX1} y1={barY1} x2={barX1} y2={barY2}
            stroke={symColor} strokeWidth={2.5} strokeLinecap="round" />
          <line x1={barX2} y1={barY1} x2={barX2} y2={barY2}
            stroke={symColor} strokeWidth={2.5} strokeLinecap="round" />
          {/* Edge step marker */}
          <polyline
            points={stepPoints}
            fill="none" stroke={symColor} strokeWidth={1.75} strokeLinecap="round" strokeLinejoin="round"
          />
          {/* Address above */}
          <text x={cx} y={plateY - 3} textAnchor="middle" fontSize="9" fontWeight="700" fill={labelColor}>
            {os.address}
          </text>
          {labelBelow(isRising ? 'OSR' : 'OSF')}
        </DraggableGroup>
      );
    }

    case 'move': {
      const move = element as MoveElement;
      return (
        <DraggableGroup className={plateClass.join(' ')} onClick={onClick} onDragStart={onDragStart}>
          {plate}
          <rect x={x + 2} y={y} width={width - 4} height={height}
            fill="none" stroke={symColor} strokeWidth={1.5} rx={2} />
          <text x={cx} y={cy - 1} textAnchor="middle" fontSize="10" fontWeight="800" fill={symColor}>
            MOV
          </text>
          <text x={cx} y={cy + 11} textAnchor="middle" fontSize="7.5" fill={labelColor}
            fontFamily="'SF Mono', 'Consolas', monospace">
            {move.source}→{move.destination}
          </text>
        </DraggableGroup>
      );
    }

    case 'scale': {
      const scale = element as ScaleElement;
      return (
        <DraggableGroup className={plateClass.join(' ')} onClick={onClick} onDragStart={onDragStart}>
          {plate}
          <rect x={x + 2} y={y} width={width - 4} height={height}
            fill="none" stroke={symColor} strokeWidth={1.5} rx={2} />
          <text x={cx} y={cy - 1} textAnchor="middle" fontSize="10" fontWeight="800" fill={symColor}>
            SCL
          </text>
          <text x={cx} y={cy + 11} textAnchor="middle" fontSize="7.5" fill={labelColor}
            fontFamily="'SF Mono', 'Consolas', monospace">
            {scale.inputAddress}
          </text>
        </DraggableGroup>
      );
    }

    case 'compare': {
      const cmp = element as CompareElement;
      const mnemonicMap: Record<string, string> = {
        '==': 'EQU', '!=': 'NEQ', '>': 'GRT', '<': 'LES', '>=': 'GEQ', '<=': 'LEQ',
      };
      const mnemonic = mnemonicMap[cmp.op] ?? 'CMP';
      return (
        <DraggableGroup className={plateClass.join(' ')} onClick={onClick} onDragStart={onDragStart}>
          {plate}
          <rect x={x + 2} y={y} width={width - 4} height={height}
            fill="none" stroke={symColor} strokeWidth={1.5} rx={2} />
          <text x={cx} y={cy - 1} textAnchor="middle" fontSize="10" fontWeight="800" fill={symColor}>
            {mnemonic}
          </text>
          <text x={cx} y={cy + 11} textAnchor="middle" fontSize="7.5" fill={labelColor}
            fontFamily="'SF Mono', 'Consolas', monospace">
            {cmp.inputA} {cmp.op} {cmp.inputB}
          </text>
        </DraggableGroup>
      );
    }

    case 'noop': {
      const noop = element as NoOp;
      return (
        <DraggableGroup className={plateClass.join(' ')} onClick={onClick} onDragStart={onDragStart}>
          {plate}
          <rect x={x + 2} y={y} width={width - 4} height={height}
            fill="none" stroke="var(--text-muted)"
            strokeWidth={1} strokeDasharray="3,2" rx={2} />
          <text x={cx} y={cy + 4} textAnchor="middle" fontSize="8" fill="var(--text-muted)">
            {noop.comment ? noop.comment : 'NOP'}
          </text>
        </DraggableGroup>
      );
    }

    default:
      return null;
  }
};