Im trying to mirror my character from right to left whenever they face left (facingdirection ==2 ) but the flipping with a matrix is flipping them around the edge which means they dont stay in place when turning from right->left and vise versa. 
knowing that the following implementation works:

import processing.sound.*;
import processing.data.JSONObject;
import processing.data.JSONArray;
import java.util.Map;
import java.util.LinkedHashMap;

SoundFile stepSound;

PImage[] idleFrames, jumpFrames, deadFrames, attackFrames, runFrames;
PImage[] idleLeftFrames, jumpLeftFrames, attackLeftFrames, runLeftFrames;

PImage[] bg;

float characterWorldX = 300;
float characterY = 210;
float characterX = 300;

float[] ldepth = {8,4,1};
float worldX = 0;

float gravity = 0.6;
float jumpVelocity = -12;
float yVelocity = 0;

float xVelocity = 0;
float maxSpeed = 5;
float acceleration = 0.5;
float deceleration = 0.8;


enum AnimState { IDLE, JUMP, DEAD, ATTACK, RUN }
enum Direction { RIGHT, LEFT }
AnimState currentState = AnimState.IDLE;
Direction currentDirection = Direction.RIGHT;

HashMap<String, PImage[]> animations = new HashMap<>();
int frameIndex = 0;
float frameTimer = 0;
float frameDuration = 1.0 / 13; // Approx. 13 FPS for animations

Background background;
boolean isRunning = false;
boolean isJumping = false;
boolean isAttacking = false;
boolean isFalling = false;

boolean movingLeft = false;
boolean movingRight = false;

Camera camera;    

void setup() {
    size(600, 360); 
    frameRate(60);
    bg = new PImage[3];
    
    //reverse loaded order for layering/parallax to not cover
    bg[2] = loadImage("background/bg_layer_1.png");
    bg[1] = loadImage("background/bg_layer_2.png");
    bg[0] = loadImage("background/bg_layer_3.png");
    
    background = new Background(bg, ldepth);
    
    loadAnimation("character_anims_combined");  //in root folder
    
    camera = new Camera(width, height);
    stepSound = new SoundFile(this, "sound/step.wav");
}

void draw() {
    background.draw(camera);
    handleMovement();
    updateState();
    
    String animKey = currentState.name() + "_RIGHT";
    PImage[] frames = animations.get(animKey); 
    
    if (frames != null && frames.length > 0) {
        if (currentDirection == Direction.LEFT)  {
            // pushMatrix();    no need for push/pop
            translate(characterX+160, 0);
            scale(-1,1);
            translate(-characterX,0);
            image(frames[frameIndex], characterX, characterY);
            // popMatrix();
        } else image(frames[frameIndex], characterX, characterY);

        frameTimer += 1.0 / frameRate;
        if (frameTimer >= frameDuration) {
            frameTimer = 0;
            frameIndex = (frameIndex + 1) % frames.length;
            
            if (frameIndex == 0 && currentState == AnimState.ATTACK) 
            {
                isAttacking = false;
            }
        }
    }
}

please fix my game:
class Player {
    float x, y;
    int health, maxHealth = 3;
    int facingDirection; // 0: down, 1: up, 2: left, 3: right
    float speed = 3;
    boolean[] keys = new boolean[4]; // 0: up, 1: down, 2: left, 3: right
    float invulnerabilityTimer = 0, invulnerabilityDuration = 1;

    // Animation-related variables
    PImage spriteSheet;
    PImage[][] animations;
    int currentFrame = 0;
    float animationTimer = 0;
    float animationSpeed = 0.1; // Time between frames
    int currentAnimation = 0; // 0: walking down, 1: walking up, 2: walking side, 3: dying, 4: attack down, 5: attack up, 6: attack side
    boolean isMoving = false;
    boolean isAttacking = false;
    boolean isDying = false;

    static final int SPRITE_WIDTH = 48;
    static final int SPRITE_HEIGHT = 48;
    static final int WALK_DOWN = 0;
    static final int WALK_UP = 1;
    static final int WALK_SIDE = 2;
    static final int DYING = 3;
    static final int ATTACK_DOWN = 4;
    static final int ATTACK_UP = 5;
    static final int ATTACK_SIDE = 6;

