"""
Mesh Converter Utility
Converts Nastran BDF/OP2 files to GLTF for web visualization
"""

import json
import numpy as np
from pathlib import Path
from typing import Optional, Dict, Any
import trimesh
from pyNastran.bdf.bdf import BDF
from pyNastran.op2.op2 import OP2

def convert_study_mesh(study_dir: Path) -> Optional[Path]:
    """
    Convert the mesh and results of a study to GLTF format.
    
    Args:
        study_dir: Path to the study directory
        
    Returns:
        Path to the generated GLTF file, or None if conversion failed
    """
    try:
        # Locate files
        setup_dir = study_dir / "1_setup" / "model"
        results_dir = study_dir / "2_results"
        vis_dir = study_dir / "3_visualization"
        vis_dir.mkdir(parents=True, exist_ok=True)
        
        # Find BDF/DAT file
        bdf_files = list(setup_dir.glob("*.dat")) + list(setup_dir.glob("*.bdf"))
        if not bdf_files:
            # Fallback: Generate placeholder if no BDF found
            return _generate_placeholder_mesh(vis_dir)
            
        bdf_path = bdf_files[0]
        
        # Find OP2 file (optional)
        op2_files = list(results_dir.glob("*.op2"))
        op2_path = op2_files[0] if op2_files else None
        
        # Load BDF
        model = BDF()
        model.read_bdf(bdf_path, xref=False)
        
        # Extract nodes and elements
        # This is a simplified extraction for shell/solid elements
        # A full implementation would handle all element types
        nodes = []
        node_ids = []
        for nid, node in model.nodes.items():
            nodes.append(node.get_position())
            node_ids.append(nid)
            
        nodes = np.array(nodes)
        node_map = {nid: i for i, nid in enumerate(node_ids)}
        
        faces = []
        
        # Process CQUAD4/CTRIA3 elements
        for eid, element in model.elements.items():
            if element.type == 'CQUAD4':
                n = [node_map[nid] for nid in element.nodes]
                faces.append([n[0], n[1], n[2]])
                faces.append([n[0], n[2], n[3]])
            elif element.type == 'CTRIA3':
                n = [node_map[nid] for nid in element.nodes]
                faces.append([n[0], n[1], n[2]])
                
        if not faces:
             # Fallback if no compatible elements found
            return _generate_placeholder_mesh(vis_dir)
            
        # Create mesh
        mesh = trimesh.Trimesh(vertices=nodes, faces=faces)
        
        # Map results if OP2 exists
        if op2_path:
            op2 = OP2()
            op2.read_op2(op2_path)
            
            # Example: Map displacement magnitude to vertex colors
            if 1 in op2.displacements:
                disp = op2.displacements[1]
                # Get last timestep
                t3 = disp.data[-1, :, :3] # Translation x,y,z
                mag = np.linalg.norm(t3, axis=1)
                
                # Normalize to 0-1 for coloring
                if mag.max() > mag.min():
                    norm_mag = (mag - mag.min()) / (mag.max() - mag.min())
                else:
                    norm_mag = np.zeros_like(mag)
                    
                # Apply colormap (simple blue-to-red)
                colors = np.zeros((len(nodes), 4))
                colors[:, 0] = norm_mag # R
                colors[:, 2] = 1 - norm_mag # B
                colors[:, 3] = 1.0 # Alpha
                
                mesh.visual.vertex_colors = colors
                
        # Export to GLTF
        output_path = vis_dir / "model.gltf"
        mesh.export(output_path)
        
        # Save metadata
        metadata = {
            "node_count": len(nodes),
            "element_count": len(faces),
            "has_results": op2_path is not None
        }
        with open(vis_dir / "model.json", 'w') as f:
            json.dump(metadata, f, indent=2)
            
        return output_path
        
    except Exception as e:
        print(f"Mesh conversion error: {e}")
        # Fallback on error
        return _generate_placeholder_mesh(vis_dir)

def _generate_placeholder_mesh(output_dir: Path) -> Path:
    """Generate a simple box mesh for testing"""
    mesh = trimesh.creation.box(extents=[10, 10, 10])
    output_path = output_dir / "model.gltf"
    mesh.export(output_path)
    
    with open(output_dir / "model.json", 'w') as f:
        json.dump({"placeholder": True}, f)
        
    return output_path
