'use client'
// src/components/projects/StructureScene.tsx
// Input: project (Project), sensors (Sensor[]), selectedId (string|null), onSelect (fn)
// Output: scène 3D procédurale r3f selon project.structure (bridge ou building)
// Rationale: rendu dans SceneWrapper (ssr:false), meshes primitifs, capteurs cliquables

import { useMemo } from 'react'
import type { Project, Sensor } from '@/types'
import { SensorMarker } from './SensorMarker'

// ── Helpers de mapping coordonnées ──────────────────────────────────────────

function bridgePos(
  nx: number, ny: number, nz: number,
  halfSpan: number, pylonH: number, halfW: number,
): [number, number, number] {
  // nx: -1..1 → along span (X)
  // ny: 0..1 → vertical (Y), 0 = tablier, 1 = sommet pylône
  // nz: -1..1 → transversal (Z)
  return [nx * halfSpan, ny * pylonH, nz * halfW]
}

function buildingPos(
  nx: number, ny: number, nz: number,
  totalH: number, halfW: number, halfD: number,
): [number, number, number] {
  // ny: 0..1 → de bas (0) en haut (1)
  return [nx * halfW, ny * totalH, nz * halfD]
}

// ── Câble (cylindre très fin) entre deux points ──────────────────────────────

function Cable({
  from,
  to,
  color = '#1E3A4A',
}: {
  from: [number, number, number]
  to: [number, number, number]
  color?: string
}) {
  const { position, rotation, length } = useMemo(() => {
    const dx = to[0] - from[0]
    const dy = to[1] - from[1]
    const dz = to[2] - from[2]
    const len = Math.sqrt(dx * dx + dy * dy + dz * dz)
    const cx = (from[0] + to[0]) / 2
    const cy = (from[1] + to[1]) / 2
    const cz = (from[2] + to[2]) / 2

    // Orientation : Y-up cylinder vers le vecteur
    const theta = Math.atan2(Math.sqrt(dx * dx + dz * dz), dy)
    const phi = Math.atan2(dz, dx)

    return {
      position: [cx, cy, cz] as [number, number, number],
      rotation: [0, -phi, theta] as [number, number, number],
      length: len,
    }
  }, [from, to])

  return (
    <mesh position={position} rotation={rotation}>
      <cylinderGeometry args={[0.015, 0.015, length, 4]} />
      <meshStandardMaterial color={color} roughness={0.8} metalness={0.3} />
    </mesh>
  )
}

// ── SceneBackground ──────────────────────────────────────────────────────────

