"""Example: Lines in a Projective Plane.

Draw N random lines in the projective plane and visualize them as great
circles on the sphere, as well as straight lines in an affine plane.
"""

#############################################
# Setup
#############################################

# [setup-1]
# Import necessary libraries
import bpy
import numpy as np

import ddg
import ddg.geometry.intersection
import ddg.geometry.quadrics
import ddg.geometry.subspaces
import ddg.math.random
import ddg.visualization.blender.camera
import ddg.visualization.blender.collection
import ddg.visualization.blender.light
import ddg.visualization.blender.material
import ddg.visualization.blender.mesh
from ddg.visualization.blender.scene import clear

# [setup-1]

# [setup-2]
# Clear the existing objects in the Blender scene
clear()
# [setup-2]


#############################################
# Blender Collections
#############################################

# [blender-collections]
# Create Blender collections for organizing objects
rendering_coll = ddg.visualization.blender.collection.collection("light and camera")
gc_coll = ddg.visualization.blender.collection.collection("great_circles")
plane_coll = ddg.visualization.blender.collection.collection("plane_intersections")
# [blender-collections]


#############################################
# Geometric Calculations
#############################################

# [geometric-calculations-1]
# Generate N random normals and calculate corresponding planes
N = 4
seed = 59232
normals = [ddg.math.random.random_point_on_sphere(2, i * seed) for i in range(N)]
planes = [
    ddg.geometry.subspaces.hyperplane_from_normal(normal, point=(0, 0, 0))
    for normal in normals
]
# [geometric-calculations-1]

# [geometric-calculations-2]
# Create a unit sphere (S2) and a projective plane
s2 = ddg.geometry.quadrics.Quadric(np.diag([1, 1, 1, -1]))
bobj_s2 = ddg.to_blender_object_helper(s2, sampling=[0.1, 40, "c"], name="s2")

projective_plane = ddg.geometry.subspaces.hyperplane_from_normal(
    (-1, 0, 0), point=(1.5, 0, 0)
)
# [geometric-calculations-2]


#############################################
# Geometric Intersections
#############################################

# [geometric-intersections-1]
# Calculate intersections of the random planes with S2 and the projective plane
for plane in planes:
    circ_on_sphere = ddg.geometry.intersection.meet(plane, s2)
    meet_plane = ddg.geometry.intersection.meet(plane, projective_plane)

    # Orthonormalize the intersection plane
    meet_plane = ddg.geometry.subspaces.Subspace.orthonormalize(meet_plane)

    if circ_on_sphere.dimension != -1:
        # Create Blender objects for circles on the sphere
        bobj_circ_on_sphere = ddg.to_blender_object_helper(
            circ_on_sphere,
            name="spheric circle",
            sampling=[0.1, 100, "c"],
            curve_properties={"bevel_depth": 0.005},
            collection=gc_coll,
        )

    if meet_plane.dimension != -1:
        # Create Blender objects for plane intersections
        bobj_meet_plane = ddg.to_blender_object_helper(
            meet_plane,
            name="plane intersection",
            sampling=[0.1, 100, "c"],
            curve_properties={"bevel_depth": 0.005},
            collection=plane_coll,
        )
# [geometric-intersections-1]
# [geometric-intersections-2]
bobjprojective = ddg.to_blender_object_helper(
    projective_plane, sampling=[0.1, 100, "c"], name="Projective plane"
)
# [geometric-intersections-2]


#############################################
# Add Camera and Light
#############################################

# [add-camera-and-light]
# Add a point light and a camera to the scene
light = ddg.visualization.blender.light.light(type_="POINT", collection=rendering_coll)
light.data.energy = 500
light.data.shadow_soft_size = 0
camera = ddg.visualization.blender.camera.camera(
    location=(-6, 0, 0), collection=rendering_coll
)

# Position the camera to look at the projective plane
ddg.visualization.blender.camera.look_at_point(camera, (1.5, 0, 0))
bpy.context.scene.camera = camera
# [add-camera-and-light]


#############################################
# Add Material
#############################################

# [add-materials-1]
# Add a material to the projective plane
project_mat = ddg.visualization.blender.material.material(color=(0.8, 0.56, 0.535))
ddg.visualization.blender.material.set_material(bobjprojective, project_mat)
# [add-materials-1]

# [add-materials-2]
# Create a material for the sphere (S2) with transparency
s2material = bpy.data.materials.new("s2 material")
s2material.use_nodes = True
s2material.node_tree.nodes.remove(s2material.node_tree.nodes.get("Principled BSDF"))
transparent = s2material.node_tree.nodes.new("ShaderNodeBsdfTransparent")
transparent.inputs["Color"].default_value = (0.5, 0.5, 0.5, 1.0)
s2material.node_tree.links.new(
    transparent.outputs["BSDF"],
    s2material.node_tree.nodes["Material Output"].inputs["Surface"],
)
ddg.visualization.blender.material.set_material(bobj_s2, s2material)
# [add-materials-2]


#
# Render settings
#

bpy.context.scene.render.engine = "CYCLES"

# rather low number of samples, but good enough for snapshot tests
bpy.context.scene.cycles.samples = 16

from testing.tests.examples.blender.snapshot import opt_in  # noqa: E402

opt_in()
