package geometry.scene;

import basics.math.algebra.Ray;
import basics.math.algebra.Vector;
import optics.light.Color;
import optics.light.Directional;
import optics.light.LightSource;
import optics.light.Point;
import pathtracing.BSDF;
import raytracing.BasicMaterial;
import renderer.mesh.BasicMesh;
import renderer.mesh.Mesh;
import renderer.primitive.Disk;
import renderer.primitive.Plane;
import renderer.primitive.Sphere;
import shading.Material;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class Scene {

    private AccelerationStructure structure;

    private List<LightSource> lights;

    public Scene(AccelerationStructure structure) {
        this.structure = structure;
        this.lights = new ArrayList<>();
    }

    public static Scene generateRaytracingExampleScene() {
        Scene scene = new Scene(new LinearList());

        BasicMaterial glass = new BasicMaterial(Color.BLACK, 1.0, Color.WHITE, true);
        BasicMaterial mirror = new BasicMaterial(Color.BLACK, 1.0, Color.WHITE, false);
        BasicMaterial white  = new BasicMaterial(new Color(0.8, 0.8, 0.8), 0.1, new Color(0.8, 0.8, 0.8), false);
        BasicMaterial red    = new BasicMaterial(new Color(0.8, 0.0, 0.0), 0.1, new Color(0.8, 0.8, 0.8), false);
        BasicMaterial green  = new BasicMaterial(new Color(0.0, 0.8, 0.0), 0.1, new Color(0.8, 0.8, 0.8), false);
        BasicMaterial blue   = new BasicMaterial(new Color(0.0, 0.0, 0.8), 0.1, new Color(0.8, 0.8, 0.8), false);

        scene.addMesh(new BasicMesh(glass, new Sphere(new Vector(0,0,0), 1.0)));
        scene.addMesh(new BasicMesh(white, new Sphere(new Vector(3,2,0), 0.25)));
        scene.addMesh(new BasicMesh(red, new Sphere(new Vector(2.5,2,-3), 0.33)));

        scene.addMesh(new BasicMesh(white, new Plane(new Vector(0, 1, 0), 1)));
        scene.addMesh(new BasicMesh(white, new Plane(new Vector(0, 1, 0), -6)));

        scene.addMesh(new BasicMesh(red, new Plane(new Vector(1, 0, 0), -4)));
        scene.addMesh(new BasicMesh(green, new Plane(new Vector(1, 0, 0), 4)));

        scene.addMesh(new BasicMesh(blue, new Plane(new Vector(0, 0, 1), 5)));
        scene.addMesh(new BasicMesh(mirror, new Plane(new Vector(0, 0, 1), -4)));

        scene.addLight(new Point(Color.WHITE.scale(0.5), new Vector(0, 4, 0)));
        scene.addLight(new Point(Color.WHITE.scale(0.5), new Vector(1, 3, 1)));

        return scene;
    }

    public static Scene generatePathtracingExampleScene() {
        Scene scene = new Scene(new LinearList());

        BSDF red = new BSDF(new Color(1, 0.3, 0.3), new Color(0), 1.0);
        BSDF green = new BSDF(new Color(0.3,1, 0.3), new Color(0), 1);
        BSDF blue = new BSDF(new Color(0.3, 0.3, 1), new Color(0), 1);
        BSDF white = new BSDF(new Color(1, 1, 1), new Color(0), 1);
        BSDF light = new BSDF(Color.BLACK, new Color(300), 1.0);

        scene.addMesh(new BasicMesh(white, new Sphere(new Vector(0,0,0), 1.0)));
        scene.addMesh(new BasicMesh(white, new Sphere(new Vector(3,2,1), 1.0)));

        scene.addMesh(new BasicMesh(white, new Plane(new Vector(0, 1, 0), 1)));
        scene.addMesh(new BasicMesh(white, new Plane(new Vector(0, 1, 0), -6)));

        scene.addMesh(new BasicMesh(red, new Plane(new Vector(-1, 0, 0), 4)));
        scene.addMesh(new BasicMesh(green, new Plane(new Vector(-1, 0, 0), -4)));

        scene.addMesh(new BasicMesh(blue, new Plane(new Vector(0, 0, 1), 5)));
        scene.addMesh(new BasicMesh(white, new Plane(new Vector(0, 0, 1), -4)));

        scene.addMesh(new BasicMesh(light, new Sphere(new Vector(0,6.0,0), 1.0)));
        //scene.addLight(new Point(Color.WHITE.scale(1.0), new Vector(0, 4, 0)));

        return scene;
    }

    public void addLight(LightSource light) {
        this.lights.add(light);
    }

    public void addMesh(Mesh mesh) {
        this.structure.addMesh(mesh);
    }

    public Optional<Hit> intersect(Ray ray) {
        return this.structure.intersect(ray);
    }

    public List<LightSource> getLights() {
        return lights;
    }
}
