import { useMemo } from 'react';
import type { MovementInteriorStyle, GalleryWindowSpec } from '../data/movement-interior-styles';
import type { RoomDims } from './hall-details/geometry';
import {
  CinquecentoDetails,
  QuattrocentoDetails,
  RomanAtriumDetails,
} from './hall-details/classical';
import {
  BaroqueStateDetails,
  FlemishDetails,
  ManneristDetails,
  NeoclassicalDetails,
  RococoDetails,
} from './hall-details/courtly';
import {
  ArtNouveauDetails,
  BourgeoisSalonDetails,
  GothicRevivalDetails,
  NorthLightSalonDetails,
  ParisAtelierDetails,
  SymbolistDetails,
} from './hall-details/nineteenth';
import {
  ConstructivistDetails,
  CubistAtelierDetails,
  DadaDetails,
  ExpressionistDetails,
  FauvistDetails,
  FuturistDetails,
  LoftDetails,
  SuprematistDetails,
  SurrealistDetails,
  WhiteCubeDetails,
} from './hall-details/modernism';

interface Props {
  style: MovementInteriorStyle;
  width: number;
  depth: number;
  halfW: number;
  halfD: number;
  /** Runtime window placement, so upper-wall relief can step around openings. */
  windows?: GalleryWindowSpec[];
}

function GothicDetails({ width, depth, halfW, halfD, trim }: Omit<Props, 'style' | 'windows'> & { trim: string }) {
  // Compound piers along the side walls, spaced by bay, each rising into the
  // vault springer. Shafts stay flush against the wall (0.16 m proud) so they
  // never intrude on the ~0.7 m frame hang margin.
  const bays = useMemo(() => {
    const spacing = 4.2;
    const count = Math.max(2, Math.min(9, Math.floor(depth / spacing)));
    const step = depth / (count + 1);
    return Array.from({ length: count }, (_, i) => -halfD + step * (i + 1));
  }, [depth, halfD]);

  const shaftHeight = 3.5;

  return (
    <group>
      {bays.map((z, i) => (
        <group key={i}>
          {[-1, 1].map((side) => (
            <group key={side} position={[side * (halfW - 0.09), 0, z]}>
              {/* Compound pier: a heavier centre shaft flanked by colonnettes */}
              <mesh position={[0, shaftHeight / 2, 0]}>
                <cylinderGeometry args={[0.1, 0.115, shaftHeight, 12]} />
                <meshStandardMaterial color="#a89e88" roughness={0.78} metalness={0.04} />
              </mesh>
              {[-0.17, 0.17].map((dz) => (
                <mesh key={dz} position={[0, shaftHeight / 2, dz]}>
                  <cylinderGeometry args={[0.052, 0.06, shaftHeight, 10]} />
                  <meshStandardMaterial color="#9e9482" roughness={0.82} metalness={0.03} />
                </mesh>
              ))}
              {/* Moulded base and foliate capital */}
              <mesh position={[0, 0.1, 0]}>
                <boxGeometry args={[0.28, 0.2, 0.52]} />
                <meshStandardMaterial color="#978d79" roughness={0.85} />
              </mesh>
              <mesh position={[0, shaftHeight + 0.12, 0]}>
                <boxGeometry args={[0.3, 0.24, 0.56]} />
                <meshStandardMaterial color="#b3a892" roughness={0.7} metalness={0.05} />
              </mesh>
              {/* Vault springer resting on the capital */}
              <mesh position={[0, shaftHeight + 0.36, 0]} rotation={[0, 0, Math.PI / 4]}>
                <boxGeometry args={[0.17, 0.17, 0.46]} />
                <meshStandardMaterial color={trim} roughness={0.72} metalness={0.06} />
              </mesh>
            </group>
          ))}

          {/* Transverse rib arching across the nave between opposite piers */}
          <group position={[0, shaftHeight + 0.42, z]}>
            {Array.from({ length: 9 }, (_, s) => {
              const segs = 9;
              const t0 = s / segs;
              const t1 = (s + 1) / segs;
              const xAt = (t: number) => -halfW + 0.09 + t * (halfW - 0.09) * 2;
              const yAt = (t: number) => Math.sin(Math.PI * t) * 0.34;
              const x0 = xAt(t0);
              const x1 = xAt(t1);
              const y0 = yAt(t0);
              const y1 = yAt(t1);
              const len = Math.hypot(x1 - x0, y1 - y0);
              return (
                <mesh
                  key={s}
                  position={[(x0 + x1) / 2, (y0 + y1) / 2, 0]}
                  rotation={[0, 0, Math.atan2(y1 - y0, x1 - x0)]}
                >
                  <boxGeometry args={[len * 1.06, 0.13, 0.16]} />
                  <meshStandardMaterial color="#b0a58f" roughness={0.74} metalness={0.05} />
                </mesh>
              );
            })}
          </group>
        </group>
      ))}

      {/* Moulded string course running the length of both side walls */}
      {[-1, 1].map((side) => (
        <mesh key={side} position={[side * (halfW - 0.05), 2.62, 0]}>
          <boxGeometry args={[0.12, 0.1, depth - 0.2]} />
          <meshStandardMaterial color="#b3a892" roughness={0.7} metalness={0.05} />
        </mesh>
      ))}

      {/* Chancel-style cornice on the end wall */}
      <mesh position={[0, 3.96, -halfD + 0.1]}>
        <boxGeometry args={[Math.max(2.4, width - 0.4), 0.16, 0.18]} />
        <meshStandardMaterial color="#b0a58f" roughness={0.7} metalness={0.05} />
      </mesh>
    </group>
  );
}

