import { DEFAULT_ELEMENT_COLOR, DEFAULT_GEOMETRY_PARAMS } from './constants';
import {
  applyTransform,
  cloneUserData,
  createDefaultElementName,
  createDefaultGroupName,
  createUniqueName,
  getElementBaseLabel,
  updateDisplayName,
} from './scene-helpers';

function normalizeNumber(value, fallback) {
  const nextValue = Number(value);
  return Number.isFinite(nextValue) ? nextValue : fallback;
}

function normalizeCapsuleLengthValue(geometryParams = {}, fallback) {
  if (geometryParams.length !== undefined) {
    return normalizeNumber(geometryParams.length, fallback);
  }
  if (geometryParams.height !== undefined) {
    return normalizeNumber(geometryParams.height, fallback);
  }
  return fallback;
}

export function normalizeGeometryParams(type, geometryParams = {}) {
  const defaults = DEFAULT_GEOMETRY_PARAMS[type];
  if (!defaults) {
    throw new Error(`不支持的元素类型：${type}`);
  }
  const normalized = {};
  Object.keys(defaults).forEach(key => {
    if (type === 'capsule' && key === 'length') {
      normalized[key] = normalizeCapsuleLengthValue(geometryParams, defaults[key]);
      return;
    }
    normalized[key] = normalizeNumber(geometryParams[key], defaults[key]);
  });
  return normalized;
}

export function createGeometry(THREE, type, geometryParams = {}) {
  const params = normalizeGeometryParams(type, geometryParams);
  switch (type) {
    case 'box':
      return new THREE.BoxGeometry(params.width, params.height, params.depth);
    case 'tetrahedron':
      return new THREE.TetrahedronGeometry(params.radius);
    case 'octahedron':
      return new THREE.OctahedronGeometry(params.radius);
    case 'cylinder':
      return new THREE.CylinderGeometry(params.radiusTop, params.radiusBottom, params.height, 32);
    case 'ring':
      return new THREE.TorusGeometry(
        params.radius,
        params.tube,
        16,
        64,
        (params.arc * Math.PI) / 180
      );
    case 'sphere':
      return new THREE.SphereGeometry(
        params.radius,
        32,
        16,
        (params.phiStart * Math.PI) / 180,
        (params.phiLength * Math.PI) / 180,
        (params.thetaStart * Math.PI) / 180,
        (params.thetaLength * Math.PI) / 180
      );
    case 'capsule':
      return new THREE.CapsuleGeometry(params.radius, params.length, 8, 16);
    default:
      throw new Error(`不支持的元素类型：${type}`);
  }
}

export function createDefaultMaterial(THREE, materialOptions = {}) {
  const color = materialOptions.color || DEFAULT_ELEMENT_COLOR;
  const opacity =
    materialOptions.opacity === undefined ? 1 : normalizeNumber(materialOptions.opacity, 1);
  return new THREE.MeshStandardMaterial({
    color,
    transparent: opacity < 1,
    opacity,
  });
}

export function createPrimitive(THREE, type, options = {}) {
  const geometryParams = normalizeGeometryParams(type, options.geometryParams);
  const geometry = createGeometry(THREE, type, geometryParams);
  const material = createDefaultMaterial(THREE, options.material);
  const mesh = new THREE.Mesh(geometry, material);
  mesh.name = options.name || getElementBaseLabel(type);
  mesh.userData = {
    nodeType: 'custom-element',
    elementType: type,
    // displayName: mesh.name,
    editable: true,
    deletable: true,
    cloneable: true,
    source: options.source || 'manual-create',
    geometryParams,
  };
  applyTransform(mesh, options.transform);
  updateDisplayName(mesh);
  return mesh;
}

export function createGroup(THREE, options = {}) {
  const group = new THREE.Group();
  group.name = options.name || '组';
  group.userData = {
    nodeType: 'custom-group',
    // displayName: group.name,
    editable: true,
    deletable: true,
    cloneable: true,
    source: options.source || 'manual-create',
  };
  applyTransform(group, options.transform);
  updateDisplayName(group);
  return group;
}

export function createElementByType(THREE, type, parent, options = {}) {
  const name = options.name || createDefaultElementName(parent, type);
  return createPrimitive(THREE, type, {
    ...options,
    name,
  });
}

export function createGroupElement(THREE, parent, options = {}) {
  const name = options.name || createDefaultGroupName(parent);
  return createGroup(THREE, {
    ...options,
    name,
  });
}

export function cloneCustomObject(THREE, object, targetParent) {
  const clonedObject = object.clone(true);
  clonedObject.traverse(child => {
    if (child.userData) {
      child.userData = cloneUserData(child.userData);
    }
    if (child.isMesh) {
      child.geometry = child.geometry.clone();
      if (Array.isArray(child.material)) {
        child.material = child.material.map(material => material.clone());
      } else if (child.material) {
        child.material = child.material.clone();
      }
    }
  });

  clonedObject.userData.source = 'clone';
  clonedObject.name = createUniqueName(targetParent, object.name);
  updateDisplayName(clonedObject);
  return clonedObject;
}
