"""Build original focus and framing references without measuring a physical lens."""

import argparse
import json
import sys
from pathlib import Path

import bpy
from mathutils import Vector

p = argparse.ArgumentParser(description=__doc__)
p.add_argument("output", type=Path)
a = p.parse_args(sys.argv[sys.argv.index("--") + 1 :])
a.output.mkdir()
bpy.ops.object.select_all(action="SELECT")
bpy.ops.object.delete(use_global=False)
s = bpy.context.scene
s.render.engine = "CYCLES"
s.cycles.samples = 24
s.render.resolution_x = 1200
s.render.resolution_y = 800
s.render.resolution_percentage = 100
s.render.pixel_aspect_x = s.render.pixel_aspect_y = 1
s.world.color = (0.12, 0.12, 0.12)


def mat(name, color):
    m = bpy.data.materials.new(name)
    m.diffuse_color = (*color, 1)
    m.use_nodes = True
    shader = m.node_tree.nodes.get("Principled BSDF")
    shader.inputs["Base Color"].default_value = (*color, 1)
    shader.inputs["Roughness"].default_value = 0.45
    return m


teal = mat("Original teal", (0.06, 0.36, 0.39))
cream = mat("Warm cream", (0.92, 0.84, 0.65))
coral = mat("Coral", (0.9, 0.28, 0.18))
navy = mat("Backdrop", (0.025, 0.055, 0.10))


def cube(name, loc, scale, material, bevel=0.07):
    bpy.ops.mesh.primitive_cube_add(size=1, location=loc)
    o = bpy.context.object
    o.name = name
    o.scale = scale
    bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
    o.data.materials.append(material)
    mod = o.modifiers.new("Soft original edges", "BEVEL")
    mod.width = bevel
    mod.segments = 3
    o.modifiers.new("Normals", "WEIGHTED_NORMAL")
    return o


cube("Table", (0, 0, -0.15), (200, 200, 0.2), navy)
cube("Lamp base", (-1.0, -0.6, 0.05), (0.9, 0.65, 0.12), teal)
cube("Lamp stem", (-1.0, -0.6, 0.67), (0.12, 0.12, 1.2), teal)
cube("Lamp head", (-1.0, -0.6, 1.3), (0.9, 0.55, 0.2), cream)
cube("Lamp coral switch", (-0.8, -0.72, 0.15), (0.13, 0.13, 0.12), coral, 0.02)
cube("Far card", (1.0, 2.0, 1.0), (1.8, 0.12, 2.0), cream)
for n in range(5):
    cube(f"Far card stripe {n}", (1.0, 1.92, 0.45 + n * 0.27), (1.3, 0.025, 0.09), coral, 0.01)
bpy.ops.object.camera_add(location=(4.5, -7.5, 3.5))
cam = bpy.context.object
cam.name = "Study camera"
cam.rotation_euler = (Vector((0, 0.6, 0.8)) - cam.location).to_track_quat("-Z", "Y").to_euler()
s.camera = cam
cam.data.sensor_width = 36
cam.data.lens = 50
cam.data.dof.use_dof = True
cam.data.dof.aperture_fstop = 1.4
focuses = {}
for name, loc in [("near", (-1, -0.6, 1)), ("far", (1, 2, 1))]:
    obj = bpy.data.objects.new(f"{name} focus reference", None)
    s.collection.objects.link(obj)
    obj.location = loc
    focuses[name] = obj
for loc, power, size in [((1, -4, 7), 1400, 5), ((-4, 1, 5), 1100, 4)]:
    bpy.ops.object.light_add(type="AREA", location=loc)
    o = bpy.context.object
    o.data.energy = power
    o.data.shape = "DISK"
    o.data.size = size
    o.rotation_euler = (Vector((0, 0, 0.6)) - o.location).to_track_quat("-Z", "Y").to_euler()
records = []
for name, focus, lens, dof in [
    ("lens-focus-near", "near", 50, True),
    ("lens-focus-far", "far", 50, True),
    ("lens-framing-narrow", "far", 54, True),
    ("mage-lamp-reference", "near", 50, False),
]:
    cam.data.dof.focus_object = focuses[focus]
    cam.data.dof.use_dof = dof
    cam.data.lens = lens
    bpy.context.view_layer.update()
    s.render.filepath = str(a.output / f"{name}.png")
    bpy.ops.render.render(write_still=True)
    records.append(
        {
            "name": name,
            "lensMM": lens,
            "DOF": dof,
            "focusObject": focuses[focus].name,
            "cameraMatrix": [list(row) for row in cam.matrix_world],
            "size": [1200, 800],
        }
    )
cam.data.lens = 50
cam.data.dof.use_dof = True
cam.data.dof.focus_object = focuses["near"]
bpy.ops.wm.save_as_mainfile(filepath=str(a.output / "lens-mage-study.blend"))
(a.output / "lens-mage-native-record.json").write_text(
    json.dumps(
        {
            "Blender": bpy.app.version_string,
            "scope": "Original virtual focus study and deliberately changed focal length not a physical lens breathing measurement",
            "records": records,
        },
        indent=2,
    )
    + "\n"
)