function ByzantineDetails({ halfW, halfD, trim }: Pick<Props, 'halfW' | 'halfD'> & { trim: string }) {
  // Engaged porphyry colonnettes with Byzantine basket/impost capitals at the
  // corners (flush — never proud of the ~0.7m frame hang margin), a marble
  // revetment dado at spring-line height, and hanging brass polycandela in
  // place of wall torches (a Byzantine basilica hangs its light, not sconces it).
  const colonnettes = useMemo(
    () =>
      [
        [-halfW + 0.08, -halfD + 0.08],
        [halfW - 0.08, -halfD + 0.08],
        [-halfW + 0.08, halfD - 0.08],
        [halfW - 0.08, halfD - 0.08],
      ] as [number, number][],
    [halfW, halfD]
  );

  const lampPositions = useMemo(
    () =>
      [
        [0, -halfD * 0.32],
        [0, halfD * 0.18],
      ] as [number, number][],
    [halfD]
  );

  const dadoW = Math.max(0, halfW * 2 - 0.3);
  const dadoD = Math.max(0, halfD * 2 - 0.3);

  return (
    <group>
      {/* Marble revetment dado — imperial banding course at chair-rail height */}
      {[
        [0, -halfD + 0.07, dadoW, 0.1] as const,
        [0, halfD - 0.07, dadoW, 0.1] as const,
        [-halfW + 0.07, 0, 0.1, dadoD] as const,
        [halfW - 0.07, 0, 0.1, dadoD] as const,
      ].map(([x, z, w, d], i) => (
        <group key={i}>
          <mesh position={[x, 0.62, z]}>
            <boxGeometry args={[w, 1.24, d]} />
            <meshStandardMaterial color="#6d5644" roughness={0.34} metalness={0.12} />
          </mesh>
          <mesh position={[x, 1.28, z]}>
            <boxGeometry args={[w * 1.004, 0.09, d * 1.004]} />
            <meshStandardMaterial color="#d8c8a8" roughness={0.42} metalness={0.1} />
          </mesh>
        </group>
      ))}

      {/* Engaged colonnettes, basket capital, and impost block */}
      {colonnettes.map(([x, z], i) => (
        <group key={i} position={[x, 0, z]}>
          {/* Polished porphyry shaft — the imperial stone of the reference basilicas */}
          <mesh position={[0, 1.95, 0]}>
            <cylinderGeometry args={[0.14, 0.16, 3.4, 14]} />
            <meshStandardMaterial color="#43222a" roughness={0.32} metalness={0.16} />
          </mesh>
          <mesh position={[0, 0.12, 0]}>
            <cylinderGeometry args={[0.17, 0.19, 0.24, 14]} />
            <meshStandardMaterial color="#d8cdb4" roughness={0.5} metalness={0.08} />
          </mesh>
          {/* Basket capital in white marble, then an impost block carrying the ceiling */}
          <mesh position={[0, 3.8, 0]}>
            <cylinderGeometry args={[0.22, 0.11, 0.3, 8]} />
            <meshStandardMaterial color="#e8e0cc" roughness={0.44} metalness={0.06} />
          </mesh>
          <mesh position={[0, 4.05, 0]}>
            <boxGeometry args={[0.28, 0.22, 0.28]} />
            <meshStandardMaterial color="#ded4bc" roughness={0.5} metalness={0.05} />
          </mesh>
        </group>
      ))}

      {/* Hanging polycandela — brass ring lamps suspended from the vault */}
      {lampPositions.map(([x, z], i) => (
        <group key={i} position={[x, 0, z]}>
          <mesh position={[0, 4.1, 0]}>
            <cylinderGeometry args={[0.012, 0.012, 0.5, 6]} />
            <meshStandardMaterial color="#5a4a20" roughness={0.4} metalness={0.6} />
          </mesh>
          <mesh position={[0, 3.84, 0]} rotation={[Math.PI / 2, 0, 0]}>
            <torusGeometry args={[0.32, 0.025, 8, 20]} />
            <meshStandardMaterial color={trim} roughness={0.25} metalness={0.8} emissive="#3a2808" emissiveIntensity={0.1} />
          </mesh>
          {Array.from({ length: 6 }, (_, j) => {
            const a = (j / 6) * Math.PI * 2;
            return (
              <mesh key={j} position={[Math.cos(a) * 0.32, 3.76, Math.sin(a) * 0.32]}>
                <sphereGeometry args={[0.045, 8, 8]} />
                <meshStandardMaterial color="#ffcf80" emissive="#ff9830" emissiveIntensity={0.9} toneMapped={false} />
              </mesh>
            );
          })}
          <pointLight position={[0, 3.76, 0]} intensity={0.85} distance={6} color="#ffb060" />
        </group>
      ))}
    </group>
  );
}

