package eu.jonahbauer.raytracing.render.material;

import eu.jonahbauer.raytracing.math.Ray;
import eu.jonahbauer.raytracing.math.Vec3;
import eu.jonahbauer.raytracing.render.Color;
import eu.jonahbauer.raytracing.scene.HitResult;
import org.jetbrains.annotations.NotNull;

import java.util.Objects;
import java.util.Optional;

public record DielectricMaterial(double refractionIndex, @NotNull Color albedo) implements Material {
    public DielectricMaterial(double refractionIndex) {
        this(refractionIndex, Color.WHITE);
    }

    public DielectricMaterial {
        Objects.requireNonNull(albedo, "albedo");
    }

    @Override
    public @NotNull Optional<ScatterResult> scatter(@NotNull Ray ray, @NotNull HitResult hit) {
        var ri = hit.frontFace() ? (1 / refractionIndex) : refractionIndex;

        var cosTheta = Math.min(- ray.direction().unit().times(hit.normal()), 1.0);
        var reflectance = reflectance(cosTheta);
        var reflect = reflectance > Math.random();

        var newDirection = (reflect ? Optional.<Vec3>empty() : Vec3.refract(ray.direction(), hit.normal(), ri))
                .orElseGet(() -> Vec3.reflect(ray.direction(), hit.normal()));

        return Optional.of(new ScatterResult(new Ray(hit.position(), newDirection), albedo));
    }

    private double reflectance(double cos) {
        // use schlick's approximation for reflectance
        var r0 = (1 - refractionIndex) / (1 + refractionIndex);
        r0 = r0 * r0;
        return r0 + (1 - r0) * (1 - cos) * (1 - cos) * (1 - cos) * (1 - cos) * (1 - cos);
    }
}
