import { useMemo } from 'react';
import type { GalleryWindowSpec, GalleryWindowStyle } from '../data/movement-interior-styles';

const WALL_HEIGHT = 4.2;

interface Props {
  windows: GalleryWindowSpec[];
  halfW: number;
  halfD: number;
  trimColor: string;
}

function windowWorldPosition(
  spec: GalleryWindowSpec,
  halfW: number,
  halfD: number
): { position: [number, number, number]; rotation: [number, number, number] } {
  const inset = 0.1;
  switch (spec.wall) {
    case 'back':
      return {
        position: [spec.x, spec.y, -halfD + inset],
        rotation: [0, 0, 0],
      };
    case 'left':
      return {
        position: [-halfW + inset, spec.y, spec.x],
        rotation: [0, Math.PI / 2, 0],
      };
    case 'right':
      return {
        position: [halfW - inset, spec.y, spec.x],
        rotation: [0, -Math.PI / 2, 0],
      };
    case 'ceiling':
      return {
        position: [spec.x, WALL_HEIGHT - 0.06, spec.x === 0 ? 0 : spec.x],
        rotation: [Math.PI / 2, 0, 0],
      };
    default:
      return { position: [0, spec.y, -halfD + inset], rotation: [0, 0, 0] };
  }
}

function WindowFrame({
  style,
  width,
  height,
  trimColor,
}: {
  style: GalleryWindowStyle;
  width: number;
  height: number;
  trimColor: string;
}) {
  const frameW = 0.08;
  const depth = 0.12;

  const arch =
    style === 'roman-arch' || style === 'gothic-lancet' || style === 'art-nouveau';

  return (
    <group>
      {/* Outer frame */}
      <mesh position={[0, 0, -depth / 2]}>
        <boxGeometry args={[width + frameW * 2, height + frameW * 2, depth]} />
        <meshStandardMaterial color={trimColor} roughness={0.35} metalness={0.45} />
      </mesh>

      {arch && style === 'gothic-lancet' && (
        <>
          {/* Two-centred arch head built from short chords */}
          {Array.from({ length: 14 }, (_, i) => {
            const segs = 14;
            const rise = width * 0.62;
            const pt = (t: number): [number, number] => {
              const x = (t - 0.5) * (width + frameW * 2);
              const y = Math.pow(Math.cos((t - 0.5) * Math.PI), 0.72) * rise;
              return [x, y];
            };
            const [x0, y0] = pt(i / segs);
            const [x1, y1] = pt((i + 1) / segs);
            const len = Math.hypot(x1 - x0, y1 - y0);
            return (
              <mesh
                key={i}
                position={[(x0 + x1) / 2, height / 2 + (y0 + y1) / 2, -depth / 2 + 0.02]}
                rotation={[0, 0, Math.atan2(y1 - y0, x1 - x0)]}
              >
                <boxGeometry args={[len * 1.15, frameW * 1.4, depth]} />
                <meshStandardMaterial color={trimColor} roughness={0.55} metalness={0.15} />
              </mesh>
            );
          })}
          {/* Glazed spandrel filling the arch head */}
          <mesh position={[0, height / 2 + width * 0.16, 0.01]}>
            <planeGeometry args={[width * 0.72, width * 0.5]} />
            <meshStandardMaterial
              color="#9fc4ef"
              emissive="#9fc4ef"
              emissiveIntensity={0.6}
              toneMapped={false}
              transparent
              opacity={0.8}
            />
          </mesh>
          {/* Mullions and transoms */}
          {[-width / 4, width / 4].map((ox) => (
            <mesh key={ox} position={[ox, 0, -depth / 2 + 0.03]}>
              <boxGeometry args={[0.045, height, depth]} />
              <meshStandardMaterial color={trimColor} roughness={0.55} metalness={0.15} />
            </mesh>
          ))}
          {[height / 3, -height / 6].map((oy) => (
            <mesh key={oy} position={[0, oy, -depth / 2 + 0.03]}>
              <boxGeometry args={[width, 0.035, depth]} />
              <meshStandardMaterial color={trimColor} roughness={0.55} metalness={0.15} />
            </mesh>
          ))}
        </>
      )}

      {style === 'roman-arch' && (
        <mesh position={[0, height / 2 + 0.05, -depth / 2 + 0.02]} rotation={[0, 0, Math.PI]}>
          <sphereGeometry args={[width / 2, 16, 8, 0, Math.PI * 2, 0, Math.PI / 2]} />
          <meshStandardMaterial color={trimColor} roughness={0.4} metalness={0.35} />
        </mesh>
      )}

      {style === 'factory' && (
        <>
          {[-width / 3, 0, width / 3].map((ox) => (
            <mesh key={ox} position={[ox, 0, -depth / 2 + 0.02]}>
              <boxGeometry args={[0.06, height, depth + 0.02]} />
              <meshStandardMaterial color="#3a3a3a" roughness={0.5} metalness={0.6} />
            </mesh>
          ))}
          {[height / 4, -height / 4].map((oy) => (
            <mesh key={oy} position={[0, oy, -depth / 2 + 0.02]}>
              <boxGeometry args={[width, 0.06, depth + 0.02]} />
              <meshStandardMaterial color="#3a3a3a" roughness={0.5} metalness={0.6} />
            </mesh>
          ))}
        </>
      )}

      {style === 'glass-block' &&
        Array.from({ length: 4 }, (_, row) =>
          Array.from({ length: 3 }, (_, col) => (
            <mesh
              key={`${row}-${col}`}
              position={[
                -width / 3 + col * (width / 3),
                -height / 4 + row * (height / 4),
                -depth / 2 + 0.03,
              ]}
            >
              <boxGeometry args={[width / 3 - 0.06, height / 4 - 0.06, 0.04]} />
              <meshStandardMaterial
                color="#d0e8f8"
                roughness={0.1}
                metalness={0.05}
                transparent
                opacity={0.75}
              />
            </mesh>
          ))
        )}

      {style === 'sash' && (
        <mesh position={[0, 0, -depth / 2 + 0.03]}>
          <boxGeometry args={[0.05, height, depth]} />
          <meshStandardMaterial color={trimColor} roughness={0.45} metalness={0.3} />
        </mesh>
      )}

      {style === 'baroque-pair' && (
        <mesh position={[0, 0, -depth / 2 + 0.03]}>
          <boxGeometry args={[0.06, height, depth]} />
          <meshStandardMaterial color={trimColor} roughness={0.3} metalness={0.55} />
        </mesh>
      )}
    </group>
  );
}