function BridgeStructure({
  project,
  sensors,
  selectedId,
  onSelect,
}: {
  project: Project
  sensors: Sensor[]
  selectedId: string | null
  onSelect: (id: string) => void
}) {
  const geo = project.structure
  const span = geo.span ?? 200
  const pylonCount = geo.pylonCount ?? 2
  const deckWidth = geo.deckWidth ?? 10
  const deckHeight = geo.deckHeight ?? 3
  const cableCount = geo.cableCount ?? 16

  // Normalisation : demi-valeurs
  const halfSpan = span / 100 * 5    // scaler pour que ~20 unités = full span
  const pylonH = (span / 100) * 4   // hauteur pylon proportionnelle
  const halfW = deckWidth / 100 * 3  // largeur tablier

  const SCALE = 5 / Math.max(halfSpan, 1)
  const scaledSpan = halfSpan * SCALE
  const scaledPylonH = pylonH * SCALE
  const scaledW = halfW * SCALE

  // Positions des pylônes le long du tablier
  const pylonPositions = useMemo(() => {
    return Array.from({ length: pylonCount }, (_, i) => {
      const t = pylonCount === 1 ? 0 : (i / (pylonCount - 1)) * 2 - 1
      return t * scaledSpan * 0.45
    })
  }, [pylonCount, scaledSpan])

  // Câbles depuis sommet pylon vers tablier (éventail)
  const cables = useMemo(() => {
    const result: Array<{ from: [number, number, number]; to: [number, number, number] }> = []
    const cablesPerPylon = Math.floor(cableCount / Math.max(pylonCount, 1))

    pylonPositions.forEach((px) => {
      const pylonTop: [number, number, number] = [px, scaledPylonH, 0]
      for (let c = 0; c < cablesPerPylon; c++) {
        const t = cablesPerPylon === 1 ? 0 : (c / (cablesPerPylon - 1)) * 2 - 1
        const anchorX = t * scaledSpan * 0.9
        const anchor: [number, number, number] = [anchorX, deckHeight * SCALE * 0.5, 0]
        result.push({ from: pylonTop, to: anchor })
      }
    })
    return result
  }, [pylonPositions, scaledPylonH, scaledSpan, cableCount, deckHeight, SCALE])

  // Mapping des capteurs
  const sensorLookup = useMemo(() => {
    const m: Record<string, Sensor> = {}
    sensors.forEach((s) => { m[s.id] = s })
    return m
  }, [sensors])

  return (
    <group>
      {/* Tablier */}
      <mesh position={[0, 0, 0]}>
        <boxGeometry args={[scaledSpan * 2, deckHeight * SCALE, scaledW * 2]} />
        <meshStandardMaterial
          color="#0F1E2E"
          emissive="#0a2030"
          emissiveIntensity={0.3}
          roughness={0.7}
          metalness={0.4}
        />
      </mesh>

      {/* Lignes de contour tablier (EdgeGeometry via wireframe overlay) */}
      <mesh position={[0, 0, 0]}>
        <boxGeometry args={[scaledSpan * 2, deckHeight * SCALE, scaledW * 2]} />
        <meshStandardMaterial
          color="#3DB8E8"
          wireframe
          transparent
          opacity={0.08}
        />
      </mesh>

      {/* Pylônes */}
      {pylonPositions.map((px, i) => (
        <group key={i} position={[px, 0, 0]}>
          {/* Fût du pylône */}
          <mesh position={[0, scaledPylonH / 2 + deckHeight * SCALE * 0.5, 0]}>
            <cylinderGeometry args={[0.15 * SCALE * 2, 0.22 * SCALE * 2, scaledPylonH, 8]} />
            <meshStandardMaterial
              color="#112233"
              emissive="#3DB8E8"
              emissiveIntensity={0.1}
              roughness={0.5}
              metalness={0.6}
            />
          </mesh>
          {/* Base pylône */}
          <mesh position={[0, -(deckHeight * SCALE * 0.3), 0]}>
            <boxGeometry args={[0.6 * SCALE * 2, 0.5 * SCALE * 2, 0.6 * SCALE * 2]} />
            <meshStandardMaterial color="#0a1a2a" roughness={0.8} metalness={0.3} />
          </mesh>
        </group>
      ))}

      {/* Câbles */}
      {cables.map((c, i) => (
        <Cable
          key={i}
          from={[c.from[0], c.from[1] + deckHeight * SCALE * 0.5, c.from[2]]}
          to={[c.to[0], c.to[1], c.to[2]]}
          color="#1E3A4A"
        />
      ))}

      {/* Capteurs */}
      {geo.sensorPositions.map((sp) => {
        const sensor = sensorLookup[sp.sensorId]
        if (!sensor) return null
        const pos: [number, number, number] = [
          sp.x * scaledSpan,
          sp.y * scaledPylonH + deckHeight * SCALE * 0.5,
          sp.z * scaledW * 2,
        ]
        return (
          <SensorMarker
            key={sp.sensorId}
            sensor={sensor}
            position={pos}
            selected={selectedId === sensor.id}
            onClick={onSelect}
          />
        )
      })}
    </group>
  )
}

