from pathlib import Path
from ursina import application
from time import perf_counter
from ursina.string_utilities import print_info


def ursinamesh_to_obj(mesh, name='', out_path=application.compressed_models_folder, max_decimals=5, flip_faces=True):
    from ursina.string_utilities import camel_to_snake

    obj = ''
    obj += f'mtllib {name}.mtl\n'
    obj += f'usemtl {name}\n'

    if not name:
        name = camel_to_snake(mesh.__class__.__name__)
    obj += 'o ' + name + '\n'
    verts = mesh.vertices

    for v in verts:
        v = [round(e, max_decimals) for e in v]
        obj += f'v {v[0]} {v[1]} {v[2]}\n'

    if mesh.uvs:
        for uv in mesh.uvs:
            uv = [round(e, max_decimals) for e in uv]
            obj += f'vt {uv[0]} {uv[1]}\n'

    obj += 's off\n'

    if mesh.triangles:
        tris = mesh.triangles

        if isinstance(tris[0], tuple): # convert from tuples to flat
            new_tris = []
            for t in tris:
                if len(t) == 3:
                    if not flip_faces:
                        new_tris.extend([t[0], t[1], t[2]])
                    else:
                        new_tris.extend([t[2], t[1], t[0]])
                elif len(t) == 4: # turn quad into tris
                    if not flip_faces:
                        new_tris.extend([t[0], t[1], t[2], t[2], t[3], t[0]])
                    else:
                        new_tris.extend([t[2], t[1], t[0], t[0], t[3], t[2]])

            tris = new_tris


    if mesh.mode == 'ngon':
        tris = []
        for i in range(1, len(mesh.vertices)-1):
            tris.extend((i, i+1, 0))


    # tris must be a list of indices
    for i, t in enumerate(tris):
        if i % 3 == 0:
            obj += '\nf '
        obj += str(t+1)
        if mesh.uvs:
            obj += '/'+str(t+1)
        obj += ' '

    obj += '\n'
    # print(obj)
    with open(out_path / (name + '.obj'), 'w') as f:
        f.write(obj)
        print_info('saved obj:', out_path / (name + '.obj'))





