How to create a mirror pose for a pose bone (using Python)?

I've done pose mirroring for characters in some other 3D software using scripting / matrices.

However in Blender I don't have the same helper methods / functions available (or haven't found them yet) and I'm not that much familiar with Matrix math in general.

For example - I could define some plane like ZY-plane and mirror left side bone pose (rotation) to right side along this plane. Can't remember the exact details. I would also limit myself to same limitations as Blenders pose mirror does, i.e. knees bend along x-axis and Y-axis is along bone length.

However, I haven't been able to do this in Blender yet. First of all, I'm not even sure how Blender's matrix is setup. To me it seems third item in its list is rotation:

pBone.matrix[3]  # this is rotation?


Any help is appreciated.

P.S. I got a setup to mirror pose bones using bpy.ops.pose.copy and by.ops.pose.paste(flipped=True) but this is not what I'm asking.

Edit - this is what I got now. Similar to what I've used in other software. But it naturally is negatively scaled after mirror and I should be able to somehow restore it back to 1,1,1 scale while keeping the rotation.

def mirror_bone_pose(bone):
# mirror matrix
mmtx = Matrix.Scale(-1, 4, (1, 0,0))

# mirror
mtx = bone.matrix
mtx = mmtx @ mtx
bone.matrix = mtx

# remove neg scale in one axis, not enough... but flips normals of bone
# bpy.context.object.pose.bones["Bone"].scale[0] = 1

# test
mirror_bone_pose(bpy.context.object.pose.bones[0])


OK, I probably have butchered all the rules for doing matrix math, but it works.

Basically, multiply the bone to have mirror matrix then scale it back, but it is now in reverse orientation, pointing towards opposite direction.

To counter this, I rotate it 180 long z and y axis. For some reason, updating / refreshing scene was needed for this to work.

This yields the rotation I was looking for (so far it seems to work like intended):

def mirrorPose(bone):
m = bone.matrix.Diagonal((-1,1,1,0))
bone.matrix = m @ bone.matrix
bone.scale = (1,1,1)

bpy.context.view_layer.update()