Shader "Custom/SkyStylized"
{
    Properties
    {
        [Header(Features)]
        [Toggle] _EnableGradient("Enable Gradient", Float) = 1
        [Toggle] _EnableClouds("Enable Clouds", Float) = 1
        [Toggle] _EnableSun("Enable Sun", Float) = 1

        [Header(Sky Colors)]
        _SkyColor ("Sky Color", Color) = (0.5, 0.7, 1.0, 1)
        [AllIn13DShaderGradientDrawer]_GradientRamp ("Gradient Ramp", 2D) = "white" {} 
        _RampTiling ("Ramp Tiling", Range(0.1, 4)) = 1.0
        _HorizonOffset ("Horizon Offset", Range(-0.5, 0.5)) = 0.15

        [Header(Cloud Shape)]
        _CloudColor ("Cloud Color", Color) = (1,1,1,1)
        _CloudThreshold ("Cloud Cutoff", Range(0, 1)) = 0.5
        _CloudContrast ("Cloud Contrast", Range(1, 10)) = 2
        _CloudDensity ("Cloud Coverage", Range(0, 1)) = 0.5
        
        [Header(Cloud Movement)]
        _CloudSpeed ("Cloud Speed", Vector) = (0.1, 0, 0.05, 0)
        _WindStretch ("Wind Stretch", Range(0, 2)) = 0.5
        
        [Header(Cloud Pattern)]
        _CloudScale1 ("Large Pattern Scale", Range(1, 20)) = 8
        _CloudScale2 ("Detail Scale", Range(1, 20)) = 12
        _WarpStrength ("Pattern Distortion", Range(0, 1)) = 0.3
        _CloudHeight ("Cloud Height", Range(0, 1)) = 0.3
        _CloudThickness ("Cloud Thickness", Range(0, 1)) = 0.1

        [Header(Sun)]
        _SunColor ("Sun Color", Color) = (1, 0.54, 0.17, 1)
        _SunSize ("Sun Size", Range(0.0001, 1.0)) = 0.05
        [Header(Sun Glow)]
        _GlowColor ("Glow Color", Color) = (1, 0.95, 0.8, 1)
        _GlowSize ("Glow Size", Range(1, 10)) = 4
        _GlowPower ("Glow Falloff", Range(1, 10)) = 3
    }

    SubShader
    {
        Tags
        {
            "Queue"="Background"
            "RenderType"="Background"
            "PreviewType"="Skybox"
        }
        Cull Off
        ZWrite Off

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 3.0
            #pragma shader_feature_local _ENABLEGRADIENT_ON
            #pragma shader_feature_local _ENABLECLOUDS_ON
            #pragma shader_feature_local _ENABLESUN_ON

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
                float3 worldPos : TEXCOORD0;
                float2 rampUV : TEXCOORD1;
            };

            // Toggle properties
            float _EnableGradient;
            float _EnableClouds;
            float _EnableSun;
            float4 _SkyColor;

            // Sky properties
            sampler2D _GradientRamp;
            float _RampTiling;
            float _HorizonOffset;

            // Cloud properties
            float4 _CloudColor;
            float _CloudThreshold, _CloudContrast, _CloudDensity;
            float4 _CloudSpeed;
            float _WindStretch;
            float _CloudScale1, _CloudScale2, _WarpStrength;
            float _CloudHeight, _CloudThickness;

            // Sun properties
            float4 _SunColor;
            float _SunSize;
            float4 _GlowColor;
            float _GlowSize, _GlowPower;

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldPos = normalize(mul(unity_ObjectToWorld, v.vertex).xyz);
                
                // Map world height to UV coordinates for gradient
                float height = o.worldPos.y + _HorizonOffset;
                o.rampUV = float2(height * _RampTiling + 0.5, 0.5);
                
                return o;
            }

            float hash(float3 p)
            {
                p = frac(p * 0.3183099 + 0.1);
                p *= 17.0;
                return frac(p.x * p.y * p.z * (p.x + p.y + p.z));
            }

            float noise(float3 x)
            {
                float3 i = floor(x);
                float3 f = frac(x);
                f = f * f * (3.0 - 2.0 * f);
                
                return lerp(lerp(lerp(hash(i + float3(0,0,0)), 
                                    hash(i + float3(1,0,0)), f.x),
                               lerp(hash(i + float3(0,1,0)), 
                                    hash(i + float3(1,1,0)), f.x), f.y),
                           lerp(lerp(hash(i + float3(0,0,1)), 
                                    hash(i + float3(1,0,1)), f.x),
                               lerp(hash(i + float3(0,1,1)), 
                                    hash(i + float3(1,1,1)), f.x), f.y), f.z);
            }

            float fbm(float3 p)
            {
                float value = 0.0;
                float amplitude = 0.5;
                float frequency = 1.0;
                
                for(int i = 0; i < 4; i++)
                {
                    value += amplitude * noise(p * frequency);
                    amplitude *= 0.5;
                    frequency *= 2.0;
                }
                
                return value;
            }

            float3 warp(float3 pos, float strength)
            {
                float3 q = float3(
                    fbm(pos + float3(0.0, 1.0, 0.5)),
                    fbm(pos + float3(2.0, -2.0, -0.5)),
                    fbm(pos + float3(-2.0, -1.0, 1.0))
                );
                
                return pos + q * strength;
            }

            float calculateCloudShape(float3 worldPos)
            {
                // Apply wind stretching along movement direction
                float3 stretching = worldPos;
                stretching.xz += worldPos.y * _WindStretch * normalize(_CloudSpeed.xz);
                
                // First layer of warping for large cloud shapes
                float3 warpedPos = warp(stretching * _CloudScale1 + _Time.y * _CloudSpeed, _WarpStrength);
                float largePattern = fbm(warpedPos);
                
                // Second layer for detail and erosion
                float3 detailPos = stretching * _CloudScale2 + _Time.y * _CloudSpeed * 1.5;
                float detail = fbm(detailPos + largePattern * 0.5) * 0.5;
                
                // Combine patterns and apply threshold
                float clouds = largePattern + detail;
                clouds = saturate((clouds - _CloudThreshold) * _CloudContrast);
                
                return clouds;
            }

            float calculateClouds(float3 worldPos)
            {
                // Height-based cloud layer mask
                float heightMask = smoothstep(_CloudHeight - _CloudThickness, 
                                           _CloudHeight + _CloudThickness, 
                                           worldPos.y);
                
                // Calculate cloud pattern
                float cloudPattern = calculateCloudShape(worldPos);
                
                // Apply coverage control
                float coverage = cloudPattern * _CloudDensity;
                
                // Combine with height mask
                return coverage * heightMask;
            }

            float3 calculateSun(float3 rayDir)
            {
                float3 sunDir = normalize(_WorldSpaceLightPos0.xyz);
                float3 delta = rayDir - sunDir;
                float distToSun = length(delta);

                // Sharp sun disk
                float sunDisk = distToSun < _SunSize ? 1.0 : 0.0;

                // Smooth glow falloff
                float glow = 1.0 - saturate(distToSun / (_SunSize * _GlowSize));
                glow = pow(glow, _GlowPower);

                // Combine sun disk and glow
                return _SunColor.rgb * sunDisk + _GlowColor.rgb * glow;
            }

            float4 frag(v2f i) : SV_Target
            {
                // Sample sky color or gradient
                float4 skyColor;
                #if _ENABLEGRADIENT_ON
                    skyColor = tex2D(_GradientRamp, i.rampUV);
                    skyColor.rgb *= _SkyColor.rgb;
                #else
                    skyColor = _SkyColor;
                #endif

                // Calculate cloud coverage
                #if _ENABLECLOUDS_ON
                    float clouds = calculateClouds(i.worldPos);
                    skyColor.rgb = lerp(skyColor.rgb, _CloudColor.rgb, clouds);
                #endif

                // Add sun contribution
                #if _ENABLESUN_ON
                    float3 sunContribution = calculateSun(i.worldPos);
                    skyColor.rgb += sunContribution;
                #endif

                return skyColor;
            }
            ENDCG
        }
    }
}