def ursinamesh_to_dae(mesh, name, folder:Path=application.compressed_models_folder, texture_name=''):
    num_vertices = len(mesh.generated_vertices)
    vertices = ' '.join([f'{v[2]} {v[1]} {v[0]}' for v in mesh.generated_vertices])

    # triangle_indices = ' '.join([f'{i} '*4 for i in range(num_vertices, 0, -1)])
    triangle_indices = ' '.join([f'{i} '*4 for i in range(num_vertices)])
    num_triangle_indices = num_vertices

    num_uvs = len(mesh.uvs)
    uvs = ' '.join([f'{uv[0]} {uv[1]}' for uv in mesh.uvs])

    num_vertex_colors = len(mesh.colors)
    vertex_colors = ' '.join([f'{c[0]} {c[1]} {c[2]} {c[3]}' for c in mesh.colors])

    texture_name = texture_name.replace('.','_')
    # print(vertices)
    text = f'''<?xml version="1.0" encoding="utf-8"?>
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <asset>
    <contributor>
      <author>Ursina User</author>
      <authoring_tool>ursina</authoring_tool>
    </contributor>
    <unit name="meter" meter="1"/>
    <up_axis>Y_UP</up_axis>
  </asset>
  <library_effects>
    <effect id="Material-effect">
      <profile_COMMON>
        <newparam sid="{texture_name}-surface">
          <surface type="2D">
            <init_from>{texture_name}</init_from>
          </surface>
        </newparam>
        <newparam sid="{texture_name}-sampler">
          <sampler2D>
            <source>{texture_name}-surface</source>
          </sampler2D>
        </newparam>
        <technique sid="common">
          <lambert>
            <emission>
              <color sid="emission">0 0 0 1</color>
            </emission>
            <diffuse>
              <texture texture="{texture_name}-sampler" texcoord="UVMap"/>
            </diffuse>
            <index_of_refraction>
              <float sid="ior">1.45</float>
            </index_of_refraction>
          </lambert>
        </technique>
      </profile_COMMON>
    </effect>
  </library_effects>
  <library_images/>
  <library_materials>
    <material id="Material-material" name="Material">
      <instance_effect url="#Material-effect"/>
    </material>
  </library_materials>
  <library_geometries>
    <geometry id="Cube-mesh" name="Cube">
      <mesh>
        <source id="Cube-mesh-positions">
          <float_array id="Cube-mesh-positions-array" count="{num_vertices*3}">{vertices}</float_array>
          <technique_common>
            <accessor source="#Cube-mesh-positions-array" count="{num_vertices}" stride="3">
              <param name="X" type="float"/>
              <param name="Y" type="float"/>
              <param name="Z" type="float"/>
            </accessor>
          </technique_common>
        </source>
        <source id="Cube-mesh-normals">
          <float_array id="Cube-mesh-normals-array" count="18">0 0 1 0 -1 0 -1 0 0 0 0 -1 1 0 0 0 1 0</float_array>
          <technique_common>
            <accessor source="#Cube-mesh-normals-array" count="6" stride="3">
              <param name="X" type="float"/>
              <param name="Y" type="float"/>
              <param name="Z" type="float"/>
            </accessor>
          </technique_common>
        </source>
        <source id="Cube-mesh-map-0">
          <float_array id="Cube-mesh-map-0-array" count="{num_uvs*2}">{uvs}</float_array>
          <technique_common>
            <accessor source="#Cube-mesh-map-0-array" count="{num_uvs}" stride="2">
              <param name="S" type="float"/>
              <param name="T" type="float"/>
            </accessor>
          </technique_common>
        </source>
        <source id="Cube-mesh-colors-Col" name="Col">
          <float_array id="Cube-mesh-colors-Col-array" count="{num_vertex_colors*3}">{vertex_colors}</float_array>
          <technique_common>
            <accessor source="#Cube-mesh-colors-Col-array" count="{num_vertex_colors}" stride="4">
              <param name="R" type="float"/>
              <param name="G" type="float"/>
              <param name="B" type="float"/>
              <param name="A" type="float"/>
            </accessor>
          </technique_common>
        </source>
        <vertices id="Cube-mesh-vertices">
          <input semantic="POSITION" source="#Cube-mesh-positions"/>
        </vertices>
        <triangles material="Material-material" count="{num_triangle_indices}">
          <input semantic="VERTEX" source="#Cube-mesh-vertices" offset="0"/>
          <input semantic="NORMAL" source="#Cube-mesh-normals" offset="1"/>
          <input semantic="TEXCOORD" source="#Cube-mesh-map-0" offset="2" set="0"/>
          <input semantic="COLOR" source="#Cube-mesh-colors-Col" offset="3" set="0"/>
          <p>{triangle_indices}</p>
        </triangles>
      </mesh>
    </geometry>
  </library_geometries>
  <library_visual_scenes>
    <visual_scene id="Scene" name="Scene">
      <node id="Cube" name="Cube" type="NODE">
        <matrix sid="transform">1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1</matrix>
        <instance_geometry url="#Cube-mesh" name="Cube">
          <bind_material>
            <technique_common>
              <instance_material symbol="Material-material" target="#Material-material">
                <bind_vertex_input semantic="UVMap" input_semantic="TEXCOORD" input_set="0"/>
              </instance_material>
            </technique_common>
          </bind_material>
        </instance_geometry>
      </node>
    </visual_scene>
  </library_visual_scenes>
  <scene>
    <instance_visual_scene url="#Scene"/>
  </scene>
</COLLADA>
    '''
    with (folder / f'{name}.dae').open('w') as f:
        f.write(text)


if __name__ == '__main__':
    from ursina import Ursina, Entity, load_model, EditorCamera, Sky
    app = Ursina()

    t = perf_counter()
    Entity(model='untitled')
    print('-------', perf_counter() - t)
    m = load_model('cube', use_deepcopy=True)
    ursinamesh_to_dae(m, 'dae_export_test.dae')
    EditorCamera()
    Sky(texture='sky_sunset')

    app.run()