/**
 * Period architecture for a movement hall.
 *
 * Every movement has its own interior, built from the architecture of the same
 * period as the movement itself. The Gothic nave and Byzantine basilica below
 * are the reference implementations; everything else lives in
 * `hall-details/`, sharing the geometry budget documented in
 * `hall-details/primitives.tsx`.
 */
export default function MovementHallDetails({ style, width, depth, halfW, halfD, windows }: Props) {
  const trim = style.tints.trim;
  const room: RoomDims = useMemo(
    () => ({ width, depth, halfW, halfD }),
    [width, depth, halfW, halfD]
  );
  const period = { room, trim, windows };

  switch (style.details) {
    case 'gothic':
      return <GothicDetails width={width} depth={depth} halfW={halfW} halfD={halfD} trim={trim} />;
    case 'byzantine':
      return <ByzantineDetails halfW={halfW} halfD={halfD} trim={trim} />;
    case 'roman':
      return <RomanAtriumDetails {...period} />;
    case 'quattrocento':
      return <QuattrocentoDetails {...period} />;
    case 'cinquecento':
      return <CinquecentoDetails {...period} />;
    case 'flemish':
      return <FlemishDetails {...period} />;
    case 'mannerist':
      return <ManneristDetails {...period} />;
    case 'baroque':
      return <BaroqueStateDetails {...period} />;
    case 'rococo':
      return <RococoDetails {...period} />;
    case 'neoclassical':
      return <NeoclassicalDetails {...period} />;
    case 'gothic-revival':
      return <GothicRevivalDetails {...period} />;
    case 'bourgeois':
      return <BourgeoisSalonDetails {...period} />;
    case 'north-light':
      return <NorthLightSalonDetails {...period} />;
    case 'paris-atelier':
      return <ParisAtelierDetails {...period} />;
    case 'symbolist':
      return <SymbolistDetails {...period} />;
    case 'art-nouveau':
      return <ArtNouveauDetails {...period} />;
    case 'fauvist':
      return <FauvistDetails {...period} />;
    case 'expressionist':
      return <ExpressionistDetails {...period} />;
    case 'cubist-atelier':
      return <CubistAtelierDetails {...period} />;
    case 'futurist':
      return <FuturistDetails {...period} />;
    case 'suprematist':
      return <SuprematistDetails {...period} />;
    case 'constructivist':
      return <ConstructivistDetails {...period} />;
    case 'dada':
      return <DadaDetails {...period} />;
    case 'surrealist':
      return <SurrealistDetails {...period} />;
    case 'loft':
      return <LoftDetails {...period} />;
    case 'white-cube':
      return <WhiteCubeDetails {...period} />;
  }
}
