import { useMemo } from 'react';
import * as THREE from 'three';
import type { Point, Wall, WallOpening } from '@house-plan-maker/shared';
import {
  getOpeningSlices,
  wallVector,
  wallNormal,
  wallRotationY,
  positionAlongWall3D,
} from './utils/wallGeometry';

interface PlinthMeshProps {
  readonly wall: Wall;
  readonly openings: readonly WallOpening[];
  readonly plinthHeight: number;
  readonly plinthThickness: number;
  /** See WallMesh — same outward shift so the plinth stays aligned with the wall. */
  readonly roomCentroid?: Point;
}

const PLINTH_COLOR = '#d4c5b2';

// ── Shared plinth material (module-level singleton) ──
const plinthMaterial = new THREE.MeshStandardMaterial({
  color: PLINTH_COLOR,
  roughness: 0.6,
});

interface PlinthSegment {
  readonly startAlongWall: number;
  readonly endAlongWall: number;
}

/**
 * Compute plinth segments for a wall — continuous along wall base,
 * interrupted at door openings (openings with elevationFromFloor === 0).
 */
function computePlinthSegments(
  wall: Wall,
  openings: readonly WallOpening[],
): readonly PlinthSegment[] {
  const { length } = wallVector(wall);
  const slices = getOpeningSlices(wall, openings);

  // Only doors (elevationFromFloor === 0) interrupt the plinth
  const doorSlices = slices.filter((s) => s.opening.elevationFromFloor === 0);

  if (doorSlices.length === 0) {
    return [{ startAlongWall: 0, endAlongWall: length }];
  }

  const segments: PlinthSegment[] = [];
  let cursor = 0;

  for (const slice of doorSlices) {
    if (slice.startAlongWall > cursor) {
      segments.push({ startAlongWall: cursor, endAlongWall: slice.startAlongWall });
    }
    cursor = slice.endAlongWall;
  }

  if (cursor < length) {
    segments.push({ startAlongWall: cursor, endAlongWall: length });
  }

  return segments;
}

export function PlinthMesh({ wall, openings, plinthHeight, plinthThickness, roomCentroid }: PlinthMeshProps) {
  const segments = useMemo(
    () => computePlinthSegments(wall, openings),
    [wall, openings],
  );

  const rotY = useMemo(() => wallRotationY(wall), [wall]);

  // Same outward shift as the wall — see WallMesh.outwardOffset.
  const outwardOffset = useMemo<[number, number]>(() => {
    if (!roomCentroid) return [0, 0];
    const { nx, ny } = wallNormal(wall);
    if (nx === 0 && ny === 0) return [0, 0];
    const midX = (wall.startX + wall.endX) / 2;
    const midY = (wall.startY + wall.endY) / 2;
    const outX = midX - roomCentroid.x;
    const outY = midY - roomCentroid.y;
    const sign = nx * outX + ny * outY >= 0 ? 1 : -1;
    const half = wall.thickness / 2;
    return [sign * nx * half, sign * ny * half];
  }, [wall, roomCentroid]);

  if (plinthHeight <= 0 || plinthThickness <= 0) return null;

  return (
    <group>
      {segments.map((segment, i) => {
        const segLen = segment.endAlongWall - segment.startAlongWall;
        if (segLen <= 0) return null;

        const midAlongWall = (segment.startAlongWall + segment.endAlongWall) / 2;
        const [cx, cz] = positionAlongWall3D(wall, midAlongWall);

        return (
          <mesh
            key={`${wall.id}-plinth-${i}`}
            position={[cx + outwardOffset[0], plinthHeight / 2, cz + outwardOffset[1]]}
            rotation={[0, rotY, 0]}
            castShadow
            material={plinthMaterial}
          >
            <boxGeometry args={[segLen, plinthHeight, wall.thickness + plinthThickness * 2]} />
          </mesh>
        );
      })}
    </group>
  );
}
