import { MeshBuilder, StandardMaterial, Color3, Mesh } from '@babylonjs/core';
import { createAnatomicalSectionMesh, createFootSectionMesh, ringPoint } from './AnatomicalMesh';

function mat(scene, name, hex, spec = 0.2, doubleside = false) {
  const m = new StandardMaterial(name, scene);
  m.diffuseColor = Color3.FromHexString(hex);
  m.specularColor = new Color3(spec, spec, spec);
  m.specularPower = 56;
  if (doubleside) { m.sideOrientation = Mesh.DOUBLESIDE; m.backFaceCulling = false; }
  return m;
}

function tag(mesh, id, label) { mesh.metadata = { type: 'prosthesisPart', partId: id, label }; }

const SOCKET_RINGS = [
  { y: 2.92, rx: 0.34, rz: 0.30 },
  { y: 3.20, rx: 0.42, rz: 0.36 },
  { y: 3.55, rx: 0.48, rz: 0.39 },
  { y: 3.95, rx: 0.52, rz: 0.42 },
  { y: 4.35, rx: 0.56, rz: 0.45 },
  { y: 4.75, rx: 0.60, rz: 0.47 },
  { y: 5.15, rx: 0.62, rz: 0.48 },
  { y: 5.50, rx: 0.63, rz: 0.49, trim: { lateral: 0.22, medial: 0.09, anterior: -0.16, posterior: 0.07 } },
];

const LINER_RINGS = [
  { y: 3.10, rx: 0.27, rz: 0.26 },
  { y: 3.80, rx: 0.40, rz: 0.34 },
  { y: 4.50, rx: 0.48, rz: 0.40 },
  { y: 5.10, rx: 0.54, rz: 0.44 },
  { y: 5.55, rx: 0.50, rz: 0.40, flatFront: 0.12, fullBack: 0.08, sideBias: 0.03 },
  { y: 5.85, rx: 0.42, rz: 0.34 },
];

const FOOT_RINGS = [
  { z: -0.75, rx: 0.24, ry: 0.26, cy: 0.32, flatSole: 0.35 },
  { z: -0.50, rx: 0.30, ry: 0.28, cy: 0.34, flatSole: 0.30 },
  { z: -0.20, rx: 0.40, ry: 0.24, cy: 0.36, flatSole: 0.25 },
  { z: 0.15, rx: 0.48, ry: 0.20, cy: 0.30, flatSole: 0.40 },
  { z: 0.55, rx: 0.54, ry: 0.18, cy: 0.28, flatSole: 0.45 },
  { z: 1.00, rx: 0.55, ry: 0.16, cy: 0.26, flatSole: 0.50 },
  { z: 1.45, rx: 0.52, ry: 0.14, cy: 0.24, flatSole: 0.55 },
  { z: 1.80, rx: 0.36, ry: 0.12, cy: 0.24, flatSole: 0.60 },
  { z: 2.05, rx: 0.18, ry: 0.09, cy: 0.26, flatSole: 0.70 },
];

function buildSocket(scene, m, rimMat, rings) {
  const R = rings || SOCKET_RINGS;
  try {
    const shell = createAnatomicalSectionMesh(scene, 'part-socket', R, { closeBottom: true });
    shell.material = m;
    const N = 30;
    const path = [];
    for (let i = 0; i <= N; i++) path.push(ringPoint(R[R.length - 1], i % N, N));
    const rim = MeshBuilder.CreateTube('part-socket-rim', { path, radius: 0.03, tessellation: 8, cap: Mesh.CAP_ALL }, scene);
    rim.material = rimMat;
    return [shell, rim];
  } catch (_) {
    const cyl = MeshBuilder.CreateCylinder('part-socket', { diameterTop: 0.7, diameterBottom: 0.95, height: 2.6, tessellation: 28 }, scene);
    cyl.position.y = 4.2; cyl.material = m;
    return [cyl];
  }
}

function buildLiner(scene, m, rings) {
  let R = LINER_RINGS;
  if (rings && rings.length) {
    R = rings.map((r) => ({ ...r, rx: r.rx * 0.85, rz: r.rz * 0.85, cx: (r.cx || 0) * 0.85, cz: (r.cz || 0) * 0.85, trim: undefined }));
    // crest slightly above the socket rim
    R = [...R, { ...R[R.length - 1], y: R[R.length - 1].y + 0.18, rx: R[R.length - 1].rx * 0.82, rz: R[R.length - 1].rz * 0.82 }];
  }
  try {
    const liner = createAnatomicalSectionMesh(scene, 'part-liner', R, { closeBottom: true, closeTop: true });
    liner.material = m;
    return [liner];
  } catch (_) {
    const cyl = MeshBuilder.CreateCylinder('part-liner', { diameterTop: 0.5, diameterBottom: 0.7, height: 2.6, tessellation: 24 }, scene);
    cyl.position.y = 4.5; cyl.material = m;
    return [cyl];
  }
}

