package eu.jonahbauer.raytracing.scene.hittable3d;

import eu.jonahbauer.raytracing.math.AABB;
import eu.jonahbauer.raytracing.math.Range;
import eu.jonahbauer.raytracing.math.Ray;
import eu.jonahbauer.raytracing.math.Vec3;
import eu.jonahbauer.raytracing.render.material.IsotropicMaterial;
import eu.jonahbauer.raytracing.scene.HitResult;
import eu.jonahbauer.raytracing.scene.Hittable;
import org.jetbrains.annotations.NotNull;

import java.util.Optional;

public record ConstantMedium(@NotNull Hittable boundary, double density, @NotNull IsotropicMaterial material) implements Hittable {

    @Override
    public @NotNull Optional<HitResult> hit(@NotNull Ray ray, @NotNull Range range) {
        var hit1 = boundary.hit(ray, Range.UNIVERSE);
        if (hit1.isEmpty()) return Optional.empty();

        var hit2 = boundary.hit(ray, new Range(hit1.get().t() + 0.0001, Double.POSITIVE_INFINITY));
        if (hit2.isEmpty()) return Optional.empty();

        var tmin = Math.max(range.min(), hit1.get().t());
        var tmax = Math.min(range.max(), hit2.get().t());
        if (tmin >= tmax) return Optional.empty();
        if (tmin < 0) tmin = 0;

        var length = ray.direction().length();
        var distance = length * (tmax - tmin);
        var hitDistance = - Math.log(Math.random()) / density;
        if (hitDistance > distance) return Optional.empty();

        var t = tmin + hitDistance / length;
        return Optional.of(new HitResult(t, ray.at(t), Vec3.UNIT_X, material, 0, 0, true)); // arbitrary normal, u, v and isFrontFace
    }

    @Override
    public @NotNull AABB getBoundingBox() {
        return boundary().getBoundingBox();
    }
}
