import bpy
tail=bpy.data.objects["TailFin"]; dorsal=bpy.data.objects["DorsalFin"]

def newmat(name):
    m=bpy.data.materials.new(name); m.use_nodes=True
    return m, m.node_tree.nodes["Principled BSDF"], m.node_tree

# BODY skin
mb,bsdf,nt=newmat("GoldfishSkin")
tex=nt.nodes.new("ShaderNodeTexCoord")
mapping=nt.nodes.new("ShaderNodeMapping"); mapping.inputs['Scale'].default_value=(6.0,3.0,4.0)
wave=nt.nodes.new("ShaderNodeTexWave"); wave.inputs['Distortion'].default_value=2.5; wave.bands_direction='Z'
noise=nt.nodes.new("ShaderNodeTexNoise"); noise.inputs['Scale'].default_value=8.0; noise.inputs['Detail'].default_value=6.0
ramp=nt.nodes.new("ShaderNodeValToRGB")
ramp.color_ramp.elements[0].color=(0.80,0.15,0.02,1)
ramp.color_ramp.elements[1].color=(1.0,0.58,0.10,1)
mixs=nt.nodes.new("ShaderNodeMixRGB"); mixs.blend_type='MULTIPLY'; mixs.inputs['Fac'].default_value=0.30
grad=nt.nodes.new("ShaderNodeTexGradient")
gmap=nt.nodes.new("ShaderNodeMapping"); gmap.inputs['Location'].default_value=(-1.5,0,0); gmap.inputs['Scale'].default_value=(0.33,0,0)
nt.links.new(tex.outputs['Object'], mapping.inputs['Vector'])
nt.links.new(mapping.outputs['Vector'], wave.inputs['Vector'])
nt.links.new(tex.outputs['Object'], gmap.inputs['Vector'])
nt.links.new(gmap.outputs['Vector'], grad.inputs['Vector'])
nt.links.new(wave.outputs['Fac'], mixs.inputs['Color1'])
nt.links.new(grad.outputs['Fac'], ramp.inputs['Fac'])
nt.links.new(ramp.outputs['Color'], mixs.inputs['Color2'])
nt.links.new(mixs.outputs['Color'], bsdf.inputs['Base Color'])
bsdf.inputs['Roughness'].default_value=0.28
for inp in bsdf.inputs:
    if 'Subsurface' in inp.name and 'Weight' in inp.name:
        inp.default_value=0.15
body=bpy.data.objects["Goldfish"]; body.data.materials.append(mb)

# FINS translucent
finm=bpy.data.materials.new("FinMat"); finm.use_nodes=True
fb_=finm.node_tree.nodes["Principled BSDF"]
fb_.inputs['Base Color'].default_value=(1.0,0.42,0.10,1)
if 'Transmission Weight' in [i.name for i in fb_.inputs]:
    fb_.inputs['Transmission Weight'].default_value=0.7
fb_.inputs['IOR'].default_value=1.1
fb_.inputs['Roughness'].default_value=0.25
fb_.inputs['Alpha'].default_value=0.9
finm.blend_method='BLEND'
for o in (tail,dorsal,bpy.data.objects["PectoralFin.L"],bpy.data.objects["PectoralFin.R"]):
    o.data.materials.append(finm)

# EYES
eye=bpy.data.materials.new("Eye"); eye.use_nodes=True
eb=eye.node_tree.nodes["Principled BSDF"]
eb.inputs['Base Color'].default_value=(0.01,0.008,0.006,1); eb.inputs['Roughness'].default_value=0.05
for n in ("Eye.L","Eye.R"): bpy.data.objects[n].data.materials.append(eye)

# FLOOR disc
bpy.ops.mesh.primitive_cylinder_add(radius=14, depth=0.2, location=(0,1.5,-1.65))
floor=bpy.context.active_object; floor.name="FloorDisc"
fm=floor.modifiers.new("bev","BEVEL"); fm.width=0.06; fm.segments=4
fl=bpy.data.materials.new("Floor"); fl.use_nodes=True
flb=fl.node_tree.nodes["Principled BSDF"]
flb.inputs['Base Color'].default_value=(0.16,0.30,0.34,1); flb.inputs['Roughness'].default_value=0.35
floor.data.materials.append(fl)

# WATER world
w=bpy.data.worlds.get("World") or bpy.data.worlds.new("World")
w.use_nodes=True; wn=w.node_tree; wn.nodes.clear()
bg=wn.nodes.new("ShaderNodeBackground"); bg.inputs['Strength'].default_value=1.0
bg.inputs['Color'].default_value=(0.05,0.28,0.36,1)
outn=wn.nodes.new("ShaderNodeOutputWorld")
wn.links.new(bg.outputs['Background'], outn.inputs['Surface'])
vol=wn.nodes.new("ShaderNodeVolumeScatter")
vol.inputs['Color'].default_value=(0.4,0.75,0.8,1); vol.inputs['Density'].default_value=0.010
wn.links.new(vol.outputs['Volume'], outn.inputs['Volume'])
bpy.context.scene.world=w
result={"ok":True}