using Godot;
using System.Collections;
using System.Collections.Generic;

namespace Rokojori
{
  public class LODCameraDistanceLevel
  {
    public Mesh mesh;
    public Material material;
    public float distance;
  }

  public class LODBuilder
  {
    public enum Mode
    {
      CameraDistance
    }

    Mode mode = Mode.CameraDistance;

    public static LODBuilder ByCameraDistance()
    {
      var builder = new LODBuilder();

      builder.mode = Mode.CameraDistance;

      return builder;
    }

    List<LODCameraDistanceLevel> levels = new List<LODCameraDistanceLevel>();

    Material material;

    public LODBuilder SetMaterial( Material material )
    {
      this.material = material;

      return this;
    }

    public LODBuilder Add( float distance, Mesh mesh, Material material = null )
    {
      var level = new LODCameraDistanceLevel
      {
        mesh = mesh,
        distance = distance,
        material = material
      };

      levels.Add( level );
      return this;
    }

    public LODNode Create( Node parent, string name = "LOD" )
    {
      var lodNode = parent.CreateChild<LODNode>( name );

      var arrangement = new LODArrangement();

      levels.Sort( ( a, b ) => Mathf.Sign( a.distance - b.distance ) );

      var maxMap = new Dictionary<LODCameraDistanceLevel, float>();

      for ( int i = 0; i < levels.Count; i++ )
      {
        if ( ( i + 1 ) < levels.Count )
        {
          maxMap[ levels[ i ] ] = levels[ i + 1 ].distance;
        }
        else
        {
          maxMap[ levels[ i ] ] = 10000f;
        }
      }

      levels[ 0 ].distance = 0;

      levels.ForEach(
        ( l )=>
        {
          var level = new LODLevel();
          var distanceRule = new LODCameraDistanceRule();
          distanceRule.minDistance = l.distance;
          distanceRule.maxDistance = maxMap[ l ];
          
          level.visibilityRules = [ distanceRule ];
          level.mesh = l.mesh;
          level.material = l.material != null ? l.material : material; 
          arrangement.levels = arrangement.levels.Add( level );
        }
      );

      lodNode.arrangement = arrangement;


      return lodNode;
    }


  }
  
}