import { useMemo } from 'react';
import type { Wall, WallOpening } from '@house-plan-maker/shared';
import {
  wallRotationY,
  positionAlongWall3D,
} from './utils/wallGeometry';

interface DoorOpeningProps {
  readonly opening: WallOpening;
  readonly wall: Wall;
  readonly isSelected: boolean;
  readonly onSelect?: (id: string) => void;
  /**
   * When true, render the door panel ajar at ~30° to indicate swing
   * direction. When false, the panel sits flush with the frame (closed).
   * Toggled globally via the 3D view's HUD; not persisted on the opening.
   */
  readonly isOpen?: boolean;
}

const FRAME_COLOR = '#8b7355';
const DOOR_PANEL_COLOR = '#a0522d';
/** Fallback frame thickness for legacy openings without an explicit value. */
const DEFAULT_FRAME_THICKNESS = 0.03;
const DOOR_PANEL_THICKNESS = 0.04;

/** Angle (radians) the door panel is shown ajar when "open" mode is on. */
const DOOR_AJAR_ANGLE = Math.PI / 6; // 30 degrees

export function DoorOpening({ opening, wall, isSelected, onSelect, isOpen = true }: DoorOpeningProps) {
  const rotY = useMemo(() => wallRotationY(wall), [wall]);

  const [cx, cz] = useMemo(
    () => positionAlongWall3D(wall, opening.positionAlongWall),
    [wall, opening.positionAlongWall],
  );

  const frameColor = isSelected ? '#6fa8dc' : FRAME_COLOR;
  const halfWidth = opening.width / 2;
  const halfThick = wall.thickness / 2 + 0.005;
  // Per-opening frame thickness with a sane fallback for old data.
  const frameThickness = Math.max(0, opening.frameThickness ?? DEFAULT_FRAME_THICKNESS);

  // Door panel rotation based on open direction
  const openDir = opening.openDirection ?? 'LEFT';
  const isRight = openDir === 'RIGHT';
  const isInward = openDir === 'INWARD';

  // Effective ajar angle is 0 when the door is shown closed.
  const ajarAngle = isOpen ? DOOR_AJAR_ANGLE : 0;

  // Hinge position along the X axis (local frame coordinates)
  const hingeX = isRight ? halfWidth : -halfWidth;
  // Swing angle sign: inward swings in +Z, others swing in -Z
  const swingSign = isInward ? 1 : -1;
  const panelRotY = swingSign * ajarAngle * (isRight ? -1 : 1);
  // Panel center offset from hinge (half the door width along local X after rotation)
  const panelHalfW = opening.width / 2;
  const panelOffsetX = isRight
    ? -panelHalfW * Math.cos(ajarAngle)
    : panelHalfW * Math.cos(ajarAngle);
  const panelOffsetZ = swingSign * panelHalfW * Math.sin(ajarAngle);

  return (
    <group
      position={[cx, opening.elevationFromFloor + opening.height / 2, cz]}
      rotation={[0, rotY, 0]}
      onClick={onSelect ? (e) => { e.stopPropagation(); onSelect(opening.id); } : undefined}
    >
      {/* Left frame post */}
      <mesh position={[-halfWidth, 0, 0]} castShadow>
        <boxGeometry args={[frameThickness, opening.height, halfThick * 2]} />
        <meshStandardMaterial color={frameColor} roughness={0.5} />
      </mesh>

      {/* Right frame post */}
      <mesh position={[halfWidth, 0, 0]} castShadow>
        <boxGeometry args={[frameThickness, opening.height, halfThick * 2]} />
        <meshStandardMaterial color={frameColor} roughness={0.5} />
      </mesh>

      {/* Top frame bar (lintel) */}
      <mesh position={[0, opening.height / 2, 0]} castShadow>
        <boxGeometry args={[opening.width + frameThickness, frameThickness, halfThick * 2]} />
        <meshStandardMaterial color={frameColor} roughness={0.5} />
      </mesh>

      {/* Door panel (shown slightly ajar to indicate swing direction) */}
      <mesh
        position={[hingeX + panelOffsetX, 0, panelOffsetZ]}
        rotation={[0, panelRotY, 0]}
        castShadow
      >
        <boxGeometry args={[opening.width, opening.height - frameThickness, DOOR_PANEL_THICKNESS]} />
        <meshStandardMaterial color={DOOR_PANEL_COLOR} roughness={0.6} transparent opacity={0.85} />
      </mesh>
    </group>
  );
}