function buildFoot(scene, m) {
  try {
    const foot = createFootSectionMesh(scene, 'part-foot', FOOT_RINGS, { closeBottom: true, closeTop: true });
    foot.material = m;
    return [foot];
  } catch (_) {
    const fb = MeshBuilder.CreateBox('part-foot', { width: 1.0, height: 0.45, depth: 2.8 }, scene);
    fb.position.set(0, 0.28, 0.65); fb.material = m;
    return [fb];
  }
}

function buildAnkle(scene, m) {
  const cyl = MeshBuilder.CreateCylinder('part-ankle', { diameterTop: 0.28, diameterBottom: 0.34, height: 0.30, tessellation: 24 }, scene);
  cyl.position.y = 0.72; cyl.material = m;
  const ring = MeshBuilder.CreateTorus('part-ankle-ring', { diameter: 0.32, thickness: 0.03, tessellation: 24 }, scene);
  ring.position.y = 0.84; ring.material = m;
  return [cyl, ring];
}

function buildPylon(scene, m) {
  const pyl = MeshBuilder.CreateCylinder('part-pylon', { diameter: 0.22, height: 1.43, tessellation: 20 }, scene);
  pyl.position.y = 1.59; pyl.material = m;
  return [pyl];
}

function buildClamp(scene, m) {
  const collar = MeshBuilder.CreateCylinder('part-clamp', { diameter: 0.30, height: 0.22, tessellation: 24 }, scene);
  collar.position.y = 2.41; collar.material = m;
  const bolt = MeshBuilder.CreateBox('part-clamp-bolt', { width: 0.09, height: 0.09, depth: 0.13 }, scene);
  bolt.position.set(0.16, 2.41, 0); bolt.material = m;
  return [collar, bolt];
}

function buildDistalAdapter(scene, m) {
  const lower = MeshBuilder.CreateCylinder('part-adapter-l', { diameter: 0.40, height: 0.20, tessellation: 24 }, scene);
  lower.position.y = 2.62; lower.material = m;
  const upper = MeshBuilder.CreateCylinder('part-adapter-u', { diameterTop: 0.34, diameterBottom: 0.40, height: 0.20, tessellation: 24 }, scene);
  upper.position.y = 2.82; upper.material = m;
  return [lower, upper];
}

export function buildProsthesis(scene, geometry) {
  const meshes = [];
  const labels = [];
  const add = (ms, id, label, labelPos) => {
    ms.forEach((mm) => tag(mm, id, label));
    meshes.push(...ms);
    labels.push({ id: `part-${id}`, position: labelPos, text: label, kind: 'part', tone: 'slate' });
  };

  add(buildFoot(scene, mat(scene, 'mat-foot', '#1B212D', 0.28, true)), 'foot', 'Prosthetic Foot', [0.5, 0.45, 1.05]);
  add(buildAnkle(scene, mat(scene, 'mat-ankle', '#3B465A', 0.5)), 'ankle', 'Ankle Adapter', [0.22, 0.72, 0]);
  add(buildPylon(scene, mat(scene, 'mat-pylon', '#2A3242', 0.65)), 'pylon', 'Pylon', [0.18, 1.59, 0]);
  add(buildClamp(scene, mat(scene, 'mat-clamp', '#4A5468', 0.55)), 'clamp', 'Tube Clamp', [0.22, 2.41, 0]);
  add(buildDistalAdapter(scene, mat(scene, 'mat-adapter', '#3B465A', 0.5)), 'adapter', 'Distal Socket Adapter', [0.26, 2.72, 0]);
  const socketRings = geometry && geometry.socketStations ? geometry.socketStations : null;
  add(buildSocket(scene, mat(scene, 'mat-socket', '#1A1626', 0.38, true), mat(scene, 'mat-socket-rim', '#2C2640', 0.4), socketRings), 'socket', 'Socket', [0.68, 4.4, 0]);
  add(buildLiner(scene, mat(scene, 'mat-liner', '#3A4453', 0.18, true), socketRings), 'liner', 'Residual Limb / Liner', [0, 5.7, 0]);

  return { meshes, labels, dispose: () => meshes.forEach((m) => { try { m.dispose(); } catch (_) {} }) };
}