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

namespace Rokojori
{ 
  [Tool]
  [GlobalClass]
  public partial class SubsurfaceScatteringModule:TextureModule
  { 
    public SubsurfaceScatteringModule()
    {
      _domainName = "subsurfaceScattering";
      _domainScaleName = "subsurfaceScattering";
      _domainValueName = "subsurfaceScattering";
      _target = "SSS_STRENGTH";
      _srgb = true;
      _type = TextureChannelType.ONE;
      _channelSource = TextureChannelSource.R;
    }

    [Export]
    public TextureFilter filter = TextureFilter.Linear_MipMap_Anisotropic;

    [Export]
    public bool useScale = true;



    public enum TransmittanceMode
    {
      No_Transmittance,
      Set_Transmittance,
      Offset_Transmittance
    }

    [Export]
    public TransmittanceMode transmittanceMode = TransmittanceMode.Set_Transmittance;

    public bool useTransmittance => TransmittanceMode.No_Transmittance != transmittanceMode;

    [Export]
    public bool skinMode = false;

    [Export]
    public bool repeat = true;

    [Export]
    public string uvChannel = "UV";

    [Export]
    public TextureDefault textureDefault = TextureDefault.White;

    
    [Export]
    public AssignmentType assignmentType = AssignmentType.Set;   
    
    public override void GrabValues()
    {
      _domainMode = useScale ? DomainMode.Texture_Scale : DomainMode.Texture;
      _textureFilter = filter;
      _repeat = repeat;
      _textureDefault = textureDefault;
      _uvChannel = uvChannel;    
      _assignmentType = assignmentType;
      
    }

    static readonly string DepthUniform = "subsurfaceScatteringTransmittanceDepth";
    static readonly string BoostUniform = "subsurfaceScatteringTransmittanceBoost";

    public override string AddVariables()
    {
      if ( ! useTransmittance )
      {
        return "";
      }

      var depth = Uniform( DepthUniform, 0.1f, 0, 24 );
      var boost = Uniform( BoostUniform, 0, 0, 1 ); 

      return "\n" + depth + "\n" + boost;
    }

    public override List<ShaderVariant> GetVariants( ShaderGenerationContext context )
    {
      var variants = base.GetVariants( context );

      if ( ! useTransmittance )
      {
        return variants;
      }

      if ( ShaderPhase.Fragment == context.phase )
      {
        var op = TransmittanceMode.Set_Transmittance == transmittanceMode ? " = " : " += ";

        var color = ShaderCodeVariable.SSS_TRANSMITTANCE_COLOR.variableName + op + "vec4(1.0)" + ";";
        var depth = ShaderCodeVariable.SSS_TRANSMITTANCE_DEPTH.variableName + op + DepthUniform + ";";
        var boost = ShaderCodeVariable.SSS_TRANSMITTANCE_BOOST.variableName + op + BoostUniform + ";";

        var code = "\n" + "  " + color +"\n" + "  " + depth + "\n" + "  " + boost + "\n\n";
        return ShaderVariant.CombineVariants( variants, ToVariants( ToCode( code ) ) );

      }

      return variants;
    }
  }
}