import * as THREE from 'three';
import { STLLoader } from 'three/examples/jsm/loaders/STLLoader.js';
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter.js';

type SupportedExt = 'glb' | 'obj' | 'stl' | 'ifc';

export function getSupportedExtension(fileName: string): SupportedExt | null {
  const ext = fileName.split('.').pop()?.toLowerCase();
  if (ext === 'glb' || ext === 'obj' || ext === 'stl' || ext === 'ifc') return ext;
  return null;
}

export const ACCEPTED_EXTENSIONS = '.glb,.obj,.stl,.ifc';

/**
 * Convert an OBJ or STL file (ArrayBuffer) into a GLB Blob.
 * GLB files are returned as-is from their original blob.
 */
export async function convertToGLB(
  buffer: ArrayBuffer,
  ext: 'obj' | 'stl',
  fileName: string
): Promise<{ blob: Blob; fileName: string; fileSize: number }> {
  const scene = new THREE.Scene();

  const material = new THREE.MeshStandardMaterial({
    color: 0x8899aa,
    metalness: 0.85,
    roughness: 0.35,
  });

  if (ext === 'stl') {
    const loader = new STLLoader();
    const geometry = loader.parse(buffer);
    geometry.computeVertexNormals();
    const mesh = new THREE.Mesh(geometry, material);
    mesh.name = fileName.replace(/\.stl$/i, '');
    scene.add(mesh);
  } else {
    const loader = new OBJLoader();
    const text = new TextDecoder().decode(buffer);
    const obj = loader.parse(text);
    obj.traverse((child) => {
      if (child instanceof THREE.Mesh) {
        child.material = material;
      }
    });
    obj.name = fileName.replace(/\.obj$/i, '');
    scene.add(obj);
  }

  const exporter = new GLTFExporter();
  const glb = await new Promise<ArrayBuffer>((resolve, reject) => {
    exporter.parse(
      scene,
      (result) => resolve(result as ArrayBuffer),
      (error) => reject(error),
      { binary: true }
    );
  });

  const glbFileName = fileName.replace(/\.(obj|stl)$/i, '.glb');
  const blob = new Blob([glb], { type: 'model/gltf-binary' });

  return { blob, fileName: glbFileName, fileSize: blob.size };
}
