import { AbstractMesh } from '@babylonjs/core'

export interface ParsedMeshData {
  meshes: unknown[]
  boundingBox: {
    min: { x: number; y: number; z: number }
    max: { x: number; y: number; z: number }
  }
  metadata: {
    modelPath: string
    parsedAt: string
    totalVertices: number
    totalIndices: number
  }
}

export const getCacheFileName = (modelPath: string) => {
  const fileName = modelPath.split('/').pop()?.replace('.gltf', '') || 'model'
  return `${fileName}_parsed.json`
}

export const loadCachedData = async (cacheFileName: string): Promise<ParsedMeshData | null> => {
  try {
    const response = await fetch(`/data/${cacheFileName}`)
    if (response.ok) {
      const cachedData = await response.json()
      console.log('📦 Loaded cached mesh data:', cachedData.metadata)
      return cachedData
    }
  } catch (error) {
    console.log('❌ No cached data found, will parse scene')
  }
  return null
}

export const extractAllMeshData = (mesh: AbstractMesh) => {
  const meshData: Record<string, unknown> = {}
  
  const safeStringify = (obj: unknown): unknown => {
    try {
      JSON.stringify(obj)
      return obj
    } catch {
      return '[Circular Reference]'
    }
  }
  
  const extractValue = (value: unknown): unknown => {
    if (value === null || value === undefined) {
      return value
    }
    
    if (typeof value === 'function') {
      return '[Function]'
    }
    
    if (typeof value === 'object' && value !== null) {
      const obj = value as Record<string, unknown>
      
      if (obj.constructor.name === 'Vector3') {
        return { x: obj.x, y: obj.y, z: obj.z }
      } else if (obj.constructor.name === 'Quaternion') {
        return { x: obj.x, y: obj.y, z: obj.z, w: obj.w }
      } else if (obj.constructor.name === 'Color3') {
        return { r: obj.r, g: obj.g, b: obj.b }
      } else if (obj.constructor.name === 'Color4') {
        return { r: obj.r, g: obj.g, b: obj.b, a: obj.a }
      } else if (Array.isArray(value)) {
        return value.map(item => extractValue(item))
      } else {
        return safeStringify(value)
      }
    }
    
    return value
  }
  
  for (const key in mesh) {
    try {
      const value = (mesh as unknown as Record<string, unknown>)[key]
      meshData[key] = extractValue(value)
    } catch (error) {
      meshData[key] = '[Error accessing property]'
    }
  }
  
  meshData.geometry = {
    vertices: mesh.getVerticesData('position') ? Array.from(mesh.getVerticesData('position')!) : [],
    indices: mesh.getIndices() ? Array.from(mesh.getIndices()!) : [],
    normals: mesh.getVerticesData('normal') ? Array.from(mesh.getVerticesData('normal')!) : [],
    uvs: mesh.getVerticesData('uv') ? Array.from(mesh.getVerticesData('uv')!) : [],
    colors: mesh.getVerticesData('color') ? Array.from(mesh.getVerticesData('color')!) : [],
    tangents: mesh.getVerticesData('tangent') ? Array.from(mesh.getVerticesData('tangent')!) : [],
    matricesWeights: mesh.getVerticesData('matricesWeights') ? Array.from(mesh.getVerticesData('matricesWeights')!) : [],
    matricesIndices: mesh.getVerticesData('matricesIndices') ? Array.from(mesh.getVerticesData('matricesIndices')!) : [],
    totalVertices: mesh.getTotalVertices(),
    totalIndices: mesh.getIndices() ? mesh.getIndices()!.length : 0
  }
  
  return meshData
}

export const parseAndCacheScene = async (meshes: AbstractMesh[], cacheFileName: string, modelPath: string): Promise<ParsedMeshData> => {
  const parsedMeshes = meshes.map(mesh => extractAllMeshData(mesh))

  const boundingBox = meshes[0].getHierarchyBoundingVectors()
  const totalVertices = parsedMeshes.reduce((sum, mesh) => {
    const meshData = mesh as Record<string, unknown>
    const geometry = meshData.geometry as Record<string, unknown>
    const vertices = geometry.vertices as number[]
    return sum + vertices.length / 3
  }, 0)
  const totalIndices = parsedMeshes.reduce((sum, mesh) => {
    const meshData = mesh as Record<string, unknown>
    const geometry = meshData.geometry as Record<string, unknown>
    const indices = geometry.indices as number[]
    return sum + indices.length
  }, 0)

  const parsedData: ParsedMeshData = {
    meshes: parsedMeshes,
    boundingBox: {
      min: boundingBox.min,
      max: boundingBox.max
    },
    metadata: {
      modelPath,
      parsedAt: new Date().toISOString(),
      totalVertices: Math.floor(totalVertices),
      totalIndices
    }
  }

  console.log('💾 Caching parsed mesh data:', parsedData.metadata)
  
  try {
    console.log('💾 Attempting to cache mesh data...')
    console.log('💾 Cache file name:', cacheFileName)
    console.log('💾 Data size:', JSON.stringify(parsedData).length, 'bytes')
    
    const response = await fetch('/api/cache-mesh-data', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        fileName: cacheFileName,
        data: parsedData
      })
    })
    
    console.log('💾 Response status:', response.status)
    console.log('💾 Response ok:', response.ok)
    
    if (response.ok) {
      const result = await response.json()
      console.log('✅ Mesh data cached successfully:', result)
    } else {
      const errorText = await response.text()
      console.warn('⚠️ Failed to cache mesh data:', response.status, errorText)
    }
  } catch (error) {
    console.warn('⚠️ Could not cache mesh data:', error)
    console.error('💾 Full error details:', error)
  }

  return parsedData
} 