function BuildingStructure({
  project,
  sensors,
  selectedId,
  onSelect,
}: {
  project: Project
  sensors: Sensor[]
  selectedId: string | null
  onSelect: (id: string) => void
}) {
  const geo = project.structure
  const floors = geo.floors ?? 8
  const floorHeight = geo.floorHeight ?? 3.5
  const width = geo.width ?? 20
  const depth = geo.depth ?? 20

  // Scale pour tenir dans ~10 unités de haut
  const SCALE = 6 / (floors * floorHeight)
  const scaledFH = floorHeight * SCALE
  const scaledW = width * SCALE * 0.5
  const scaledD = depth * SCALE * 0.5
  const totalH = floors * scaledFH

  const sensorLookup = useMemo(() => {
    const m: Record<string, Sensor> = {}
    sensors.forEach((s) => { m[s.id] = s })
    return m
  }, [sensors])

  // Colonnes aux 4 coins
  const colPositions: [number, number, number][] = [
    [-scaledW * 0.85, totalH / 2, -scaledD * 0.85],
    [ scaledW * 0.85, totalH / 2, -scaledD * 0.85],
    [-scaledW * 0.85, totalH / 2,  scaledD * 0.85],
    [ scaledW * 0.85, totalH / 2,  scaledD * 0.85],
  ]

  return (
    <group position={[0, -totalH / 2, 0]}>
      {/* Corps principal du bâtiment */}
      <mesh position={[0, totalH / 2, 0]}>
        <boxGeometry args={[scaledW * 2, totalH, scaledD * 2]} />
        <meshStandardMaterial
          color="#0D1B2A"
          emissive="#0a1a2a"
          emissiveIntensity={0.2}
          roughness={0.6}
          metalness={0.4}
        />
      </mesh>

      {/* Wireframe overlay accent */}
      <mesh position={[0, totalH / 2, 0]}>
        <boxGeometry args={[scaledW * 2, totalH, scaledD * 2]} />
        <meshStandardMaterial
          color="#3DB8E8"
          wireframe
          transparent
          opacity={0.06}
        />
      </mesh>

      {/* Lignes d'étages (dalle par dalle) */}
      {Array.from({ length: floors }, (_, i) => (
        <mesh key={i} position={[0, i * scaledFH + scaledFH * 0.5, 0]}>
          <boxGeometry args={[scaledW * 2 + 0.02, 0.04, scaledD * 2 + 0.02]} />
          <meshStandardMaterial
            color="#3DB8E8"
            emissive="#3DB8E8"
            emissiveIntensity={0.4}
            transparent
            opacity={0.35}
          />
        </mesh>
      ))}

      {/* Colonnes */}
      {colPositions.map((pos, i) => (
        <mesh key={i} position={pos}>
          <boxGeometry args={[0.2, totalH, 0.2]} />
          <meshStandardMaterial
            color="#112233"
            emissive="#3DB8E8"
            emissiveIntensity={0.08}
            roughness={0.5}
            metalness={0.6}
          />
        </mesh>
      ))}

      {/* Capteurs */}
      {geo.sensorPositions.map((sp) => {
        const sensor = sensorLookup[sp.sensorId]
        if (!sensor) return null
        const pos: [number, number, number] = [
          sp.x * scaledW,
          (sp.y + 1) / 2 * totalH,
          sp.z * scaledD,
        ]
        return (
          <SensorMarker
            key={sp.sensorId}
            sensor={sensor}
            position={pos}
            selected={selectedId === sensor.id}
            onClick={onSelect}
          />
        )
      })}
    </group>
  )
}

// ── Export principal ─────────────────────────────────────────────────────────

export interface StructureSceneProps {
  project: Project
  sensors: Sensor[]
  selectedId: string | null
  onSelect: (id: string) => void
}

export function StructureScene({ project, sensors, selectedId, onSelect }: StructureSceneProps) {
  if (project.structure.kind === 'bridge') {
    return (
      <BridgeStructure
        project={project}
        sensors={sensors}
        selectedId={selectedId}
        onSelect={onSelect}
      />
    )
  }
  return (
    <BuildingStructure
      project={project}
      sensors={sensors}
      selectedId={selectedId}
      onSelect={onSelect}
    />
  )
}
