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

namespace Rokojori
{ 
  [Tool]
  [GlobalClass]
  public partial class FresnelFading:FadingModifier
  {     
    [Export]
    public bool advancedControls = true;

    public override bool IsSameType( FadingModifier modifier )
    {
      if ( modifier is FresnelFading ff )
      {
        return ff.advancedControls == advancedControls;
      }

      return false;
    }

    public override List<ShaderCode> GetFadingCode( ShaderGenerationContext context, int offsetIndex, AlphaFadeMode parentFadeMode )
    {
      if ( advancedControls )
      {
        return GetFadingCodeAdvanced( context, offsetIndex, parentFadeMode );
      }
      else
      {
        return GetFadingCodeSimple( context, offsetIndex, parentFadeMode );
      }

      return null;
    }

    public List<ShaderCode> GetFadingCodeSimple( ShaderGenerationContext context, int offsetIndex, AlphaFadeMode parentFadeMode )
    {
      var alphaFadeMode = GetFadeMode( parentFadeMode );
      var suffix = GetSuffix( offsetIndex );

      if ( context.isIncludesPhase )
      {
        return IncludeLightLibrary().Concat( IncludeMathLibrary() );
      }

      if ( context.isVariablesPhase )
      {
        var code = 
        $@"
        uniform float fresnelFadingPower{suffix} = 1.0f;
        uniform bool fresnelFadingInverse{suffix} = false;
        ";
        return ToCode( code.Indent( "  " ) );
      }


      if ( context.isFragmentPhase )
      {
        var code = 
        $@"
        float fresnelFadingAlpha{suffix} = clamp01( fresnelNormalizedFromView( NORMAL,  fresnelFadingPower{suffix} ) );  

        if ( ! fresnelFadingInverse{suffix} )
        {{ fresnelFadingAlpha{suffix} = 1.0 - fresnelFadingAlpha{suffix}; }}      
        
        ";


        return ToCode( code.Indent( "  " ) ).Concat(  ToCode( AlphaFade.Fragment( "fresnelFadingAlpha" + suffix, alphaFadeMode ) ) );
      }

      return [];
    }   


    public List<ShaderCode> GetFadingCodeAdvanced( ShaderGenerationContext context, int offsetIndex, AlphaFadeMode parentFadeMode )
    {
      var alphaFadeMode = GetFadeMode( parentFadeMode );
      var suffix = GetSuffix( offsetIndex );

      if ( context.isIncludesPhase )
      {
        return IncludeLightLibrary();
      }

      if ( context.isVariablesPhase )
      {
        var code = 
        $@"
        uniform float advancedFresnelFadingZOffset{suffix} = 0.0f;
        uniform float advancedFresnelFadingPower{suffix} = 1.0f;
        uniform float advancedFresnelFadingPostScale{suffix} = 1.0f;
        uniform float advancedFresnelFadingPostOffset{suffix} = 0.0f;
        uniform bool advancedFresnelFadingInverse{suffix} = false;

        ";
        return ToCode( code.Indent( "" ) );
      }


      if ( context.isFragmentPhase )
      {
        var code = 
        $@"
        float advancedFresnelFadingAlpha{suffix} = clamp01( fresnelNormalizedFromViewAdvanced( NORMAL,  
                                                      advancedFresnelFadingZOffset{suffix},
                                                      advancedFresnelFadingPower{suffix},
                                                      advancedFresnelFadingPostScale{suffix}, 
                                                      advancedFresnelFadingPostOffset{suffix} 
                                                  ) );        

        if ( ! advancedFresnelFadingInverse{suffix} )
        {{ advancedFresnelFadingAlpha{suffix} = 1.0 - advancedFresnelFadingAlpha{suffix}; }}      

        ";


        return ToCode( code.Indent( "  " ) ).Concat(  ToCode( AlphaFade.Fragment( "advancedFresnelFadingAlpha" + suffix, alphaFadeMode ) ) );
      }

      return [];
    } 

  }
}