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

using System.Threading.Tasks;

namespace Rokojori
{
  [Tool][GlobalClass]
  public partial class Cylinder_Baker:_XX_MultiBakeModeBillboardBase
  {
    [Export]
    public int cylinderSides = 4;
    [Export]
    public bool createBackFacesForSides = false;
    [Export]
    public bool cylinderTop = false;
    [Export]
    public bool createBackFacesForTop = false;
    [Export]
    public bool cylinderBottom = false;
    [Export]
    public bool createBackFacesForBottom = false;
    [Export( PropertyHint.Range, "-1,1" )]
    public float cylinderSideOffset = 0;
    [Export( PropertyHint.Range, "-1,1" )]
    public float cylinderTopOffset = 0f;
    [Export( PropertyHint.Range, "-1,1" )]
    public float cylinderBottomOffset = 0f;   


    public override int GetNumViews()
    {
      var cylinderViews = cylinderSides;

      if ( cylinderBottom )
      {
        cylinderViews ++;
      }

      if ( cylinderTop )
      {
        cylinderViews ++;
      }

      return cylinderViews;
    }

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

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


      bakerCameras.ForEach(
        bk =>
        {
          var vs = bk.viewSettings;
          vs.fovDistance = Manual_BakingFDSettings.Create( fov, distance );
          vs.rotationMode = BakingViewSettings.RotationMode.Yaw_Pitch;
        }
      );

      var index = 0;
      var mg = new MeshGeometry();  

      var numTextures = GetNumViews();
      var textureAlignment = TextureMerger.ComputeTextureAlignment( numTextures );
 

      if ( cylinderTop )
      {
        bakerCameras[ index ].viewSettings.yaw = 0;
        bakerCameras[ index ].viewSettings.pitch = 90f;        

        var uv = TextureMerger.GetUVRectangle( textureAlignment, index, true );

        var q = new MeshGeometry();        
        q.AddQuad( bakerCameras[ index ].viewSettings.bakingRotation, outputScale, uv.min, uv.max );  


        if ( cylinderTopOffset != 0 )
        {
          var topOffset = Vector3.Up * cylinderTopOffset * outputScale * 0.5f;
          q.ApplyTranslation( topOffset, -4 );
        }

        mg.Add( q );

        if ( createBackFacesForTop )
        {
          q.FlipNormalDirection();
          mg.Add( q );
        }

        index ++;
      }

      if ( cylinderBottom )
      {
        bakerCameras[ index ].viewSettings.yaw = 0;
        bakerCameras[ index ].viewSettings.pitch = -90f;

        var uv = TextureMerger.GetUVRectangle( textureAlignment, index, true );

        var q = new MeshGeometry();
        q.AddQuad( bakerCameras[ index ].viewSettings.bakingRotation, outputScale, uv.min, uv.max ); 

        if ( cylinderBottomOffset != 0 )
        {
          var bottomOffset = Vector3.Down * cylinderBottomOffset * outputScale * 0.5f;
          q.ApplyTranslation( bottomOffset, -4 );
        }

        mg.Add( q );

        if ( createBackFacesForBottom )
        {
          q.FlipNormalDirection();
          mg.Add( q );
        }

        index ++;
      }

      
      for ( int i = 0; i < cylinderSides; i++ )
      {
        var angle = ( 360f * i ) / (float) cylinderSides;
        bakerCameras[ index ].viewSettings.yaw = angle;
        bakerCameras[ index ].viewSettings.pitch = 0;

        var uv = TextureMerger.GetUVRectangle( textureAlignment, index, true );    
        

        var q = new MeshGeometry(); 
        q.AddQuad( bakerCameras[ index ].viewSettings.bakingRotation, outputScale, uv.min, uv.max ); 

         if ( cylinderSideOffset != 0 )
        {
          var sideOffset = Vector3.Forward *bakerCameras[ index ].viewSettings.bakingRotation * cylinderSideOffset * outputScale * -0.5f;
          q.ApplyTranslation( sideOffset, -4 );
        }                

        mg.Add( q );

        if ( createBackFacesForSides )
        {
          q.FlipNormalDirection();
          mg.Add( q );
        }

        index++;

      }

      mg.ApplyTranslation( -mb.targetPivot );
      
      mb.X_outputMesh.Mesh = mg.GenerateMesh();  
      
    }
  }
}