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

using System.Threading.Tasks;

namespace Rokojori
{
  [Tool]
  [GlobalClass]
  public partial class Octahedral_Baker:_XX_MultiBakeMode
  {
    public static readonly string octahedralShader = "res://addons/rokojori_action_library/External/Imposter/materials/shaders/ImpostorShader.gdshader";


    [Export]
    public int octahedralSides = 4;
    [Export]
    public bool octahedralFullSphere = false;
    

    public override int GetNumViews()
    {
      var views = octahedralSides * octahedralSides;

      return views;
    }

    public override void CreateMaterial( List<_XX_BakingPass> passes )
    {
      var mb = multiBaker;
      var material = new ShaderMaterial();
      material.Shader = ResourceLoader.Load( octahedralShader ) as Shader;

      material.SetShaderParameter( "isFullSphere", octahedralFullSphere );
      material.SetShaderParameter( "imposterFrames", Vector2.One * octahedralSides  );

      // Materials.Set( mb.X_outputMesh, material );    


      MaterialSurfaceContainer.SetMaterialInSlot( mb.X_outputMesh, MaterialSlot.MeshSurface, material );
    }

    public override void AssignMaterial( List<_XX_BakingPass> passes )
    {
      var mb = multiBaker;

      // var material = Materials.Get<ShaderMaterial>( mb.X_outputMesh );     

      var material = MaterialSurfaceContainer.GetMaterialInSlot<ShaderMaterial>( mb.X_outputMesh, MaterialSlot.MeshSurface ); 

      if ( material == null )
      {
        RJLog.Log( "Not the right material on mesh!" );
        return;
      }

      
      material.SetShaderParameter( "imposterTextureAlbedo", 
        _XX_BakingPass.Get( passes, BakingTargetType.Albedo, BakingTargetType.Lit ) );
      
      material.SetShaderParameter( "imposterTextureNormal", 
        _XX_BakingPass.Get( passes, BakingTargetType.Normals ) );

      material.SetShaderParameter( "imposterTextureOrm", 
        _XX_BakingPass.Get( passes, BakingTargetType.ORM ) );  

      material.SetShaderParameter( "imposterTextureDepth", 
        _XX_BakingPass.Get( passes, BakingTargetType.Depth ) );       
      
    }

    public override void CreateBakers()
    {
      var fov = multiBaker.GetCameraFOV();
      var distance = multiBaker.GetCameraDistance();
      var outputScale = multiBaker.GetOutputScale();

      var _bakers = multiBaker.bakerCameras;
      var mb = multiBaker;

      

      _bakers.ForEach(
        bk =>
        {
          var vs = bk.viewSettings;
          vs.fovDistance = Manual_BakingFDSettings.Create( fov, distance );      

          vs.rotationMode = BakingViewSettings.RotationMode.Quaternion;
        }
      );


      var numTextures = GetNumViews();
      var textureAlignment = TextureMerger.ComputeTextureAlignment( numTextures );
 
      var toOP = 1f / ( octahedralSides - 1 );
      var index = 0;

      for ( int x = 0; x < octahedralSides; x++ )
      {
        for ( int y = 0; y < octahedralSides; y++ )
        {
          var inverseX = ( octahedralSides - 1 ) - x; 
          var inverseY = ( octahedralSides - 1 ) - y; 
          var octahedralPosition = new Vector2( y, inverseX ) * toOP;

          var normal = OctahedralMapping.Map( octahedralPosition, octahedralFullSphere );

          _bakers[ index ].viewSettings.rotationQuaternion = Math3D.LookRotation( normal, true ).Normalized().Inverse();           

          index ++;
        }


      }

      var qm = new QuadMesh();
      mb.X_outputMesh.Mesh = qm;
      var magicScale = 0.75f;
      mb.X_outputMesh.Scale = Vector3.One * ( outputScale / mb.cameraZoom * magicScale);
            
      
    }

    
  }
}