export function createCrystalLattice(THREE, config, scene) {
  const maxDepth = config.maxDepth ?? 4;
  const baseSize = config.baseSize ?? 1.0;
  const scaleFalloff = config.scaleFalloff ?? 0.5;
  const connectionRadius = config.connectionRadius ?? 0.02;
  const showConnections = config.showConnections !== false;
  
  // Animation
  const rotationSpeed = config.animation?.rotationSpeed ?? 0.1;
  const formationProgress = config.animation?.formationProgress ?? 1.0;
  const shimmerSpeed = config.animation?.shimmerSpeed ?? 2.0;
  const pulseSpeed = config.animation?.pulseSpeed ?? 1.0;
  
  // Colors
  const colors = config.colors || {};
  const crystalColor = new THREE.Color(colors.crystal || '#88ccff');
  const coreColor = new THREE.Color(colors.core || '#ffffff');
  const connectionColor = new THREE.Color(colors.connection || '#4488cc');
  const emissiveColor = new THREE.Color(colors.emissive || '#002244');
  const emissiveIntensity = colors.emissiveIntensity ?? 0.6;
  
  // Material
  const metalness = config.material?.metalness ?? 0.9;
  const roughness = config.material?.roughness ?? 0.1;
  const envMapIntensity = config.material?.envMapIntensity ?? 1.0;
  const opacity = config.material?.opacity ?? 0.95;
  const fresnelPower = config.material?.fresnelPower ?? 3.0;
  const fresnelBias = config.material?.fresnelBias ?? 0.0;
  const specularIntensity = config.material?.specularIntensity ?? 1.0;
  const wireframe = config.material?.wireframe ?? false;
  const depthWrite = config.material?.depthWrite !== false;
  const depthTest = config.material?.depthTest !== false;
  const blending = config.material?.blending ?? 'normal'; // 'normal', 'additive', 'multiply', 'subtractive'
  const side = config.material?.side ?? 'double'; // 'front', 'back', 'double'
  const envMapPath = config.material?.envMap || null;
  let envMapTexture = null;
  if (envMapPath) {
    const loader = new THREE.TextureLoader();
    envMapTexture = loader.load('/' + envMapPath);
    envMapTexture.mapping = THREE.EquirectangularReflectionMapping;
  }
  
  // Light settings (can be overridden by scene lights)
  const lightSettings = config.light || {};
  const lightDir = new THREE.Vector3(
    lightSettings.direction?.x ?? 1.0,
    lightSettings.direction?.y ?? 1.0,
    lightSettings.direction?.z ?? 0.5
  ).normalize();
  const lightColor = new THREE.Color(lightSettings.color || '#ffffff');
  const lightIntensity = lightSettings.intensity ?? 1.0;
  const ambientColor = new THREE.Color(lightSettings.ambientColor || '#1a1a3a');
  const ambientIntensity = lightSettings.ambientIntensity ?? 0.4;

  const latticeGroup = new THREE.Group();
  
  // Octahedron vertices for spawning
  const octaVertices = [
    new THREE.Vector3(1, 0, 0),
    new THREE.Vector3(-1, 0, 0),
    new THREE.Vector3(0, 1, 0),
    new THREE.Vector3(0, -1, 0),
    new THREE.Vector3(0, 0, 1),
    new THREE.Vector3(0, 0, -1)
  ];
  
  const crystalMatrices = [];
  const crystalDepths = [];
  const connectionMatrices = [];
  
  function generateLattice(center, size, depth) {
    if (depth > maxDepth) return;
    
    // Add crystal at this position
    const matrix = new THREE.Matrix4();
    matrix.compose(center, new THREE.Quaternion(), new THREE.Vector3(size, size, size));
    crystalMatrices.push(matrix);
    crystalDepths.push(depth);
    
    // Recurse to vertices
    if (depth < maxDepth) {
      const newSize = size * scaleFalloff;
      const offset = size * 1.2; // Distance to child crystals
      
      for (let i = 0; i < octaVertices.length; i++) {
        const childCenter = center.clone().add(octaVertices[i].clone().multiplyScalar(offset));
        
        // Add connection to child
        if (showConnections) {
          const midPoint = center.clone().add(childCenter).multiplyScalar(0.5);
          const dir = childCenter.clone().sub(center).normalize();
          const connQuat = new THREE.Quaternion().setFromUnitVectors(new THREE.Vector3(0, 1, 0), dir);
          const connLength = center.distanceTo(childCenter);
          
          const connMatrix = new THREE.Matrix4();
          connMatrix.compose(
            midPoint,
            connQuat,
            new THREE.Vector3(connectionRadius, connLength / 2, connectionRadius)
          );
          connectionMatrices.push(connMatrix);
        }
        
        generateLattice(childCenter, newSize, depth + 1);
      }
    }
  }
  
  generateLattice(new THREE.Vector3(0, 0, 0), baseSize, 0);
  
  console.log(`[CrystalLattice] Generated ${crystalMatrices.length} crystals, ${connectionMatrices.length} connections`);
  
  // Create crystal mesh
  const crystalGeo = new THREE.OctahedronGeometry(1, 0);
  
  // Determine Three.js blending mode
  let threeBlending = THREE.NormalBlending;
  if (blending === 'additive') threeBlending = THREE.AdditiveBlending;
  else if (blending === 'multiply') threeBlending = THREE.MultiplyBlending;
  else if (blending === 'subtractive') threeBlending = THREE.SubtractiveBlending;
  
  // Determine Three.js side
  let threeSide = THREE.DoubleSide;
  if (side === 'front') threeSide = THREE.FrontSide;
  else if (side === 'back') threeSide = THREE.BackSide;
  
  const crystalMaterial = new THREE.ShaderMaterial({
    uniforms: {
      uTime: { value: 0 },
      uFormation: { value: formationProgress },
      uRotationSpeed: { value: rotationSpeed },
      uShimmerSpeed: { value: shimmerSpeed },
      uPulseSpeed: { value: pulseSpeed },
      uCrystalColor: { value: crystalColor },
      uCoreColor: { value: coreColor },
      uEmissiveColor: { value: emissiveColor },
      uEmissiveIntensity: { value: emissiveIntensity },
      uMetalness: { value: metalness },
      uRoughness: { value: roughness },
      uEnvMapIntensity: { value: envMapIntensity },
      uEnvMap: { value: envMapTexture },
      uHasEnvMap: { value: envMapTexture ? 1.0 : 0.0 },
      uMaxDepth: { value: maxDepth },
      // New material properties
      uOpacity: { value: opacity },
      uFresnelPower: { value: fresnelPower },
      uFresnelBias: { value: fresnelBias },
      uSpecularIntensity: { value: specularIntensity },
      // Light uniforms
      uLightDir: { value: lightDir },
      uLightColor: { value: lightColor },
      uLightIntensity: { value: lightIntensity },
      uAmbientColor: { value: ambientColor },
      uAmbientIntensity: { value: ambientIntensity },
    },
    vertexShader: `
      attribute float instanceDepth;
      
      uniform float uTime;
      uniform float uFormation;
      uniform float uRotationSpeed;
      uniform float uShimmerSpeed;
      uniform float uPulseSpeed;
      uniform float uMaxDepth;
      
      varying vec3 vNormal;
      varying vec3 vWorldPos;
      varying vec3 vViewDir;
      varying vec3 vReflect;
      varying float vDepth;
      varying float vFormationFactor;
      varying float vShimmer;
      
      mat3 rotateY(float angle) {
        float c = cos(angle);
        float s = sin(angle);
        return mat3(c, 0, s, 0, 1, 0, -s, 0, c);
      }
      
      void main() {
        vDepth = instanceDepth;
        
        float depthNorm = instanceDepth / uMaxDepth;
        vFormationFactor = smoothstep(depthNorm - 0.1, depthNorm + 0.1, uFormation);
        
        vec3 instancePos = vec3(instanceMatrix[3][0], instanceMatrix[3][1], instanceMatrix[3][2]);
        float instanceScale = length(vec3(instanceMatrix[0][0], instanceMatrix[1][0], instanceMatrix[2][0]));
        
        vec3 formDir = normalize(instancePos + vec3(0.001));
        float formDist = length(instancePos) * (1.0 - vFormationFactor);
        vec3 animatedPos = instancePos - formDir * formDist;
        
        float rotAngle = uTime * uRotationSpeed + instanceDepth * 0.5;
        mat3 rot = rotateY(rotAngle);
        animatedPos = rot * animatedPos;
        
        float pulse = 1.0 + sin(uTime * uPulseSpeed + instanceDepth) * 0.1;
        
        vShimmer = sin(uTime * uShimmerSpeed + instancePos.x * 10.0 + instancePos.y * 10.0 + instancePos.z * 10.0) * 0.5 + 0.5;
        
        vec3 scaledPos = rot * position * instanceScale * pulse * vFormationFactor;
        vec3 worldPos = animatedPos + scaledPos;
        
        vWorldPos = worldPos;
        vViewDir = normalize(cameraPosition - worldPos);
        vNormal = normalize(rot * normal);
        vReflect = reflect(-vViewDir, vNormal);
        
        gl_Position = projectionMatrix * viewMatrix * vec4(worldPos, 1.0);
      }
    `,
    fragmentShader: `
      uniform vec3 uCrystalColor;
      uniform vec3 uCoreColor;
      uniform vec3 uEmissiveColor;
      uniform float uEmissiveIntensity;
      uniform float uMetalness;
      uniform float uRoughness;
      uniform float uEnvMapIntensity;
      uniform sampler2D uEnvMap;
      uniform float uHasEnvMap;
      uniform float uShimmerSpeed;
      uniform float uMaxDepth;
      uniform float uTime;
      // New material properties
      uniform float uOpacity;
      uniform float uFresnelPower;
      uniform float uFresnelBias;
      uniform float uSpecularIntensity;
      // Light uniforms
      uniform vec3 uLightDir;
      uniform vec3 uLightColor;
      uniform float uLightIntensity;
      uniform vec3 uAmbientColor;
      uniform float uAmbientIntensity;
      
      varying vec3 vNormal;
      varying vec3 vWorldPos;
      varying vec3 vViewDir;
      varying vec3 vReflect;
      varying float vDepth;
      varying float vFormationFactor;
      varying float vShimmer;
      
      #define PI 3.14159265359
      
      vec3 sampleEnvMap(vec3 dir) {
        float phi = atan(dir.z, dir.x);
        float theta = acos(clamp(dir.y, -1.0, 1.0));
        vec2 uv = vec2((phi + PI) / (2.0 * PI), theta / PI);
        return texture2D(uEnvMap, uv).rgb;
      }
      
      void main() {
        if (vFormationFactor < 0.01) discard;
        
        float depthNorm = vDepth / uMaxDepth;
        vec3 baseColor = mix(uCoreColor, uCrystalColor, depthNorm);
        baseColor += (uCoreColor - baseColor) * vShimmer * 0.3;
        
        vec3 normal = normalize(vNormal);
        vec3 viewDir = normalize(vViewDir);
        vec3 lightDir = normalize(uLightDir);
        vec3 halfDir = normalize(lightDir + viewDir);
        
        // Fresnel with configurable power and bias
        float fresnel = uFresnelBias + (1.0 - uFresnelBias) * pow(1.0 - max(dot(normal, viewDir), 0.0), uFresnelPower);
        
        float NdotL = max(dot(normal, lightDir), 0.0);
        
        float specPower = mix(512.0, 8.0, uRoughness);
        float specular = pow(max(dot(normal, halfDir), 0.0), specPower) * uSpecularIntensity;
        
        vec3 diffuseColor = baseColor * (1.0 - uMetalness);
        vec3 specularColor = mix(vec3(0.04), baseColor, uMetalness);
        
        // Ambient light contribution
        vec3 color = diffuseColor * uAmbientColor * uAmbientIntensity;
        // Directional light contribution
        color += diffuseColor * uLightColor * uLightIntensity * NdotL;
        // Specular highlight
        color += specularColor * uLightColor * specular * uLightIntensity * (1.0 - uRoughness * 0.3);
        
        // Environment map reflection
        if (uHasEnvMap > 0.5) {
          vec3 envColor = sampleEnvMap(normalize(vReflect));
          color += specularColor * envColor * fresnel * uEnvMapIntensity;
        } else {
          color += specularColor * fresnel * uEnvMapIntensity * 0.3;
        }
        
        // Emissive contribution
        color += uEmissiveColor * uEmissiveIntensity * (0.5 + vShimmer * 0.5);
        
        gl_FragColor = vec4(color, uOpacity * vFormationFactor);
      }
    `,
    transparent: true,
    side: threeSide,
    wireframe: wireframe,
    depthWrite: depthWrite,
    depthTest: depthTest,
    blending: threeBlending,
  });
  
  const crystalMesh = new THREE.InstancedMesh(crystalGeo, crystalMaterial, crystalMatrices.length);
  const depthArray = new Float32Array(crystalMatrices.length);
  for (let i = 0; i < crystalMatrices.length; i++) {
    crystalMesh.setMatrixAt(i, crystalMatrices[i]);
    depthArray[i] = crystalDepths[i];
  }
  crystalMesh.instanceMatrix.needsUpdate = true;
  crystalGeo.setAttribute('instanceDepth', new THREE.InstancedBufferAttribute(depthArray, 1));
  latticeGroup.add(crystalMesh);
  
  // Create connections if enabled
  if (showConnections && connectionMatrices.length > 0) {
    const connGeo = new THREE.CylinderGeometry(1, 1, 2, 6);
    const connMaterial = new THREE.MeshBasicMaterial({
      color: connectionColor,
      transparent: true,
      opacity: 0.5
    });
    
    const connMesh = new THREE.InstancedMesh(connGeo, connMaterial, connectionMatrices.length);
    for (let i = 0; i < connectionMatrices.length; i++) {
      connMesh.setMatrixAt(i, connectionMatrices[i]);
    }
    connMesh.instanceMatrix.needsUpdate = true;
    latticeGroup.add(connMesh);
    latticeGroup.userData.connMesh = connMesh;
  }
  
  latticeGroup.userData.crystalMesh = crystalMesh;
  latticeGroup.userData.config = config;
  
  if (config.position) {
    latticeGroup.position.set(config.position.x ?? 0, config.position.y ?? 0, config.position.z ?? 0);
  }
  if (config.rotation) {
    latticeGroup.rotation.set(
      (config.rotation.x ?? 0) * Math.PI / 180,
      (config.rotation.y ?? 0) * Math.PI / 180,
      (config.rotation.z ?? 0) * Math.PI / 180
    );
  }
  
  scene.add(latticeGroup);
  return latticeGroup;
}
