using Godot;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;

namespace Rokojori
{ 
  [Tool]
  [GlobalClass]
  public partial class CameraDistanceFading:FadingModifier
  { 
    public enum Mode
    {
      Near_Camera,
      Far_Camera
    }

    [Export]
    public Mode mode;
    

    public override bool IsSameType( FadingModifier modifier )
    {
      if ( modifier is CameraDistanceFading cdf )
      {
        return cdf.mode == mode;
      }

      return false;
    }

    public override List<ShaderCode> GetFadingCode( ShaderGenerationContext context, int offsetIndex, AlphaFadeMode parentFadeMode )
    {
      bool isNear = mode == Mode.Near_Camera;

      var alphaFadeMode = GetFadeMode( parentFadeMode );
      
      var suffix = GetSuffix( offsetIndex );

      if ( context.isIncludesPhase )
      {
        return IncludeNoiseLibrary().Concat( IncludeCamerasLibrary() );
      }

      var fadeOutVariable = isNear ? "nearCameraFadeOutDistance" : "farCameraFadeOutDistance";
      var fadeInVariable = isNear ? "nearCameraFadeInDistance" : "farCameraFadeInDistance";

      fadeOutVariable += suffix;
      fadeInVariable += suffix;

      if ( context.isVariablesPhase )
      {
        if ( isNear )
        {
          var nearFadeOutDistance  = Uniform( fadeOutVariable, 0.0f, 0.1f, 5000 ).LineBreak();
          var nearFadeInDistance   = Uniform( fadeInVariable, 0.0f, 0.5f, 5000 ).LineBreak();

          return ToCode( nearFadeOutDistance, nearFadeInDistance );
        }
        else
        {
          var farFadeInDistance   = Uniform( fadeInVariable, 0.0f, 0.1f, 5000 ).LineBreak();
          var farFadeOutDistance  = Uniform( fadeOutVariable, 0.0f, 0.5f, 5000 ).LineBreak();

          return ToCode( farFadeInDistance, farFadeOutDistance );
        }        
      }


      if ( context.isFragmentPhase )
      {
        var prefix = isNear ? "near" : "far";
        var variable = $"{prefix}CameraDistanceFadeAlpha{suffix}"; 
        var code = $"float {variable} = cameraDistanceFade( VERTEX, {fadeOutVariable}, {fadeInVariable});\n";        

        return ToCode( code.Indent( "  ") ).Concat( ToCode( AlphaFade.Fragment( variable, alphaFadeMode ) ) );
      }

      return [];
    }


  }
}