function SingleWindow({
  spec,
  trimColor,
}: {
  spec: GalleryWindowSpec;
  trimColor: string;
}) {
  return (
    <group>
      <WindowFrame style={spec.style} width={spec.width} height={spec.height} trimColor={trimColor} />

      {/* Sky / daylight pane */}
      <mesh position={[0, 0, 0.02]}>
        <planeGeometry args={[spec.width - 0.12, spec.height - 0.12]} />
        <meshStandardMaterial
          color={spec.lightColor}
          emissive={spec.lightColor}
          emissiveIntensity={0.85}
          roughness={0.05}
          metalness={0.02}
          toneMapped={false}
          transparent
          opacity={0.92}
        />
      </mesh>

      {/* Soft sky gradient overlay */}
      <mesh position={[0, spec.height * 0.15, 0.03]}>
        <planeGeometry args={[spec.width - 0.2, spec.height * 0.5]} />
        <meshBasicMaterial color="#ffffff" transparent opacity={0.25} toneMapped={false} />
      </mesh>

      {/* One fill light per window — keep total scene lights well under WebGL limits. */}
      <spotLight
        position={[0, 0, 0.15]}
        angle={Math.min(1.2, (spec.width / Math.max(spec.height, 0.5)) * 0.55)}
        penumbra={0.95}
        intensity={spec.lightIntensity * Math.PI * 0.85}
        distance={14}
        decay={0}
        color={spec.lightColor}
      />
    </group>
  );
}

export default function GalleryWindows({ windows, halfW, halfD, trimColor }: Props) {
  return (
    <group>
      {windows.map((spec, i) => {
        const { position, rotation } = windowWorldPosition(spec, halfW, halfD);
        return (
          <group key={`${spec.wall}-${spec.x}-${i}`} position={position} rotation={rotation}>
            <SingleWindow spec={spec} trimColor={trimColor} />
          </group>
        );
      })}
    </group>
  );
}

/** Ceiling-mounted gallery track lights for even illumination. */
export function GalleryTrackLights({
  width,
  depth,
  intensity,
  color,
}: {
  width: number;
  depth: number;
  intensity: number;
  color: string;
}) {
  const positions = useMemo(() => {
    const pts: [number, number, number][] = [];
    // Cap fixtures so MeshStandard hall materials stay within WebGL light limits.
    const cols = Math.max(2, Math.min(3, Math.floor(width / 5)));
    const rows = Math.max(1, Math.min(2, Math.floor(depth / 8)));
    for (let c = 0; c < cols; c++) {
      for (let r = 0; r < rows; r++) {
        const x = -width / 2 + (width / (cols + 1)) * (c + 1);
        const z = -depth / 2 + (depth / (rows + 1)) * (r + 1);
        pts.push([x, WALL_HEIGHT - 0.15, z]);
      }
    }
    return pts;
  }, [width, depth]);

  return (
    <group>
      {positions.map(([x, y, z], i) => (
        <group key={i} position={[x, y, z]}>
          <mesh rotation={[Math.PI, 0, 0]}>
            <cylinderGeometry args={[0.02, 0.025, 0.12, 8]} />
            <meshStandardMaterial color="#2a2a2a" metalness={0.8} roughness={0.25} />
          </mesh>
          <spotLight
            position={[0, -0.04, 0]}
            angle={0.7}
            penumbra={0.9}
            intensity={intensity}
            distance={12}
            decay={0}
            color={color}
          />
        </group>
      ))}
    </group>
  );
}