    static final int FRAME_COUNT = 4; // Number of frames per animation

    Player(float x, float y, PImage spriteSheet) {
        this.x = x;
        this.y = y;
        this.facingDirection = 0;
        this.health = maxHealth;
        this.spriteSheet = spriteSheet;
        loadAnimations();
    }

    void loadAnimations() {
        animations = new PImage[7][FRAME_COUNT]; // 7 rows, 4 frames per animation
        for (int row = 0; row < 7; row++) {
            for (int col = 0; col < FRAME_COUNT; col++) {
                animations[row][col] = spriteSheet.get(col * SPRITE_WIDTH, row * SPRITE_HEIGHT, SPRITE_WIDTH, SPRITE_HEIGHT);
            }
        }
    }

    void setMove(int k, boolean b) {
        switch(k) {
            case 87: keys[0] = b; break; // W
            case 83: keys[1] = b; break; // S
            case 65: keys[2] = b; break; // A
            case 68: keys[3] = b; break; // D
            case SHIFT: 
            isRunning = b;
            speed = isRunning ? 3 : 1;  
            break; //run
        }
        isMoving = keys[0] || keys[1] || keys[2] || keys[3];
    }
    
    void update() {
        float newX = x, newY = y;
        
        if (keys[0]) { // Up
            newY -= speed;
            facingDirection = 1;
        }
        if (keys[1]) { // Down
            newY += speed;
            facingDirection = 0;
        }
        if (keys[2]) { // Left
            newX -= speed;
            facingDirection = 2;
        }
        if (keys[3]) { // Right
            newX += speed;
            facingDirection = 3;
        }
        
        if (newX >= 0 && newX < width && newY >= 0 && newY < height) {
            int tileX = floor(newX / TILE_SIZE);
            int tileY = floor(newY / TILE_SIZE);
            if (map[tileX][tileY].type == TileType.EMPTY) {
                x = newX;
                y = newY;
            }
        }
        
        // Update animation
        if (animationTimer >= animationSpeed) {
            animationTimer -= animationSpeed;
            currentFrame = (currentFrame + 1) % FRAME_COUNT;
        } else {
            animationTimer += 1.0 / frameRate;
        }
        
        if (invulnerabilityTimer > 0) {
            invulnerabilityTimer -= 1.0 / frameRate;
        }

        updateAnimationState();
    }

    void updateAnimationState() {
        if (isDying) {
            currentAnimation = DYING;
        } else if (isAttacking) {
            switch (facingDirection) {
                case 0: currentAnimation = ATTACK_DOWN; break;
                case 1: currentAnimation = ATTACK_UP; break;
                case 2:
                case 3: currentAnimation = ATTACK_SIDE; break;
            }
        } else if (isMoving) {
            switch (facingDirection) {
                case 0: currentAnimation = WALK_DOWN; break;
                case 1: currentAnimation = WALK_UP; break;
                case 2:
                case 3: currentAnimation = WALK_SIDE; break;
            }
        } else {
            // If not moving, use the first frame of the corresponding walking animation
            currentFrame = 0;
        }
    }

    void display() {
    pushMatrix();

    if (invulnerabilityTimer > 0 && (int)(invulnerabilityTimer * 10) % 2 == 0) {
        tint(255, 128); // Semi-transparent
    }

    if (facingDirection == 2) { // Facing left
        translate(x + SPRITE_WIDTH, y);
        scale(-1, 1);
        translate(-x, 0);
        // image(frames[frameIndex], characterX, characterY);
        //     // popMatrix();
        // } else image(frames[frameIndex], characterX, characterY);

        image(animations[currentAnimation][currentFrame], x, y);
    }
    else{
        translate(x, y);
        image(animations[currentAnimation][currentFrame], -SPRITE_WIDTH/2, -SPRITE_HEIGHT/2);
    }


    if (mining) {
        image(pickaxeSprite, 0, -TILE_SIZE / 2, TILE_SIZE, TILE_SIZE);
    } else {
        image(gunSprite, 0, -TILE_SIZE / 2, TILE_SIZE, TILE_SIZE);
    }
    
    popMatrix();
    noTint();
    }