using System;
using Bmaju.InnerMinmus.RingShadows;
class RingGlowTests
{
    static int count;
    static void Near(string name,double result,double expected,double tolerance=1e-9)
    {
        if(double.IsNaN(result) || Math.Abs(result-expected)>tolerance) throw new Exception(name+": "+result+" != "+expected);
        count++;Console.WriteLine("PASS "+name);
    }
    static void Main()
    {
        Near("full particle phase",RingRadiance.Lambert(1),1);
        Near("dark particle phase",RingRadiance.Lambert(-1),0);
        Near("quarter particle phase",RingRadiance.Lambert(0),1/Math.PI);
        var source=new RingEmitter { Point=new D3(10,0,0),ToSun=new D3(-1,0,0),Radiance=new D3(100,80,50) };
        var noBlockers=new GlowOccluder[0];
        D3 near=RingRadiance.Sample(new[]{source},new D3(),new D3(1,0,0),true,noBlockers,-1);
        Near("inverse square incident red",near.x,1);Near("source colour retained",near.y,0.8);
        D3 far=RingRadiance.Sample(new[]{source},new D3(-10,0,0),new D3(1,0,0),true,noBlockers,-1);
        Near("inverse square distance scaling",far.x,0.25);
        Near("receiver facing away is unlit",RingRadiance.Sample(new[]{source},new D3(),new D3(-1,0,0),true,noBlockers,-1).x,0);
        Near("flight receiver defers normal response to native shader",RingRadiance.Sample(new[]{source},new D3(),new D3(),false,noBlockers,-1).x,1);
        var blocker=new GlowOccluder(new D3(5,0,0),1);
        Near("planet occludes source",RingRadiance.Sample(new[]{source},new D3(),new D3(1,0,0),true,new[]{blocker},-1).x,0);
        Near("receiver body skip",RingRadiance.Sample(new[]{source},new D3(),new D3(1,0,0),true,new[]{blocker},0).x,1);
        Near("occluder behind receiver ignored",RingRadiance.Blocked(new D3(),new D3(10,0,0),new GlowOccluder(new D3(-5,0,0),1))?1:0,0);
        Near("occluder beyond emitter ignored",RingRadiance.Blocked(new D3(),new D3(10,0,0),new GlowOccluder(new D3(15,0,0),1))?1:0,0);
        Near("tangent ray is not blocked",RingRadiance.Blocked(new D3(),new D3(10,0,0),new GlowOccluder(new D3(5,1,0),1))?1:0,0);
        double area=0,inner=1628400,outer=1972800;
        for(int a=0;a<16;a++) for(int r=0;r<2;r++) area+=RingRadiance.SectorArea(inner+(outer-inner)*r/2,inner+(outer-inner)*(r+1)/2,16,1);
        Near("distributed patches conserve annulus area",area/(Math.PI*(outer*outer-inner*inner)),1,1e-12);
        var dark=source;dark.Radiance=new D3();Near("shadowed ring patch emits no light",RingRadiance.Sample(new[]{dark},new D3(),new D3(1,0,0),true,noBlockers,-1).x,0);
        Near("independent patches add flux",RingRadiance.Sample(new[]{source,source},new D3(),new D3(1,0,0),true,noBlockers,-1).x,2);
        Console.WriteLine("TOTAL "+count+" passed; geometry/radiance only, not Unity rendering");
    }
}
