function setVector3(target, value, defaults) {
  if (Array.isArray(value)) {
    target.set(value[0] || defaults[0], value[1] || defaults[1], value[2] || defaults[2]);
    return;
  }
  target.set(value?.x || defaults[0], value?.y || defaults[1], value?.z || defaults[2]);
}

export function createSceneFoundation(THREE, data, aspectRatio) {
  const scene = new THREE.Scene();

  if (data.background) {
    if (typeof data.background === 'string') {
      scene.background = new THREE.Color(data.background);
    } else if (data.background.color) {
      scene.background = new THREE.Color(data.background.color);
    }
  } else {
    scene.background = new THREE.Color(0x000000);
  }

  if (data.fog) {
    scene.fog = new THREE.Fog(
      new THREE.Color(data.fog.color || 0x000000),
      data.fog.near || 10,
      data.fog.far || 100
    );
  }

  const camera = createCamera(THREE, data.camera || {}, aspectRatio);
  const animatedLights = createLights(THREE, scene, data.lights || []);
  return { scene, camera, animatedLights };
}

export function createCamera(THREE, camData, aspectRatio) {
  const camera = camData.type === 'orthographic'
    ? new THREE.OrthographicCamera(-10, 10, 10, -10, 0.1, 1000)
    : new THREE.PerspectiveCamera(
      camData.fov || 60,
      aspectRatio,
      camData.near || 0.1,
      camData.far || 1000
    );

  setVector3(camera.position, camData.position, [0, 5, 10]);
  if (camData.rotation) {
    const rotation = Array.isArray(camData.rotation)
      ? camData.rotation
      : [camData.rotation.x, camData.rotation.y, camData.rotation.z];
    camera.rotation.set(
      THREE.MathUtils.degToRad(rotation[0] || 0),
      THREE.MathUtils.degToRad(rotation[1] || 0),
      THREE.MathUtils.degToRad(rotation[2] || 0)
    );
  } else if (camData.lookAt) {
    const lookAt = Array.isArray(camData.lookAt)
      ? camData.lookAt
      : [camData.lookAt.x, camData.lookAt.y, camData.lookAt.z];
    camera.lookAt(lookAt[0] || 0, lookAt[1] || 0, lookAt[2] || 0);
  }
  return camera;
}

export function createLights(THREE, scene, lights) {
  const animatedLights = [];
  lights.forEach((lightData, lightIndex) => {
    const color = new THREE.Color(lightData.color || 0xffffff);
    const intensity = lightData.intensity ?? 1;
    let light;

    switch (lightData.type) {
      case 'ambient':
        light = new THREE.AmbientLight(color, intensity);
        break;
      case 'directional': {
        light = new THREE.DirectionalLight(color, intensity);
        setVector3(light.position, lightData.position, [5, 10, 5]);
        if (lightData.castShadow) {
          light.castShadow = true;
          light.shadow.mapSize.width = 2048;
          light.shadow.mapSize.height = 2048;
          light.shadow.camera.near = 0.5;
          light.shadow.camera.far = 500;
          const shadowSize = lightData.shadowCameraSize || 20;
          light.shadow.camera.left = -shadowSize;
          light.shadow.camera.right = shadowSize;
          light.shadow.camera.top = shadowSize;
          light.shadow.camera.bottom = -shadowSize;
          light.shadow.bias = lightData.shadowBias ?? -0.001;
          light.shadow.radius = lightData.shadowRadius ?? 1;
          light.shadow.camera.updateProjectionMatrix();
        }
        break;
      }
      case 'point': {
        light = new THREE.PointLight(color, intensity, lightData.distance || 0, lightData.decay ?? 2);
        setVector3(light.position, lightData.position, [0, 5, 0]);
        if (lightData.castShadow) {
          light.castShadow = true;
          light.shadow.mapSize.width = 1024;
          light.shadow.mapSize.height = 1024;
          light.shadow.camera.near = 0.5;
          light.shadow.camera.far = lightData.distance || 50;
          light.shadow.bias = lightData.shadowBias ?? -0.001;
          light.shadow.radius = lightData.shadowRadius ?? 1;
        }
        if (lightData.animation) {
          light.userData.animation = lightData.animation;
          light.userData.name = lightData.name;
          light.userData.originalIntensity = intensity;
          const marker = new THREE.Mesh(
            new THREE.SphereGeometry(0.5, 16, 16),
            new THREE.MeshBasicMaterial({ color, transparent: true, opacity: 1.0 })
          );
          light.add(marker);
          const glow = new THREE.Mesh(
            new THREE.SphereGeometry(1.2, 16, 16),
            new THREE.MeshBasicMaterial({ color, transparent: true, opacity: 0.3, side: THREE.BackSide })
          );
          light.add(glow);
        }
        break;
      }
      case 'spot':
        light = new THREE.SpotLight(color, intensity);
        setVector3(light.position, lightData.position, [0, 10, 0]);
        light.angle = lightData.angle || Math.PI / 6;
        break;
      case 'hemisphere':
        light = new THREE.HemisphereLight(
          new THREE.Color(lightData.skyColor || 0x87CEEB),
          new THREE.Color(lightData.groundColor || 0x3a5a2a),
          intensity
        );
        break;
      case 'rectarea':
        light = new THREE.RectAreaLight(color, intensity, lightData.width || 10, lightData.height || 10);
        setVector3(light.position, lightData.position, [0, 5, 0]);
        light.lookAt(
          lightData.lookAt?.x || 0,
          lightData.lookAt?.y || 0,
          lightData.lookAt?.z || 0
        );
        break;
      default:
        console.warn(`Unknown light type "${lightData.type}", creating fallback ambient light`);
        light = new THREE.AmbientLight(color, intensity);
        break;
    }

    light.userData = light.userData || {};
    light.userData.lightIndex = lightIndex;
    if (lightData.visible === false) light.visible = false;
    scene.add(light);
    if (light.userData.animation) animatedLights.push(light);
  });
  return animatedLights;
}
